aboutsummaryrefslogtreecommitdiff
path: root/src/vendorcode/cavium/bdk
diff options
context:
space:
mode:
authorDavid Hendricks <dhendricks@fb.com>2018-03-09 14:30:38 -0800
committerPhilipp Deppenwiese <zaolin.daisuki@gmail.com>2018-07-03 15:53:32 +0000
commit7d48ac5c7dfb52fc470bbad1013b4d460bc6a1e0 (patch)
tree42002ba1e86627339ff4a6cf38efb4b3f00033bb /src/vendorcode/cavium/bdk
parentd837e660074e0621d63f59515f933c209441b653 (diff)
soc/cavium: Integrate BDK files into coreboot
* Make it compile. * Fix whitespace errors. * Fix printf formats. * Add missing headers includes * Guard headers with ifdefs Compile DRAM init code in romstage. Compile QLM, PCIe, RNG, PHY, GPIO, MDIO init code in ramstage. Change-Id: I0a93219a14bfb6ebe41103a825d5032b11e7f2c6 Signed-off-by: David Hendricks <dhendricks@fb.com> Reviewed-on: https://review.coreboot.org/25089 Reviewed-by: Philipp Deppenwiese <zaolin.daisuki@gmail.com> Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
Diffstat (limited to 'src/vendorcode/cavium/bdk')
-rw-r--r--src/vendorcode/cavium/bdk/lame_string.c149
-rw-r--r--src/vendorcode/cavium/bdk/libbdk-arch/bdk-csr.c9
-rw-r--r--src/vendorcode/cavium/bdk/libbdk-arch/bdk-model.c789
-rw-r--r--src/vendorcode/cavium/bdk/libbdk-arch/bdk-numa.c28
-rw-r--r--src/vendorcode/cavium/bdk/libbdk-boot/bdk-boot-gpio.c70
-rw-r--r--src/vendorcode/cavium/bdk/libbdk-boot/bdk-boot-pcie.c68
-rw-r--r--src/vendorcode/cavium/bdk/libbdk-boot/bdk-boot-qlm.c515
-rw-r--r--src/vendorcode/cavium/bdk/libbdk-boot/bdk-boot-status.c2
-rw-r--r--src/vendorcode/cavium/bdk/libbdk-boot/bdk-boot-usb.c (renamed from src/vendorcode/cavium/bdk/libbdk-arch/bdk-platform.c)33
-rw-r--r--src/vendorcode/cavium/bdk/libbdk-boot/bdk-boot.c98
-rw-r--r--src/vendorcode/cavium/bdk/libbdk-boot/bdk-watchdog.c108
-rw-r--r--src/vendorcode/cavium/bdk/libbdk-dram/bdk-dram-address.c6
-rw-r--r--src/vendorcode/cavium/bdk/libbdk-dram/bdk-dram-config.c24
-rw-r--r--src/vendorcode/cavium/bdk/libbdk-dram/bdk-dram-size.c33
-rw-r--r--src/vendorcode/cavium/bdk/libbdk-dram/bdk-dram-test-addrbus.c1
-rw-r--r--src/vendorcode/cavium/bdk/libbdk-dram/bdk-dram-test-databus.c6
-rw-r--r--src/vendorcode/cavium/bdk/libbdk-dram/bdk-dram-test-fastscan.c1
-rw-r--r--src/vendorcode/cavium/bdk/libbdk-dram/bdk-dram-test-patfil.c48
-rw-r--r--src/vendorcode/cavium/bdk/libbdk-dram/bdk-dram-test.c188
-rw-r--r--src/vendorcode/cavium/bdk/libbdk-driver/bdk-driver-mdio.c351
-rw-r--r--src/vendorcode/cavium/bdk/libbdk-driver/bdk-driver-rnm.c36
-rw-r--r--src/vendorcode/cavium/bdk/libbdk-hal/bdk-access.c70
-rw-r--r--src/vendorcode/cavium/bdk/libbdk-hal/bdk-clock.c133
-rw-r--r--src/vendorcode/cavium/bdk/libbdk-hal/bdk-config.c1420
-rw-r--r--src/vendorcode/cavium/bdk/libbdk-hal/bdk-ecam-io.c373
-rw-r--r--src/vendorcode/cavium/bdk/libbdk-hal/bdk-ecam.c216
-rw-r--r--src/vendorcode/cavium/bdk/libbdk-hal/bdk-gpio.c1
-rw-r--r--src/vendorcode/cavium/bdk/libbdk-hal/bdk-l2c.c152
-rw-r--r--src/vendorcode/cavium/bdk/libbdk-hal/bdk-nic.c1090
-rw-r--r--src/vendorcode/cavium/bdk/libbdk-hal/bdk-pcie-cn8xxx.c1263
-rw-r--r--src/vendorcode/cavium/bdk/libbdk-hal/bdk-pcie.c221
-rw-r--r--src/vendorcode/cavium/bdk/libbdk-hal/bdk-qlm.c423
-rw-r--r--src/vendorcode/cavium/bdk/libbdk-hal/bdk-sata.c1117
-rw-r--r--src/vendorcode/cavium/bdk/libbdk-hal/bdk-twsi.c318
-rw-r--r--src/vendorcode/cavium/bdk/libbdk-hal/bdk-usb.c683
-rw-r--r--src/vendorcode/cavium/bdk/libbdk-hal/device/bdk-device.c721
-rw-r--r--src/vendorcode/cavium/bdk/libbdk-hal/if/bdk-if-phy-marvell.c115
-rw-r--r--src/vendorcode/cavium/bdk/libbdk-hal/if/bdk-if-phy-vetesse-8514.c224
-rw-r--r--src/vendorcode/cavium/bdk/libbdk-hal/if/bdk-if-phy-vetesse-xfi.c395
-rw-r--r--src/vendorcode/cavium/bdk/libbdk-hal/if/bdk-if-phy-vetesse.c372
-rw-r--r--src/vendorcode/cavium/bdk/libbdk-hal/if/bdk-if-phy.c445
-rw-r--r--src/vendorcode/cavium/bdk/libbdk-hal/qlm/bdk-qlm-cn81xx.c1003
-rw-r--r--src/vendorcode/cavium/bdk/libbdk-hal/qlm/bdk-qlm-common-sata.c625
-rw-r--r--src/vendorcode/cavium/bdk/libbdk-hal/qlm/bdk-qlm-common.c1636
-rw-r--r--src/vendorcode/cavium/bdk/libbdk-hal/qlm/bdk-qlm-errata-cn8xxx.c398
-rw-r--r--src/vendorcode/cavium/bdk/libbdk-hal/qlm/bdk-qlm-margin-cn8xxx.c271
-rw-r--r--src/vendorcode/cavium/bdk/libbdk-os/bdk-init.c500
-rw-r--r--src/vendorcode/cavium/bdk/libbdk-os/bdk-thread.c384
-rw-r--r--src/vendorcode/cavium/bdk/libbdk-trust/bdk-trust.c238
-rw-r--r--src/vendorcode/cavium/bdk/libdram/dram-env.c7
-rw-r--r--src/vendorcode/cavium/bdk/libdram/dram-env.h4
-rw-r--r--src/vendorcode/cavium/bdk/libdram/dram-init-ddr3.c4398
-rw-r--r--src/vendorcode/cavium/bdk/libdram/dram-init-ddr3.h5
-rw-r--r--src/vendorcode/cavium/bdk/libdram/dram-internal.h4
-rw-r--r--src/vendorcode/cavium/bdk/libdram/dram-l2c.c4
-rw-r--r--src/vendorcode/cavium/bdk/libdram/dram-print.h19
-rw-r--r--src/vendorcode/cavium/bdk/libdram/dram-spd.c44
-rw-r--r--src/vendorcode/cavium/bdk/libdram/dram-tune-ddr3.c1365
-rw-r--r--src/vendorcode/cavium/bdk/libdram/dram-util.h3
-rw-r--r--src/vendorcode/cavium/bdk/libdram/lib_octeon_shared.c39
-rw-r--r--src/vendorcode/cavium/bdk/libdram/libdram-config-load.c10
-rw-r--r--src/vendorcode/cavium/bdk/libdram/libdram.c95
62 files changed, 16175 insertions, 7192 deletions
diff --git a/src/vendorcode/cavium/bdk/lame_string.c b/src/vendorcode/cavium/bdk/lame_string.c
new file mode 100644
index 0000000000..11c5add209
--- /dev/null
+++ b/src/vendorcode/cavium/bdk/lame_string.c
@@ -0,0 +1,149 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright (c) 2003-2017 Cavium Inc. (support@cavium.com). All rights
+ * reserved.
+ * Copyright 2018-present Facebook, Inc.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * string.c: hastily cobbled-together string functions
+ */
+
+#include <assert.h>
+#include <string.h>
+#include <lame_string.h>
+
+static int char_to_val(char c)
+{
+ if (c >= '0' && c <= '9') /* digits */
+ return c - '0';
+ if (c >= 'A' && c <= 'F') /* uppercase */
+ return c - 'A' + 10;
+ if (c >= 'a' && c <= 'f') /* lowercase */
+ return c - 'a' + 10;
+ return -1;
+}
+
+unsigned long long int strtoull(const char *nptr, char **endptr, int base)
+{
+ unsigned long long int val;
+ size_t i, error = 0;
+
+ /* TODO: enforce lameness of this API for now... */
+ assert((base == 0) || (base == 16) || base == 10);
+
+ if (!nptr)
+ return 0;
+
+ /* Trim whitespace */
+ for (i = 0; i < strlen(nptr); i++)
+ if (nptr[i] != ' ')
+ break;
+
+ if (base == 0) {
+ /* Autodetect base */
+ if (strlen(&nptr[i]) >= 2 && ((nptr[i] == '0') &&
+ ((nptr[i + 1] == 'x') || (nptr[i + 1] == 'X')))) {
+ base = 16;
+ i += 2; /* start loop after prefix */
+ } else
+ base = 10;
+ }
+
+ val = 0;
+ for (; i < strlen(nptr); i++) {
+ if (base == 16) {
+ if (!isxdigit(nptr[i])) {
+ if (*endptr)
+ *endptr = (char *)&nptr[i];
+ error = 1;
+ break;
+ }
+ } else {
+ if (!isdigit(nptr[i])) {
+ if (*endptr)
+ *endptr = (char *)&nptr[i];
+ error = 1;
+ break;
+ }
+ }
+
+ val *= base;
+ val += char_to_val(nptr[i]);
+ }
+
+ if (error) {
+ printk(BIOS_ERR, "Failed to convert string '%s', base %d to "
+ "int\n", nptr, base);
+ return 0;
+ }
+ return val;
+}
+
+unsigned long int strtoul(const char *nptr, char **endptr, int base)
+{
+ unsigned long long int u = strtol(nptr, endptr, base);
+ /* FIXME: check for overflow (u > max) */
+ return (unsigned long int)u;
+}
+
+long int strtol(const char *nptr, char **endptr, int base)
+{
+ unsigned long long int u;
+ int is_neg = 0;
+ const char *p;
+ long int ret;
+
+ if (nptr[0] == '-') {
+ is_neg = 1;
+ p = &nptr[1];
+ } else {
+ p = &nptr[0];
+ }
+ u = strtoull(p, NULL, base);
+ /* FIXME: check for overflow (u > max) */
+ if (is_neg)
+ ret = 0 - (long int)u;
+ else
+ ret = (long int)u;
+ return ret;
+}
+
+long long int strtoll(const char *nptr, char **endptr, int base)
+{
+ unsigned long long int u;
+ int is_neg = 0;
+ const char *p;
+ long long int ret;
+
+ if (nptr[0] == '-') {
+ is_neg = 1;
+ p = &nptr[1];
+ } else {
+ p = &nptr[0];
+ }
+ u = strtoull(p, NULL, base);
+ /* FIXME: check for overflow (sign-bit set) */
+ if (is_neg)
+ ret = 0 - (long long int)u;
+ else
+ ret = (long long int)u;
+ return ret;
+}
+
+/* FIXME: replace sscanf() usage for bdk_config_get_int. returns number of
+ * strings converted, so 1 if successful and 0 if not */
+int str_to_int(const char *str, int64_t *val)
+{
+ *val = strtol(str, NULL, 10);
+ return 1;
+}
+
+/* FIXME: replace sscanf() usage for bdk_config_get_int. returns number of
+ * strings converted, so 1 if successful and 0 if not */
+int str_to_hex(const char *str, int64_t *val)
+{
+ *val = strtol(str, NULL, 16);
+ return 1;
+}
diff --git a/src/vendorcode/cavium/bdk/libbdk-arch/bdk-csr.c b/src/vendorcode/cavium/bdk/libbdk-arch/bdk-csr.c
index 981ad231dc..fc9ac35735 100644
--- a/src/vendorcode/cavium/bdk/libbdk-arch/bdk-csr.c
+++ b/src/vendorcode/cavium/bdk/libbdk-arch/bdk-csr.c
@@ -37,9 +37,10 @@
* ARISING OUT OF USE OR PERFORMANCE OF THE SOFTWARE LIES WITH YOU.
***********************license end**************************************/
#include <bdk.h>
-#include <stdio.h>
#include "libbdk-arch/bdk-csrs-pccpf.h"
#include "libbdk-arch/bdk-csrs-pem.h"
+#include "libbdk-arch/bdk-csrs-rst.h"
+#include "libbdk-hal/bdk-pcie.h"
#ifndef BDK_BUILD_HOST
@@ -87,9 +88,6 @@ uint64_t __bdk_csr_read_slow(bdk_node_t node, bdk_csr_type_t type, int busnum, i
case BDK_CSR_TYPE_PCICONFIGRC:
{
- /* Don't allow PCIe register access if PCIe wasn't linked in */
- if (!bdk_pcie_config_read32)
- bdk_fatal("PCIe CSR access not supported when PCIe not linked in\n");
union bdk_pcc_dev_con_s dev_con;
switch (busnum)
{
@@ -201,9 +199,6 @@ void __bdk_csr_write_slow(bdk_node_t node, bdk_csr_type_t type, int busnum, int
case BDK_CSR_TYPE_PCICONFIGRC:
{
- /* Don't allow PCIe register access if PCIe wasn't linked in */
- if (!bdk_pcie_config_write32)
- bdk_fatal("PCIe CSR access not supported when PCIe not linked in\n");
union bdk_pcc_dev_con_s dev_con;
switch (busnum)
{
diff --git a/src/vendorcode/cavium/bdk/libbdk-arch/bdk-model.c b/src/vendorcode/cavium/bdk/libbdk-arch/bdk-model.c
index f2b4a0c803..fc4053e1a4 100644
--- a/src/vendorcode/cavium/bdk/libbdk-arch/bdk-model.c
+++ b/src/vendorcode/cavium/bdk/libbdk-arch/bdk-model.c
@@ -41,6 +41,8 @@
#include "libbdk-arch/bdk-csrs-mio_fus.h"
#include "libbdk-arch/bdk-csrs-fus.h"
#include "libbdk-arch/bdk-csrs-fusf.h"
+#include <libbdk-hal/bdk-clock.h>
+#include <libbdk-hal/bdk-utils.h>
/*
Format of a SKU
@@ -100,562 +102,6 @@ typedef struct
6, checking for trusted boot */
#define FUSES_CHECK_FUSF 0xffff
-/***************************************************/
-/* SKU table for t88 */
-/* From "Thunder Part Number fuse overview Rev 16.xlsx" */
-/***************************************************/
-static const model_sku_info_t t88_sku_info[] =
-{
- /* Index zero reserved for no fuses programmed */
- { 0x01, "CN", 88, 2601, "AAP", /* 48, 32 cores */
- { /* List of fuses for this SKU */
- 0 /* End of fuse list marker */
- }
- },
- { 0x02, "CN", 88, 2601, "AAS", /* 24 cores */
- { /* List of fuses for this SKU */
- BDK_MIO_FUS_FUSE_NUM_E_OCX_DIS, /* Disable CCPI */
- 0 /* End of fuse list marker */
- }
- },
- { 0x03, "CN", 88, 2601, "ST", /* 48, 32 cores */
- { /* List of fuses for this SKU */
- BDK_MIO_FUS_FUSE_NUM_E_TNS_CRIPPLE, /* Disable TNS */
- BDK_MIO_FUS_FUSE_NUM_E_PEM_DISX(0), /* Disable PEM0-1 */
- BDK_MIO_FUS_FUSE_NUM_E_PEM_DISX(2), /* Disable PEM4-5 */
- 0 /* End of fuse list marker */
- }
- },
- { 0x04, "CN", 88, 2601, "STT", /* 48 cores */
- { /* List of fuses for this SKU */
- BDK_MIO_FUS_FUSE_NUM_E_PEM_DISX(0), /* Disable PEM0-1 */
- BDK_MIO_FUS_FUSE_NUM_E_PEM_DISX(2), /* Disable PEM4-5 */
- 0 /* End of fuse list marker */
- }
- },
- { 0x05, "CN", 88, 2601, "STS", /* 24 cores */
- { /* List of fuses for this SKU */
- BDK_MIO_FUS_FUSE_NUM_E_LMC_DIS, /* Disable LMC2-3 */
- BDK_MIO_FUS_FUSE_NUM_E_OCX_DIS, /* Disable CCPI */
- BDK_MIO_FUS_FUSE_NUM_E_TNS_CRIPPLE, /* Disable TNS */
- BDK_MIO_FUS_FUSE_NUM_E_PEM_DISX(0), /* Disable PEM0-1 */
- BDK_MIO_FUS_FUSE_NUM_E_PEM_DISX(2), /* Disable PEM4-5 */
- BDK_MIO_FUS_FUSE_NUM_E_BGX_DISX(1), /* Disable BGX1 */
- 0 /* End of fuse list marker */
- }
- },
- { 0x06, "CN", 88, 2601, "STP", /* 48, 32 cores */
- { /* List of fuses for this SKU */
- BDK_MIO_FUS_FUSE_NUM_E_TNS_CRIPPLE, /* Disable TNS */
- 0 /* End of fuse list marker */
- }
- },
- { 0x07, "CN", 88, 2601, "NT", /* 48, 32 cores */
- { /* List of fuses for this SKU */
- BDK_MIO_FUS_FUSE_NUM_E_SATA_DISX(0),/* Disable SATA0-3 */
- BDK_MIO_FUS_FUSE_NUM_E_SATA_DISX(2),/* Disable SATA8-11 */
- BDK_MIO_FUS_FUSE_NUM_E_SATA_DISX(3),/* Disable SATA12-15 */
- 0 /* End of fuse list marker */
- }
- },
- { 0x08, "CN", 88, 2601, "NTS", /* 24 cores */
- { /* List of fuses for this SKU */
- BDK_MIO_FUS_FUSE_NUM_E_LMC_DIS, /* Disable LMC2-3 */
- BDK_MIO_FUS_FUSE_NUM_E_OCX_DIS, /* Disable CCPI */
- BDK_MIO_FUS_FUSE_NUM_E_SATA_DISX(0),/* Disable SATA0-3 */
- BDK_MIO_FUS_FUSE_NUM_E_SATA_DISX(2),/* Disable SATA8-11 */
- BDK_MIO_FUS_FUSE_NUM_E_SATA_DISX(3),/* Disable SATA12-15 */
- BDK_MIO_FUS_FUSE_NUM_E_BGX_DISX(1), /* Disable BGX1 */
- 0 /* End of fuse list marker */
- }
- },
- { 0x09, "CN", 88, 2601, "NTP", /* 48, 32 cores */
- { /* List of fuses for this SKU */
- BDK_MIO_FUS_FUSE_NUM_E_SATA_DISX(0),/* Disable SATA0-3 */
- BDK_MIO_FUS_FUSE_NUM_E_SATA_DISX(1),/* Disable SATA4-7 */
- BDK_MIO_FUS_FUSE_NUM_E_SATA_DISX(2),/* Disable SATA8-11 */
- BDK_MIO_FUS_FUSE_NUM_E_SATA_DISX(3),/* Disable SATA12-15 */
- 0 /* End of fuse list marker */
- }
- },
- { 0x0a, "CN", 88, 2601, "CP", /* 48,32 cores */
- { /* List of fuses for this SKU */
- BDK_MIO_FUS_FUSE_NUM_E_NODFA_CP2, /* Disable HFA */
- BDK_MIO_FUS_FUSE_NUM_E_RSVD134X(0), /* Disable HNA */
- BDK_MIO_FUS_FUSE_NUM_E_NOZIP, /* Disable Compression */
- BDK_MIO_FUS_FUSE_NUM_E_TNS_CRIPPLE, /* Disable TNS */
- BDK_MIO_FUS_FUSE_NUM_E_SATA_DISX(0),/* Disable SATA0-3 */
- BDK_MIO_FUS_FUSE_NUM_E_SATA_DISX(2),/* Disable SATA8-11 */
- BDK_MIO_FUS_FUSE_NUM_E_SATA_DISX(3),/* Disable SATA12-15 */
- 0 /* End of fuse list marker */
- }
- },
- { 0x0b, "CN", 88, 2601, "CPS", /* 24 cores */
- { /* List of fuses for this SKU */
- BDK_MIO_FUS_FUSE_NUM_E_NODFA_CP2, /* Disable HFA */
- BDK_MIO_FUS_FUSE_NUM_E_RSVD134X(0), /* Disable HNA */
- BDK_MIO_FUS_FUSE_NUM_E_NOZIP, /* Disable Compression */
- BDK_MIO_FUS_FUSE_NUM_E_LMC_DIS, /* Disable LMC2-3 */
- BDK_MIO_FUS_FUSE_NUM_E_OCX_DIS, /* Disable CCPI */
- BDK_MIO_FUS_FUSE_NUM_E_TNS_CRIPPLE, /* Disable TNS */
- BDK_MIO_FUS_FUSE_NUM_E_SATA_DISX(0),/* Disable SATA0-3 */
- BDK_MIO_FUS_FUSE_NUM_E_SATA_DISX(2),/* Disable SATA8-11 */
- BDK_MIO_FUS_FUSE_NUM_E_SATA_DISX(3),/* Disable SATA12-15 */
- BDK_MIO_FUS_FUSE_NUM_E_BGX_DISX(1), /* Disable BGX1 */
- 0 /* End of fuse list marker */
- }
- },
- { 0x0c, "CN", 88, 2601, "SNT", /* 48,32 cores, Nitrox connects to PEM2x8, QLM4-5 */
- { /* List of fuses for this SKU */
- BDK_MIO_FUS_FUSE_NUM_E_RSVD231X(0), /* Nitrox 3 is present */
- 0 /* End of fuse list marker */
- }
- },
- { 0x0d, "CN", 88, 2601, "SC", /* 48,32 cores, Nitrox connects to PEM2x8, QLM4-5 */
- { /* List of fuses for this SKU */
- BDK_MIO_FUS_FUSE_NUM_E_RSVD231X(0), /* Nitrox 3 is present */
- BDK_MIO_FUS_FUSE_NUM_E_NODFA_CP2, /* Disable HFA */
- BDK_MIO_FUS_FUSE_NUM_E_RSVD134X(0), /* Disable HNA */
- BDK_MIO_FUS_FUSE_NUM_E_NOZIP, /* Disable Compression */
- BDK_MIO_FUS_FUSE_NUM_E_TNS_CRIPPLE, /* Disable TNS */
- 0 /* End of fuse list marker */
- }
- },
- /* Index gap for adding more CN88 variants */
- { 0x20, "CN", 86, 1676, "AAP", /* No part, match unfused CN86XX */
- { /* List of fuses for this SKU */
- BDK_MIO_FUS_FUSE_NUM_E_CHIP_IDX(6), /* Alternate package fuse */
- 0 /* End of fuse list marker */
- }
- },
- { 0x21, "CN", 86, 1676, "SCP", /* 8 cores */
- { /* List of fuses for this SKU */
- BDK_MIO_FUS_FUSE_NUM_E_CHIP_IDX(6), /* Alternate package fuse */
- BDK_MIO_FUS_FUSE_NUM_E_L2C_CRIPX(1),/* L2C is half size */
- BDK_MIO_FUS_FUSE_NUM_E_NODFA_CP2, /* Disable HFA */
- BDK_MIO_FUS_FUSE_NUM_E_RSVD134X(0), /* Disable HNA */
- BDK_MIO_FUS_FUSE_NUM_E_NOZIP, /* Disable Compression */
- BDK_MIO_FUS_FUSE_NUM_E_LMC_DIS, /* Disable LMC2-3 */
- BDK_MIO_FUS_FUSE_NUM_E_OCX_DIS, /* Disable CCPI */
- BDK_MIO_FUS_FUSE_NUM_E_TNS_CRIPPLE, /* Disable TNS */
- 0 /* End of fuse list marker */
- }
- },
- {} /* End of SKU list marker */
-};
-
-/***************************************************/
-/* SKU table for t83 */
-/* From "Thunder Part Number fuse overview Rev 16.xlsx" */
-/***************************************************/
-static const model_sku_info_t t83_sku_info[] =
-{
- /* Index zero reserved for no fuses programmed */
- { 0x01, "CN", 83, 1676, "SCP", /* 24, 20, 16, 12, 8 cores */
- { /* List of fuses for this SKU */
- 0 /* End of fuse list marker */
- }
- },
- { 0x02, "CN", 83, 1676, "CP", /* 24, 20, 16, 12, 8 cores */
- { /* List of fuses for this SKU */
- /* Disable all Nitrox cores, CPT0 and CPT1 */
- BDK_MIO_FUS_FUSE_NUM_E_CPT0_ENG_DISX(0), /* Nitrox */
- //BDK_MIO_FUS_FUSE_NUM_E_CPT0_ENG_DISX(1), /* Nitrox */
- //BDK_MIO_FUS_FUSE_NUM_E_CPT0_ENG_DISX(2), /* Nitrox */
- //BDK_MIO_FUS_FUSE_NUM_E_CPT0_ENG_DISX(3), /* Nitrox */
- //BDK_MIO_FUS_FUSE_NUM_E_CPT0_ENG_DISX(4), /* Nitrox */
- //BDK_MIO_FUS_FUSE_NUM_E_CPT0_ENG_DISX(5), /* Nitrox */
- //BDK_MIO_FUS_FUSE_NUM_E_CPT0_ENG_DISX(6), /* Nitrox */
- //BDK_MIO_FUS_FUSE_NUM_E_CPT0_ENG_DISX(7), /* Nitrox */
- //BDK_MIO_FUS_FUSE_NUM_E_CPT0_ENG_DISX(8), /* Nitrox */
- //BDK_MIO_FUS_FUSE_NUM_E_CPT0_ENG_DISX(9), /* Nitrox */
- //BDK_MIO_FUS_FUSE_NUM_E_CPT0_ENG_DISX(10), /* Nitrox */
- //BDK_MIO_FUS_FUSE_NUM_E_CPT0_ENG_DISX(11), /* Nitrox */
- //BDK_MIO_FUS_FUSE_NUM_E_CPT0_ENG_DISX(12), /* Nitrox */
- //BDK_MIO_FUS_FUSE_NUM_E_CPT0_ENG_DISX(13), /* Nitrox */
- //BDK_MIO_FUS_FUSE_NUM_E_CPT0_ENG_DISX(14), /* Nitrox */
- //BDK_MIO_FUS_FUSE_NUM_E_CPT0_ENG_DISX(15), /* Nitrox */
- BDK_MIO_FUS_FUSE_NUM_E_CPT0_ENG_DISX(16), /* Nitrox */
- //BDK_MIO_FUS_FUSE_NUM_E_CPT0_ENG_DISX(17), /* Nitrox */
- //BDK_MIO_FUS_FUSE_NUM_E_CPT0_ENG_DISX(18), /* Nitrox */
- //BDK_MIO_FUS_FUSE_NUM_E_CPT0_ENG_DISX(19), /* Nitrox */
- //BDK_MIO_FUS_FUSE_NUM_E_CPT0_ENG_DISX(20), /* Nitrox */
- //BDK_MIO_FUS_FUSE_NUM_E_CPT0_ENG_DISX(21), /* Nitrox */
- //BDK_MIO_FUS_FUSE_NUM_E_CPT0_ENG_DISX(22), /* Nitrox */
- //BDK_MIO_FUS_FUSE_NUM_E_CPT0_ENG_DISX(23), /* Nitrox */
- //BDK_MIO_FUS_FUSE_NUM_E_CPT0_ENG_DISX(24), /* Nitrox */
- //BDK_MIO_FUS_FUSE_NUM_E_CPT0_ENG_DISX(25), /* Nitrox */
- //BDK_MIO_FUS_FUSE_NUM_E_CPT0_ENG_DISX(26), /* Nitrox */
- //BDK_MIO_FUS_FUSE_NUM_E_CPT0_ENG_DISX(27), /* Nitrox */
- //BDK_MIO_FUS_FUSE_NUM_E_CPT0_ENG_DISX(28), /* Nitrox */
- //BDK_MIO_FUS_FUSE_NUM_E_CPT0_ENG_DISX(29), /* Nitrox */
- //BDK_MIO_FUS_FUSE_NUM_E_CPT0_ENG_DISX(30), /* Nitrox */
- //BDK_MIO_FUS_FUSE_NUM_E_CPT0_ENG_DISX(31), /* Nitrox */
- BDK_MIO_FUS_FUSE_NUM_E_CPT0_ENG_DISX(32), /* Nitrox */
- //BDK_MIO_FUS_FUSE_NUM_E_CPT0_ENG_DISX(33), /* Nitrox */
- //BDK_MIO_FUS_FUSE_NUM_E_CPT0_ENG_DISX(34), /* Nitrox */
- //BDK_MIO_FUS_FUSE_NUM_E_CPT0_ENG_DISX(35), /* Nitrox */
- //BDK_MIO_FUS_FUSE_NUM_E_CPT0_ENG_DISX(36), /* Nitrox */
- //BDK_MIO_FUS_FUSE_NUM_E_CPT0_ENG_DISX(37), /* Nitrox */
- //BDK_MIO_FUS_FUSE_NUM_E_CPT0_ENG_DISX(38), /* Nitrox */
- //BDK_MIO_FUS_FUSE_NUM_E_CPT0_ENG_DISX(39), /* Nitrox */
- //BDK_MIO_FUS_FUSE_NUM_E_CPT0_ENG_DISX(40), /* Nitrox */
- //BDK_MIO_FUS_FUSE_NUM_E_CPT0_ENG_DISX(41), /* Nitrox */
- //BDK_MIO_FUS_FUSE_NUM_E_CPT0_ENG_DISX(42), /* Nitrox */
- //BDK_MIO_FUS_FUSE_NUM_E_CPT0_ENG_DISX(43), /* Nitrox */
- //BDK_MIO_FUS_FUSE_NUM_E_CPT0_ENG_DISX(44), /* Nitrox */
- //BDK_MIO_FUS_FUSE_NUM_E_CPT0_ENG_DISX(45), /* Nitrox */
- //BDK_MIO_FUS_FUSE_NUM_E_CPT0_ENG_DISX(46), /* Nitrox */
- BDK_MIO_FUS_FUSE_NUM_E_CPT0_ENG_DISX(47), /* Nitrox */
- BDK_MIO_FUS_FUSE_NUM_E_CPT1_ENG_DISX(0), /* Nitrox */
- //BDK_MIO_FUS_FUSE_NUM_E_CPT1_ENG_DISX(1), /* Nitrox */
- //BDK_MIO_FUS_FUSE_NUM_E_CPT1_ENG_DISX(2), /* Nitrox */
- //BDK_MIO_FUS_FUSE_NUM_E_CPT1_ENG_DISX(3), /* Nitrox */
- //BDK_MIO_FUS_FUSE_NUM_E_CPT1_ENG_DISX(4), /* Nitrox */
- //BDK_MIO_FUS_FUSE_NUM_E_CPT1_ENG_DISX(5), /* Nitrox */
- //BDK_MIO_FUS_FUSE_NUM_E_CPT1_ENG_DISX(6), /* Nitrox */
- //BDK_MIO_FUS_FUSE_NUM_E_CPT1_ENG_DISX(7), /* Nitrox */
- //BDK_MIO_FUS_FUSE_NUM_E_CPT1_ENG_DISX(8), /* Nitrox */
- //BDK_MIO_FUS_FUSE_NUM_E_CPT1_ENG_DISX(9), /* Nitrox */
- //BDK_MIO_FUS_FUSE_NUM_E_CPT1_ENG_DISX(10), /* Nitrox */
- //BDK_MIO_FUS_FUSE_NUM_E_CPT1_ENG_DISX(11), /* Nitrox */
- //BDK_MIO_FUS_FUSE_NUM_E_CPT1_ENG_DISX(12), /* Nitrox */
- //BDK_MIO_FUS_FUSE_NUM_E_CPT1_ENG_DISX(13), /* Nitrox */
- //BDK_MIO_FUS_FUSE_NUM_E_CPT1_ENG_DISX(14), /* Nitrox */
- //BDK_MIO_FUS_FUSE_NUM_E_CPT1_ENG_DISX(15), /* Nitrox */
- BDK_MIO_FUS_FUSE_NUM_E_CPT1_ENG_DISX(16), /* Nitrox */
- //BDK_MIO_FUS_FUSE_NUM_E_CPT1_ENG_DISX(17), /* Nitrox */
- //BDK_MIO_FUS_FUSE_NUM_E_CPT1_ENG_DISX(18), /* Nitrox */
- //BDK_MIO_FUS_FUSE_NUM_E_CPT1_ENG_DISX(19), /* Nitrox */
- //BDK_MIO_FUS_FUSE_NUM_E_CPT1_ENG_DISX(20), /* Nitrox */
- //BDK_MIO_FUS_FUSE_NUM_E_CPT1_ENG_DISX(21), /* Nitrox */
- //BDK_MIO_FUS_FUSE_NUM_E_CPT1_ENG_DISX(22), /* Nitrox */
- BDK_MIO_FUS_FUSE_NUM_E_CPT1_ENG_DISX(23), /* Nitrox */
- 0 /* End of fuse list marker */
- }
- },
- { 0x03, "CN", 83, 1676, "AUS", /* 24, 20, 16, 12, 8 cores */
- { /* List of fuses for this SKU */
- FUSES_CHECK_FUSF, /* Trusted boot */
- 0 /* End of fuse list marker */
- }
- },
- { 0x04, "CN", 82, 1676, "SCP", /* 12, 8 cores */
- { /* List of fuses for this SKU */
- BDK_MIO_FUS_FUSE_NUM_E_L2C_CRIPX(1),/* L2C is half size */
- BDK_MIO_FUS_FUSE_NUM_E_LMC_DIS, /* Disable upper LMC */
- /* Disable Nitrox cores CPT0[24-47] and CPT1[12-23] */
- BDK_MIO_FUS_FUSE_NUM_E_CPT0_ENG_DISX(24), /* Nitrox */
- //BDK_MIO_FUS_FUSE_NUM_E_CPT0_ENG_DISX(25), /* Nitrox */
- //BDK_MIO_FUS_FUSE_NUM_E_CPT0_ENG_DISX(26), /* Nitrox */
- //BDK_MIO_FUS_FUSE_NUM_E_CPT0_ENG_DISX(27), /* Nitrox */
- //BDK_MIO_FUS_FUSE_NUM_E_CPT0_ENG_DISX(28), /* Nitrox */
- //BDK_MIO_FUS_FUSE_NUM_E_CPT0_ENG_DISX(29), /* Nitrox */
- //BDK_MIO_FUS_FUSE_NUM_E_CPT0_ENG_DISX(30), /* Nitrox */
- //BDK_MIO_FUS_FUSE_NUM_E_CPT0_ENG_DISX(31), /* Nitrox */
- BDK_MIO_FUS_FUSE_NUM_E_CPT0_ENG_DISX(32), /* Nitrox */
- //BDK_MIO_FUS_FUSE_NUM_E_CPT0_ENG_DISX(33), /* Nitrox */
- //BDK_MIO_FUS_FUSE_NUM_E_CPT0_ENG_DISX(34), /* Nitrox */
- //BDK_MIO_FUS_FUSE_NUM_E_CPT0_ENG_DISX(35), /* Nitrox */
- //BDK_MIO_FUS_FUSE_NUM_E_CPT0_ENG_DISX(36), /* Nitrox */
- //BDK_MIO_FUS_FUSE_NUM_E_CPT0_ENG_DISX(37), /* Nitrox */
- //BDK_MIO_FUS_FUSE_NUM_E_CPT0_ENG_DISX(38), /* Nitrox */
- //BDK_MIO_FUS_FUSE_NUM_E_CPT0_ENG_DISX(39), /* Nitrox */
- //BDK_MIO_FUS_FUSE_NUM_E_CPT0_ENG_DISX(40), /* Nitrox */
- //BDK_MIO_FUS_FUSE_NUM_E_CPT0_ENG_DISX(41), /* Nitrox */
- //BDK_MIO_FUS_FUSE_NUM_E_CPT0_ENG_DISX(42), /* Nitrox */
- //BDK_MIO_FUS_FUSE_NUM_E_CPT0_ENG_DISX(43), /* Nitrox */
- //BDK_MIO_FUS_FUSE_NUM_E_CPT0_ENG_DISX(44), /* Nitrox */
- //BDK_MIO_FUS_FUSE_NUM_E_CPT0_ENG_DISX(45), /* Nitrox */
- //BDK_MIO_FUS_FUSE_NUM_E_CPT0_ENG_DISX(46), /* Nitrox */
- BDK_MIO_FUS_FUSE_NUM_E_CPT0_ENG_DISX(47), /* Nitrox */
- BDK_MIO_FUS_FUSE_NUM_E_CPT1_ENG_DISX(12), /* Nitrox */
- //BDK_MIO_FUS_FUSE_NUM_E_CPT1_ENG_DISX(13), /* Nitrox */
- //BDK_MIO_FUS_FUSE_NUM_E_CPT1_ENG_DISX(14), /* Nitrox */
- //BDK_MIO_FUS_FUSE_NUM_E_CPT1_ENG_DISX(15), /* Nitrox */
- BDK_MIO_FUS_FUSE_NUM_E_CPT1_ENG_DISX(16), /* Nitrox */
- //BDK_MIO_FUS_FUSE_NUM_E_CPT1_ENG_DISX(17), /* Nitrox */
- //BDK_MIO_FUS_FUSE_NUM_E_CPT1_ENG_DISX(18), /* Nitrox */
- //BDK_MIO_FUS_FUSE_NUM_E_CPT1_ENG_DISX(19), /* Nitrox */
- //BDK_MIO_FUS_FUSE_NUM_E_CPT1_ENG_DISX(20), /* Nitrox */
- //BDK_MIO_FUS_FUSE_NUM_E_CPT1_ENG_DISX(21), /* Nitrox */
- //BDK_MIO_FUS_FUSE_NUM_E_CPT1_ENG_DISX(22), /* Nitrox */
- BDK_MIO_FUS_FUSE_NUM_E_CPT1_ENG_DISX(23), /* Nitrox */
- 0 /* End of fuse list marker */
- }
- },
- { 0x05, "CN", 82, 1676, "CP", /* 12, 8 cores */
- { /* List of fuses for this SKU */
- BDK_MIO_FUS_FUSE_NUM_E_L2C_CRIPX(1),/* L2C is half size */
- BDK_MIO_FUS_FUSE_NUM_E_LMC_DIS, /* Disable upper LMC */
- /* Disable all Nitrox cores, CPT0 and CPT1 */
- BDK_MIO_FUS_FUSE_NUM_E_CPT0_ENG_DISX(0), /* Nitrox */
- //BDK_MIO_FUS_FUSE_NUM_E_CPT0_ENG_DISX(1), /* Nitrox */
- //BDK_MIO_FUS_FUSE_NUM_E_CPT0_ENG_DISX(2), /* Nitrox */
- //BDK_MIO_FUS_FUSE_NUM_E_CPT0_ENG_DISX(3), /* Nitrox */
- //BDK_MIO_FUS_FUSE_NUM_E_CPT0_ENG_DISX(4), /* Nitrox */
- //BDK_MIO_FUS_FUSE_NUM_E_CPT0_ENG_DISX(5), /* Nitrox */
- //BDK_MIO_FUS_FUSE_NUM_E_CPT0_ENG_DISX(6), /* Nitrox */
- //BDK_MIO_FUS_FUSE_NUM_E_CPT0_ENG_DISX(7), /* Nitrox */
- //BDK_MIO_FUS_FUSE_NUM_E_CPT0_ENG_DISX(8), /* Nitrox */
- //BDK_MIO_FUS_FUSE_NUM_E_CPT0_ENG_DISX(9), /* Nitrox */
- //BDK_MIO_FUS_FUSE_NUM_E_CPT0_ENG_DISX(10), /* Nitrox */
- //BDK_MIO_FUS_FUSE_NUM_E_CPT0_ENG_DISX(11), /* Nitrox */
- //BDK_MIO_FUS_FUSE_NUM_E_CPT0_ENG_DISX(12), /* Nitrox */
- //BDK_MIO_FUS_FUSE_NUM_E_CPT0_ENG_DISX(13), /* Nitrox */
- //BDK_MIO_FUS_FUSE_NUM_E_CPT0_ENG_DISX(14), /* Nitrox */
- //BDK_MIO_FUS_FUSE_NUM_E_CPT0_ENG_DISX(15), /* Nitrox */
- BDK_MIO_FUS_FUSE_NUM_E_CPT0_ENG_DISX(16), /* Nitrox */
- //BDK_MIO_FUS_FUSE_NUM_E_CPT0_ENG_DISX(17), /* Nitrox */
- //BDK_MIO_FUS_FUSE_NUM_E_CPT0_ENG_DISX(18), /* Nitrox */
- //BDK_MIO_FUS_FUSE_NUM_E_CPT0_ENG_DISX(19), /* Nitrox */
- //BDK_MIO_FUS_FUSE_NUM_E_CPT0_ENG_DISX(20), /* Nitrox */
- //BDK_MIO_FUS_FUSE_NUM_E_CPT0_ENG_DISX(21), /* Nitrox */
- //BDK_MIO_FUS_FUSE_NUM_E_CPT0_ENG_DISX(22), /* Nitrox */
- //BDK_MIO_FUS_FUSE_NUM_E_CPT0_ENG_DISX(23), /* Nitrox */
- //BDK_MIO_FUS_FUSE_NUM_E_CPT0_ENG_DISX(24), /* Nitrox */
- //BDK_MIO_FUS_FUSE_NUM_E_CPT0_ENG_DISX(25), /* Nitrox */
- //BDK_MIO_FUS_FUSE_NUM_E_CPT0_ENG_DISX(26), /* Nitrox */
- //BDK_MIO_FUS_FUSE_NUM_E_CPT0_ENG_DISX(27), /* Nitrox */
- //BDK_MIO_FUS_FUSE_NUM_E_CPT0_ENG_DISX(28), /* Nitrox */
- //BDK_MIO_FUS_FUSE_NUM_E_CPT0_ENG_DISX(29), /* Nitrox */
- //BDK_MIO_FUS_FUSE_NUM_E_CPT0_ENG_DISX(30), /* Nitrox */
- //BDK_MIO_FUS_FUSE_NUM_E_CPT0_ENG_DISX(31), /* Nitrox */
- BDK_MIO_FUS_FUSE_NUM_E_CPT0_ENG_DISX(32), /* Nitrox */
- //BDK_MIO_FUS_FUSE_NUM_E_CPT0_ENG_DISX(33), /* Nitrox */
- //BDK_MIO_FUS_FUSE_NUM_E_CPT0_ENG_DISX(34), /* Nitrox */
- //BDK_MIO_FUS_FUSE_NUM_E_CPT0_ENG_DISX(35), /* Nitrox */
- //BDK_MIO_FUS_FUSE_NUM_E_CPT0_ENG_DISX(36), /* Nitrox */
- //BDK_MIO_FUS_FUSE_NUM_E_CPT0_ENG_DISX(37), /* Nitrox */
- //BDK_MIO_FUS_FUSE_NUM_E_CPT0_ENG_DISX(38), /* Nitrox */
- //BDK_MIO_FUS_FUSE_NUM_E_CPT0_ENG_DISX(39), /* Nitrox */
- //BDK_MIO_FUS_FUSE_NUM_E_CPT0_ENG_DISX(40), /* Nitrox */
- //BDK_MIO_FUS_FUSE_NUM_E_CPT0_ENG_DISX(41), /* Nitrox */
- //BDK_MIO_FUS_FUSE_NUM_E_CPT0_ENG_DISX(42), /* Nitrox */
- //BDK_MIO_FUS_FUSE_NUM_E_CPT0_ENG_DISX(43), /* Nitrox */
- //BDK_MIO_FUS_FUSE_NUM_E_CPT0_ENG_DISX(44), /* Nitrox */
- //BDK_MIO_FUS_FUSE_NUM_E_CPT0_ENG_DISX(45), /* Nitrox */
- //BDK_MIO_FUS_FUSE_NUM_E_CPT0_ENG_DISX(46), /* Nitrox */
- BDK_MIO_FUS_FUSE_NUM_E_CPT0_ENG_DISX(47), /* Nitrox */
- BDK_MIO_FUS_FUSE_NUM_E_CPT1_ENG_DISX(0), /* Nitrox */
- //BDK_MIO_FUS_FUSE_NUM_E_CPT1_ENG_DISX(1), /* Nitrox */
- //BDK_MIO_FUS_FUSE_NUM_E_CPT1_ENG_DISX(2), /* Nitrox */
- //BDK_MIO_FUS_FUSE_NUM_E_CPT1_ENG_DISX(3), /* Nitrox */
- //BDK_MIO_FUS_FUSE_NUM_E_CPT1_ENG_DISX(4), /* Nitrox */
- //BDK_MIO_FUS_FUSE_NUM_E_CPT1_ENG_DISX(5), /* Nitrox */
- //BDK_MIO_FUS_FUSE_NUM_E_CPT1_ENG_DISX(6), /* Nitrox */
- //BDK_MIO_FUS_FUSE_NUM_E_CPT1_ENG_DISX(7), /* Nitrox */
- //BDK_MIO_FUS_FUSE_NUM_E_CPT1_ENG_DISX(8), /* Nitrox */
- //BDK_MIO_FUS_FUSE_NUM_E_CPT1_ENG_DISX(9), /* Nitrox */
- //BDK_MIO_FUS_FUSE_NUM_E_CPT1_ENG_DISX(10), /* Nitrox */
- //BDK_MIO_FUS_FUSE_NUM_E_CPT1_ENG_DISX(11), /* Nitrox */
- //BDK_MIO_FUS_FUSE_NUM_E_CPT1_ENG_DISX(12), /* Nitrox */
- //BDK_MIO_FUS_FUSE_NUM_E_CPT1_ENG_DISX(13), /* Nitrox */
- //BDK_MIO_FUS_FUSE_NUM_E_CPT1_ENG_DISX(14), /* Nitrox */
- //BDK_MIO_FUS_FUSE_NUM_E_CPT1_ENG_DISX(15), /* Nitrox */
- BDK_MIO_FUS_FUSE_NUM_E_CPT1_ENG_DISX(16), /* Nitrox */
- //BDK_MIO_FUS_FUSE_NUM_E_CPT1_ENG_DISX(17), /* Nitrox */
- //BDK_MIO_FUS_FUSE_NUM_E_CPT1_ENG_DISX(18), /* Nitrox */
- //BDK_MIO_FUS_FUSE_NUM_E_CPT1_ENG_DISX(19), /* Nitrox */
- //BDK_MIO_FUS_FUSE_NUM_E_CPT1_ENG_DISX(20), /* Nitrox */
- //BDK_MIO_FUS_FUSE_NUM_E_CPT1_ENG_DISX(21), /* Nitrox */
- //BDK_MIO_FUS_FUSE_NUM_E_CPT1_ENG_DISX(22), /* Nitrox */
- BDK_MIO_FUS_FUSE_NUM_E_CPT1_ENG_DISX(23), /* Nitrox */
- 0 /* End of fuse list marker */
- }
- },
- {} /* End of SKU list marker */
-};
-
-/***************************************************/
-/* SKU table for t81 */
-/* From "Thunder Part Number fuse overview Rev 16.xlsx" */
-/***************************************************/
-static const model_sku_info_t t81_sku_info[] =
-{
- /* Index zero reserved for no fuses programmed */
- { 0x01, "CN", 81, 676, "SCP", /* 4, 2 cores */
- { /* List of fuses for this SKU */
- /* No fuses */
- 0 /* End of fuse list marker */
- }
- },
- { 0x02, "CN", 81, 676, "CP", /* 4, 2 cores */
- { /* List of fuses for this SKU */
- BDK_MIO_FUS_FUSE_NUM_E_CPT_ENG_DISX(1), /* Nitrox */
- //BDK_MIO_FUS_FUSE_NUM_E_CPT_ENG_DISX(2), /* Nitrox */
- //BDK_MIO_FUS_FUSE_NUM_E_CPT_ENG_DISX(3), /* Nitrox */
- //BDK_MIO_FUS_FUSE_NUM_E_CPT_ENG_DISX(4), /* Nitrox */
- //BDK_MIO_FUS_FUSE_NUM_E_CPT_ENG_DISX(5), /* Nitrox */
- //BDK_MIO_FUS_FUSE_NUM_E_CPT_ENG_DISX(6), /* Nitrox */
- //BDK_MIO_FUS_FUSE_NUM_E_CPT_ENG_DISX(7), /* Nitrox */
- //BDK_MIO_FUS_FUSE_NUM_E_CPT_ENG_DISX(8), /* Nitrox */
- //BDK_MIO_FUS_FUSE_NUM_E_CPT_ENG_DISX(9), /* Nitrox */
- //BDK_MIO_FUS_FUSE_NUM_E_CPT_ENG_DISX(10), /* Nitrox */
- //BDK_MIO_FUS_FUSE_NUM_E_CPT_ENG_DISX(11), /* Nitrox */
- //BDK_MIO_FUS_FUSE_NUM_E_CPT_ENG_DISX(12), /* Nitrox */
- //BDK_MIO_FUS_FUSE_NUM_E_CPT_ENG_DISX(13), /* Nitrox */
- //BDK_MIO_FUS_FUSE_NUM_E_CPT_ENG_DISX(14), /* Nitrox */
- //BDK_MIO_FUS_FUSE_NUM_E_CPT_ENG_DISX(15), /* Nitrox */
- BDK_MIO_FUS_FUSE_NUM_E_CPT_ENG_DISX(16), /* Nitrox */
- 0 /* End of fuse list marker */
- }
- },
- { 0x07, "CN", 81, 676, "AUS", /* 4, 2 cores */
- { /* List of fuses for this SKU */
- FUSES_CHECK_FUSF, /* Trusted boot */
- 0 /* End of fuse list marker */
- }
- },
- { 0x08, "CN", 81, 676, "AUC", /* 4, 2 cores */
- { /* List of fuses for this SKU */
- FUSES_CHECK_FUSF, /* Trusted boot */
- BDK_MIO_FUS_FUSE_NUM_E_CPT_ENG_DISX(1), /* Nitrox */
- //BDK_MIO_FUS_FUSE_NUM_E_CPT_ENG_DISX(2), /* Nitrox */
- //BDK_MIO_FUS_FUSE_NUM_E_CPT_ENG_DISX(3), /* Nitrox */
- //BDK_MIO_FUS_FUSE_NUM_E_CPT_ENG_DISX(4), /* Nitrox */
- //BDK_MIO_FUS_FUSE_NUM_E_CPT_ENG_DISX(5), /* Nitrox */
- //BDK_MIO_FUS_FUSE_NUM_E_CPT_ENG_DISX(6), /* Nitrox */
- //BDK_MIO_FUS_FUSE_NUM_E_CPT_ENG_DISX(7), /* Nitrox */
- //BDK_MIO_FUS_FUSE_NUM_E_CPT_ENG_DISX(8), /* Nitrox */
- //BDK_MIO_FUS_FUSE_NUM_E_CPT_ENG_DISX(9), /* Nitrox */
- //BDK_MIO_FUS_FUSE_NUM_E_CPT_ENG_DISX(10), /* Nitrox */
- //BDK_MIO_FUS_FUSE_NUM_E_CPT_ENG_DISX(11), /* Nitrox */
- //BDK_MIO_FUS_FUSE_NUM_E_CPT_ENG_DISX(12), /* Nitrox */
- //BDK_MIO_FUS_FUSE_NUM_E_CPT_ENG_DISX(13), /* Nitrox */
- //BDK_MIO_FUS_FUSE_NUM_E_CPT_ENG_DISX(14), /* Nitrox */
- //BDK_MIO_FUS_FUSE_NUM_E_CPT_ENG_DISX(15), /* Nitrox */
- BDK_MIO_FUS_FUSE_NUM_E_CPT_ENG_DISX(16), /* Nitrox */
- 0 /* End of fuse list marker */
- }
- },
- { 0x03, "CN", 80, 676, "SCP", /* 4, 2 cores */
- { /* List of fuses for this SKU */
- /* Note that CHIP_ID(7) is suppose to be blown, but a few chips
- have incorrect fuses. We allow CN80XX SKUs with or without
- CHIP_ID(7) */
- //BDK_MIO_FUS_FUSE_NUM_E_CHIP_IDX(7), /* Alternate package fuse 2? */
- BDK_MIO_FUS_FUSE_NUM_E_L2C_CRIPX(1), /* L2C is half size */
- BDK_MIO_FUS_FUSE_NUM_E_LMC_HALF, /* LMC is half width */
- 0 /* End of fuse list marker */
- }
- },
- { 0x04, "CN", 80, 676, "CP", /* 4, 2 cores */
- { /* List of fuses for this SKU */
- /* Note that CHIP_ID(7) is suppose to be blown, but a few chips
- have incorrect fuses. We allow CN80XX SKUs with or without
- CHIP_ID(7) */
- //BDK_MIO_FUS_FUSE_NUM_E_CHIP_IDX(7), /* Alternate package fuse 2? */
- BDK_MIO_FUS_FUSE_NUM_E_L2C_CRIPX(1), /* L2C is half size */
- BDK_MIO_FUS_FUSE_NUM_E_LMC_HALF, /* LMC is half width */
- BDK_MIO_FUS_FUSE_NUM_E_CPT_ENG_DISX(1), /* Nitrox */
- //BDK_MIO_FUS_FUSE_NUM_E_CPT_ENG_DISX(2), /* Nitrox */
- //BDK_MIO_FUS_FUSE_NUM_E_CPT_ENG_DISX(3), /* Nitrox */
- //BDK_MIO_FUS_FUSE_NUM_E_CPT_ENG_DISX(4), /* Nitrox */
- //BDK_MIO_FUS_FUSE_NUM_E_CPT_ENG_DISX(5), /* Nitrox */
- //BDK_MIO_FUS_FUSE_NUM_E_CPT_ENG_DISX(6), /* Nitrox */
- //BDK_MIO_FUS_FUSE_NUM_E_CPT_ENG_DISX(7), /* Nitrox */
- //BDK_MIO_FUS_FUSE_NUM_E_CPT_ENG_DISX(8), /* Nitrox */
- //BDK_MIO_FUS_FUSE_NUM_E_CPT_ENG_DISX(9), /* Nitrox */
- //BDK_MIO_FUS_FUSE_NUM_E_CPT_ENG_DISX(10), /* Nitrox */
- //BDK_MIO_FUS_FUSE_NUM_E_CPT_ENG_DISX(11), /* Nitrox */
- //BDK_MIO_FUS_FUSE_NUM_E_CPT_ENG_DISX(12), /* Nitrox */
- //BDK_MIO_FUS_FUSE_NUM_E_CPT_ENG_DISX(13), /* Nitrox */
- //BDK_MIO_FUS_FUSE_NUM_E_CPT_ENG_DISX(14), /* Nitrox */
- //BDK_MIO_FUS_FUSE_NUM_E_CPT_ENG_DISX(15), /* Nitrox */
- BDK_MIO_FUS_FUSE_NUM_E_CPT_ENG_DISX(16), /* Nitrox */
- 0 /* End of fuse list marker */
- }
- },
- { 0x05, "CN", 80, 555, "SCP", /* 4, 2 cores */
- { /* List of fuses for this SKU */
- BDK_MIO_FUS_FUSE_NUM_E_CHIP_IDX(6), /* Alternate package fuse */
- BDK_MIO_FUS_FUSE_NUM_E_L2C_CRIPX(1), /* L2C is half size */
- BDK_MIO_FUS_FUSE_NUM_E_LMC_HALF, /* LMC is half width */
- 0 /* End of fuse list marker */
- }
- },
- { 0x06, "CN", 80, 555, "CP", /* 4, 2 cores */
- { /* List of fuses for this SKU */
- BDK_MIO_FUS_FUSE_NUM_E_CHIP_IDX(6), /* Alternate package fuse */
- BDK_MIO_FUS_FUSE_NUM_E_L2C_CRIPX(1), /* L2C is half size */
- BDK_MIO_FUS_FUSE_NUM_E_LMC_HALF, /* LMC is half width */
- BDK_MIO_FUS_FUSE_NUM_E_CPT_ENG_DISX(1), /* Nitrox */
- //BDK_MIO_FUS_FUSE_NUM_E_CPT_ENG_DISX(2), /* Nitrox */
- //BDK_MIO_FUS_FUSE_NUM_E_CPT_ENG_DISX(3), /* Nitrox */
- //BDK_MIO_FUS_FUSE_NUM_E_CPT_ENG_DISX(4), /* Nitrox */
- //BDK_MIO_FUS_FUSE_NUM_E_CPT_ENG_DISX(5), /* Nitrox */
- //BDK_MIO_FUS_FUSE_NUM_E_CPT_ENG_DISX(6), /* Nitrox */
- //BDK_MIO_FUS_FUSE_NUM_E_CPT_ENG_DISX(7), /* Nitrox */
- //BDK_MIO_FUS_FUSE_NUM_E_CPT_ENG_DISX(8), /* Nitrox */
- //BDK_MIO_FUS_FUSE_NUM_E_CPT_ENG_DISX(9), /* Nitrox */
- //BDK_MIO_FUS_FUSE_NUM_E_CPT_ENG_DISX(10), /* Nitrox */
- //BDK_MIO_FUS_FUSE_NUM_E_CPT_ENG_DISX(11), /* Nitrox */
- //BDK_MIO_FUS_FUSE_NUM_E_CPT_ENG_DISX(12), /* Nitrox */
- //BDK_MIO_FUS_FUSE_NUM_E_CPT_ENG_DISX(13), /* Nitrox */
- //BDK_MIO_FUS_FUSE_NUM_E_CPT_ENG_DISX(14), /* Nitrox */
- //BDK_MIO_FUS_FUSE_NUM_E_CPT_ENG_DISX(15), /* Nitrox */
- BDK_MIO_FUS_FUSE_NUM_E_CPT_ENG_DISX(16), /* Nitrox */
- 0 /* End of fuse list marker */
- }
- },
- {} /* End of SKU list marker */
-};
-
-/***************************************************/
-/* SKU table for t93 */
-/***************************************************/
-static const model_sku_info_t t93_sku_info[] =
-{
- /* Index zero reserved for no fuses programmed */
- { 0x01, "CN", 93, 1676, "SCP", /* 24, 20, 16, 12, 8 cores */
- { /* List of fuses for this SKU */
- /* No fuses */
- 0 /* End of fuse list marker */
- }
- },
- {} /* End of SKU list marker */
-};
-
-/**
- * Given a core count, return the last two digits of a model number
- *
- * @param cores Number of cores
- *
- * @return Two digit model number
- */
-static int model_digits_for_cores(int cores)
-{
- /* If the number of cores is between two model levels, use the lower
- level. This assumes that a model guarantees a minimum number of
- cores. This should never happen, but you never know */
- switch (cores)
- {
- case 1: return 10; /* CNxx10 = 1 core */
- case 2: return 20; /* CNxx20 = 2 cores */
- case 3: return 25; /* CNxx25 = 3 cores */
- case 4: return 30; /* CNxx30 = 4 cores */
- case 5: return 32; /* CNxx32 = 5 cores */
- case 6: return 34; /* CNxx34 = 6 cores */
- case 7: return 38; /* CNxx38 = 7 cores */
- case 8: return 40; /* CNxx40 = 8 cores */
- case 9: return 42; /* CNxx42 = 9 cores */
- case 10: return 45; /* CNxx45 = 10 cores */
- case 11: return 48; /* CNxx48 = 11 cores */
- case 12: return 50; /* CNxx50 = 12 cores */
- case 13: return 52; /* CNxx52 = 13 cores */
- case 14: return 55; /* CNxx55 = 14 cores */
- case 15: return 58; /* CNxx58 = 15 cores */
- case 16 ... 19: return 60; /* CNxx60 = 16 cores */
- case 20 ... 23: return 65; /* CNxx65 = 20 cores */
- case 24 ... 31: return 70; /* CNxx70 = 24 cores */
- case 32 ... 39: return 80; /* CNxx80 = 32 cores */
- case 40 ... 43: return 85; /* CNxx85 = 40 cores */
- case 44 ... 47: return 88; /* CNxx88 = 44 cores */
- default: return 90; /* CNxx90 = 48 cores */
- }
-}
-
/**
* Return non-zero if the die is in an alternate package. The
* normal is_model() checks will treat alternate package parts
@@ -694,234 +140,3 @@ int cavium_is_altpkg(uint32_t arg_model)
else
return 0;
}
-
-/**
- * Return the SKU string for a chip
- *
- * @param node Node to get SKU for
- *
- * @return Chip's SKU
- */
-const char* bdk_model_get_sku(int node)
-{
- /* Storage for SKU is per node. Static variable stores the value
- so we don't decode on every call */
- static char chip_sku[BDK_NUMA_MAX_NODES][32] = { { 0, }, };
-
- /* Return the cached string if we've already filled it in */
- if (chip_sku[node][0])
- return chip_sku[node];
-
- /* Figure out which SKU list to use */
- const model_sku_info_t *sku_info;
- uint64_t result;
- asm ("mrs %[rd],MIDR_EL1" : [rd] "=r" (result));
- result = bdk_extract(result, 4, 12);
- switch (result)
- {
- case 0xa1:
- sku_info = t88_sku_info;
- break;
- case 0xa2:
- sku_info = t81_sku_info;
- break;
- case 0xa3:
- sku_info = t83_sku_info;
- break;
- case 0xb2:
- sku_info = t93_sku_info;
- break;
- default:
- bdk_fatal("SKU detect: Unknown die\n");
- }
-
- /* Read the SKU index from the PNAME fuses */
- int match_index = -1;
- // FIXME: Implement PNAME reads
-
- /* Search the SKU list for the best match, where all the fuses match.
- Only needed if the PNAME fuses don't specify the index */
- if (match_index == -1)
- {
- match_index = 0;
- int match_score = -1;
- int index = 0;
- while (sku_info[index].fuse_index)
- {
- int score = 0;
- int fuse_index = 0;
- /* Count the number of fuses that match. A mismatch forces the worst
- score (-1) */
- while (sku_info[index].fuses[fuse_index])
- {
- int fuse;
- /* FUSES_CHECK_FUSF is special for trusted parts */
- if (sku_info[index].fuses[fuse_index] == FUSES_CHECK_FUSF)
- {
- BDK_CSR_INIT(fusf_ctl, node, BDK_FUSF_CTL);
- fuse = (fusf_ctl.u >> 6) & 1;
- }
- else
- {
- fuse = bdk_fuse_read(node, sku_info[index].fuses[fuse_index]);
- }
- if (fuse)
- {
- /* Match, improve the score */
- score++;
- }
- else
- {
- /* Mismatch, force score bad */
- score = -1;
- break;
- }
- fuse_index++;
- }
- /* If this score is better than the last match, use this index as the
- match */
- if (score > match_score)
- {
- match_score = score;
- match_index = index;
- }
- index++;
- }
- }
-
- /* Use the SKU table to determine the defaults for the SKU parts */
- const char *prefix = sku_info[match_index].prefix;
- int model = 100 * sku_info[match_index].model_base;
- int cores = bdk_get_num_cores(node);
- const char *customer_code = "";
- int rclk_limit = bdk_clock_get_rate(node, BDK_CLOCK_RCLK) / 1000000;
- const char *bg_str = "BG"; /* Default Ball Grid array */
- int balls = sku_info[match_index].num_balls; /* Num package balls */
- const char *segment = sku_info[match_index].segment; /* Market segment */
- char prod_phase[4]; /* Blank = production, PR = Prototype, ES = Engineering sample */
- char prod_rev[5]; /* Product revision */
- const char *rohs_option = "G"; /* RoHS is always G for current parts */
-
- /* Update the model number with the number of cores */
- model = (model / 100) * 100 + model_digits_for_cores(cores);
-
- /* Update the RCLK setting based on MIO_FUS_DAT3[core_pll_mul] */
- uint64_t core_pll_mul;
- if (CAVIUM_IS_MODEL(CAVIUM_CN8XXX))
- {
- BDK_CSR_INIT(mio_fus_dat3, node, BDK_MIO_FUS_DAT3);
- core_pll_mul = mio_fus_dat3.s.core_pll_mul;
- }
- else
- core_pll_mul = bdk_fuse_read_range(bdk_numa_local(), BDK_FUS_FUSE_NUM_E_CORE_MAX_MULX(0), 7);
-
- if (core_pll_mul)
- {
- /* CORE_PLL_MUL covers bits 5:1, so we need to multiple by 2. The
- documentation doen't mention this clearly: There is a 300Mhz
- addition to the base multiplier */
- rclk_limit = core_pll_mul * 2 * 50 + 300;
- }
-
- /* FIXME: Hardcode production as there is no way to tell */
- prod_phase[0] = 0;
-
- /* Read the Pass information from fuses. Note that pass info in
- MIO_FUS_DAT2[CHIP_ID] is encoded as
- bit[7] = Unused, zero
- bit[6] = Alternate package
- bit[5..3] = Major pass
- bit[2..0] = Minor pass */
- int major_pass;
- int minor_pass;
- if (CAVIUM_IS_MODEL(CAVIUM_CN8XXX))
- {
- BDK_CSR_INIT(mio_fus_dat2, node, BDK_MIO_FUS_DAT2);
- major_pass = ((mio_fus_dat2.s.chip_id >> 3) & 7) + 1;
- minor_pass = mio_fus_dat2.s.chip_id & 7;
- }
- else
- {
- /* FIXME: We don't support getting the pass for other node on CN9XXX */
- bdk_ap_midr_el1_t midr_el1;
- BDK_MRS(MIDR_EL1, midr_el1.u);
- major_pass = (midr_el1.s.variant & 7) + 1;
- minor_pass = midr_el1.s.revision;
- }
-
- if (major_pass == 1)
- {
- /* Pass 1.x is special in that we don't show the implied 'X' */
- if (minor_pass == 0)
- {
- /* Completely blank for 1.0 */
- prod_rev[0] = 0;
- }
- else
- {
- /* If we are production and not pass 1.0, the product phase
- changes from blank to "-P". The product revision then
- follows the product phase without a '-' */
- if (prod_phase[0] == 0)
- {
- /* Change product phase to "-P" */
- prod_phase[0] = '-';
- prod_phase[1] = 'P';
- prod_phase[2] = 0;
- }
- /* No separator between phase and revision */
- prod_rev[0] = '1';
- prod_rev[1] = '0' + minor_pass;
- prod_rev[2] = 0;
- }
- }
- else
- {
- /* Pass 2.0 and above 12345678 */
- const char pass_letter[8] = "XYWVUTSR";
- prod_rev[0] = '-';
- prod_rev[1] = pass_letter[major_pass-1];
- if (minor_pass == 0)
- {
- /* Nothing after the letter code */
- prod_rev[2] = 0;
- }
- else
- {
- /* Add major and minor after the letter code */
- prod_rev[2] = '0' + major_pass;
- prod_rev[3] = '0' + minor_pass;
- prod_rev[4] = 0;
- }
- }
-
- /* Special check for CN88XX pass 2.0 and 2.1. Documentation mistakenly
- specified 2.0 as -PR and 2.1 as -Y. Rather than fix the docs, OPs has
- decided to special case this SKU */
- if (CAVIUM_IS_MODEL(CAVIUM_CN88XX) && (major_pass == 2))
- {
- if (minor_pass == 0)
- {
- prod_phase[0] = '-'; /* SKU ends with -PR-Y-G */
- prod_phase[1] = 'P';
- prod_phase[2] = 'R';
- prod_phase[3] = 0;
- }
- else if (minor_pass == 1)
- {
- prod_rev[0] = '-'; /* SKU ends with -Y-G */
- prod_rev[1] = 'Y';
- prod_rev[2] = 0;
- }
- }
-
- /* Read PNAME fuses, looking for SKU overrides */
- // FIXME: Implement PNAME reads
-
- /* Build the SKU string */
- snprintf(chip_sku[node], sizeof(chip_sku[node]), "%s%d%s-%d%s%d-%s%s%s-%s",
- prefix, model, customer_code, rclk_limit, bg_str, balls, segment,
- prod_phase, prod_rev, rohs_option);
-
- return chip_sku[node];
-}
diff --git a/src/vendorcode/cavium/bdk/libbdk-arch/bdk-numa.c b/src/vendorcode/cavium/bdk/libbdk-arch/bdk-numa.c
index 33d34ba669..ede3b10170 100644
--- a/src/vendorcode/cavium/bdk/libbdk-arch/bdk-numa.c
+++ b/src/vendorcode/cavium/bdk/libbdk-arch/bdk-numa.c
@@ -37,11 +37,18 @@
* ARISING OUT OF USE OR PERFORMANCE OF THE SOFTWARE LIES WITH YOU.
***********************license end**************************************/
#include <bdk.h>
-#include <stdio.h>
+#include <libbdk-hal/bdk-atomic.h>
-int __bdk_numa_master_node = -1; /* Which node is the master */
-static int __bdk_numa_exists_mask = 0; /* Bitmask of nodes that exist */
-static bdk_spinlock_t __bdk_numa_lock;
+/*
+ * FIXME(dhendrix): can't include bdk-spinlock.h, compile complains:
+ * {standard input}:40: Error: selected processor does not support `ldadda x3,x5,[x2]'
+ */
+
+//int __bdk_numa_master_node = -1; /* Which node is the master */
+int __bdk_numa_master_node = 0; /* FIXME(dhendrix): assume 0 */
+//static int __bdk_numa_exists_mask = 0; /* Bitmask of nodes that exist */
+static int __bdk_numa_exists_mask = 1; /* FIXME(dhendrix): assume 0x01 */
+//static bdk_spinlock_t __bdk_numa_lock;
/**
* Get a bitmask of the nodes that exist
@@ -60,11 +67,8 @@ uint64_t bdk_numa_get_exists_mask(void)
*/
void bdk_numa_set_exists(bdk_node_t node)
{
- bdk_spinlock_lock(&__bdk_numa_lock);
- __bdk_numa_exists_mask |= 1 << node;
- if (__bdk_numa_master_node == -1)
- __bdk_numa_master_node = node;
- bdk_spinlock_unlock(&__bdk_numa_lock);
+ /* FIXME(dhendrix): stub. */
+ return;
}
/**
@@ -76,7 +80,8 @@ void bdk_numa_set_exists(bdk_node_t node)
*/
int bdk_numa_exists(bdk_node_t node)
{
- return __bdk_numa_exists_mask & (1 << node);
+ /* FIXME(dhendrix): stub */
+ return node == 0;
}
/**
@@ -86,6 +91,7 @@ int bdk_numa_exists(bdk_node_t node)
*/
extern int bdk_numa_is_only_one()
{
- return __bdk_numa_exists_mask == 1;
+ /* FIXME(dhendrix): stub */
+ return 1;
}
diff --git a/src/vendorcode/cavium/bdk/libbdk-boot/bdk-boot-gpio.c b/src/vendorcode/cavium/bdk/libbdk-boot/bdk-boot-gpio.c
new file mode 100644
index 0000000000..330a23ba49
--- /dev/null
+++ b/src/vendorcode/cavium/bdk/libbdk-boot/bdk-boot-gpio.c
@@ -0,0 +1,70 @@
+/***********************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"
+#include "libbdk-hal/bdk-config.h"
+#include "libbdk-hal/bdk-gpio.h"
+#include "libbdk-boot/bdk-boot-gpio.h"
+
+/**
+ * Configure GPIO on all nodes as part of booting
+ */
+void bdk_boot_gpio(void)
+{
+ const int NUM_GPIO = bdk_gpio_get_num();
+ for (bdk_node_t n = BDK_NODE_0; n < BDK_NUMA_MAX_NODES; n++)
+ {
+ if (bdk_numa_exists(n))
+ {
+ for (int gpio = 0; gpio < NUM_GPIO; gpio++)
+ {
+ int pin_sel = bdk_config_get_int(BDK_CONFIG_GPIO_PIN_SELECT, gpio, n);
+ if (pin_sel >= 0)
+ {
+ BDK_TRACE(INIT, "Connecting N%d.GPIO%d to pin select 0x%x\n",
+ n, gpio, pin_sel);
+ bdk_gpio_select_pin(n, gpio, pin_sel);
+ }
+ int invert = bdk_config_get_int(BDK_CONFIG_GPIO_POLARITY, gpio, n);
+ if (invert)
+ BDK_CSR_MODIFY(c, n, BDK_GPIO_BIT_CFGX(gpio), c.s.pin_xor = 1);
+ }
+ }
+ }
+}
diff --git a/src/vendorcode/cavium/bdk/libbdk-boot/bdk-boot-pcie.c b/src/vendorcode/cavium/bdk/libbdk-boot/bdk-boot-pcie.c
new file mode 100644
index 0000000000..b03c2e03ee
--- /dev/null
+++ b/src/vendorcode/cavium/bdk/libbdk-boot/bdk-boot-pcie.c
@@ -0,0 +1,68 @@
+/***********************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 <string.h>
+#include "libbdk-hal/if/bdk-if.h"
+#include "libbdk-hal/bdk-qlm.h"
+#include "libbdk-arch/bdk-csrs-pem.h"
+#include "libbdk-boot/bdk-boot-pcie.h"
+#include "libbdk-hal/bdk-pcie.h"
+
+/**
+ * Configure PCIe on all nodes as part of booting
+ */
+void bdk_boot_pcie(void)
+{
+ /* Initialize PCIe and bring up the link */
+ for (bdk_node_t n = BDK_NODE_0; n < BDK_NUMA_MAX_NODES; n++)
+ {
+ if (bdk_numa_exists(n))
+ {
+ for (int p = 0; p < bdk_pcie_get_num_ports(n); p++)
+ {
+ /* Only init PCIe that are attached to QLMs */
+ if (bdk_qlm_get_qlm_num(n, BDK_IF_PCIE, p, 0) != -1)
+ {
+ BDK_TRACE(INIT, "Initializing PCIe%d on Node %d\n", p, n);
+ bdk_pcie_rc_initialize(n, p);
+ }
+ }
+ }
+ }
+}
diff --git a/src/vendorcode/cavium/bdk/libbdk-boot/bdk-boot-qlm.c b/src/vendorcode/cavium/bdk/libbdk-boot/bdk-boot-qlm.c
new file mode 100644
index 0000000000..73bdca0363
--- /dev/null
+++ b/src/vendorcode/cavium/bdk/libbdk-boot/bdk-boot-qlm.c
@@ -0,0 +1,515 @@
+/***********************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 <string.h>
+#include "libbdk-hal/if/bdk-if.h"
+#include "libbdk-hal/bdk-qlm.h"
+#include "libbdk-hal/bdk-utils.h"
+#include "libbdk-boot/bdk-boot-qlm.h"
+#include "libbdk-hal/bdk-config.h"
+#include "libbdk-hal/bdk-twsi.h"
+
+static void boot_init_qlm_clk(void)
+{
+ /* Setup reference clocks */
+ for (bdk_node_t n = BDK_NODE_0; n < BDK_NUMA_MAX_NODES; n++)
+ {
+ if (!bdk_numa_exists(n))
+ continue;
+
+ int num_qlms = bdk_qlm_get_num(n);
+
+ BDK_TRACE(INIT, "Initializing QLM clocks on Node %d\n", n);
+ for (int qlm = 0; qlm < num_qlms; qlm++)
+ {
+ bdk_qlm_clock_t clk = bdk_config_get_int(BDK_CONFIG_QLM_CLK, n, qlm);
+ if (BDK_QLM_CLK_LAST == clk) /* no entry */
+ continue;
+
+ if (clk > BDK_QLM_CLK_LAST)
+ {
+ bdk_warn("Invalid clock source %d for QLM%d on node %d. Not configuring.\n",
+ clk, qlm, n);
+ continue;
+ }
+
+ if (0 != bdk_qlm_set_clock(n, qlm, clk))
+ {
+ bdk_error("Error setting clock source %d for QLM%d on node %d. Ignoring.\n",
+ clk, qlm, n);
+ }
+ }
+ }
+}
+
+/**
+ * Given a node and DLM/QLM, return the possible BGX lanes connected to it. This
+ * is needed to determine which PHY address to use for SFP/SFP+ detection.
+ *
+ * @param node Node the DLM/QLM is on
+ * @param qlm DLM/QLM to find the BGX for
+ * @param bgx Output: The BGX instance number, or -1 on failure
+ * @param bgx_lane_mask
+ * Output: Which BGX indexes may be connected to this port
+ */
+static void find_bgx(int node, int qlm, int *bgx, int *bgx_lane_mask)
+{
+ *bgx = -1;
+ *bgx_lane_mask = 0;
+
+ if (CAVIUM_IS_MODEL(CAVIUM_CN88XX))
+ {
+ switch (qlm)
+ {
+ case 0: /* BGX0 -> QLM0 */
+ case 1: /* BGX1 -> QLM1 */
+ *bgx = qlm;
+ *bgx_lane_mask = 0xf;
+ return;
+ default:
+ BDK_TRACE(INIT, "N%d.QLM%d: No BGX for this QLM, illegal config\n", node, qlm);
+ return;
+ }
+ }
+ else if (CAVIUM_IS_MODEL(CAVIUM_CN83XX))
+ {
+ switch (qlm)
+ {
+ case 2: /* BGX0 -> QLM2 */
+ *bgx = 0;
+ *bgx_lane_mask = 0xf;
+ return;
+ case 3: /* BGX1 -> QLM3 */
+ *bgx = 1;
+ *bgx_lane_mask = 0xf;
+ return;
+ case 4: /* BGX3 -> DLM4 */
+ *bgx = 3;
+ *bgx_lane_mask = 0x3;
+ return;
+ case 5: /* BGX2 -> DLM5 */
+ *bgx = 2;
+ *bgx_lane_mask = 0x3;
+ return;
+ case 6: /* BGX2 -> DLM6 */
+ *bgx = 2;
+ *bgx_lane_mask = 0xc;
+ return;
+ default:
+ BDK_TRACE(INIT, "N%d.QLM%d: No BGX for this QLM, illegal config\n", node, qlm);
+ return;
+ }
+ }
+ else if (CAVIUM_IS_MODEL(CAVIUM_CN81XX))
+ {
+ switch (qlm)
+ {
+ case 0: /* BGX0 -> DLM0 */
+ *bgx = 0;
+ *bgx_lane_mask = 0x3;
+ return;
+ case 1: /* BGX0 -> DLM1 */
+ *bgx = 0;
+ *bgx_lane_mask = 0xc;
+ return;
+ case 2: /* BGX1 -> DLM2 */
+ *bgx = 1;
+ *bgx_lane_mask = 0x3;
+ return;
+ case 3: /* BGX1 -> DLM3 */
+ *bgx = 1;
+ *bgx_lane_mask = 0xc;
+ return;
+ default:
+ BDK_TRACE(INIT, "N%d.QLM%d: No BGX for this QLM, illegal config\n", node, qlm);
+ return;
+ }
+ }
+ else
+ bdk_error("N%d.QLM%d: Unsupported chip, update %s()\n", node, qlm, __FUNCTION__);
+}
+
+/**
+ * Determine the DLM/QLM mode based on a SFP/SFP+ connected to the port. Note that
+ * the CN8XXX parts can't control mode per lane, so all SFP/SFP+ on a DLM/QLM must
+ * be the same mode. This code is sloppy about finding the BGX PHY for the DLM/QLM
+ * because not all lanes may be used.
+ *
+ * @param node Node to determine mode for
+ * @param qlm DLM/QLM the SFP/SFP+ is connected to
+ *
+ * @return QLM mode or -1 on failure
+ */
+static int init_sfp(int node, int qlm)
+{
+ int mode = BDK_QLM_MODE_XFI_4X1; /* Default to XFI if detection fails */
+ int bgx = -1;
+ int bgx_lane_mask = 0;
+
+ find_bgx(node, qlm, &bgx, &bgx_lane_mask);
+ if (bgx == -1)
+ return mode;
+
+ BDK_TRACE(INIT, "N%d.QLM%d: Checking for SFP/SFP+\n", node, qlm);
+
+ for (int index = 0; index < 4; index++)
+ {
+ /* Skip BGX indexes that aren't applicable */
+ if ((bgx_lane_mask & (1 << index)) == 0)
+ continue;
+ /* Lookup the PHY address for this BGX port */
+ int phy_addr = bdk_config_get_int(BDK_CONFIG_PHY_ADDRESS, node, bgx, index);
+ /* SFP/SFP+ are connected with TWSI, so only check ports with
+ PHYs connected with TWSI */
+ if ((phy_addr & BDK_IF_PHY_TYPE_MASK) != BDK_IF_PHY_TWSI)
+ continue;
+
+ /* For TWSI:
+ Bits[31:24]: Node ID, 0xff for device node
+ Bits[23:16]: TWSI internal address width in bytes (0-2)
+ Bits[15:12]: 2=TWSI
+ Bits[11:8]: TWSI bus number
+ Bits[7:0]: TWSI address */
+ int n = (phy_addr >> 24) & 0xff;
+ int twsi_ia_width = (phy_addr >> 16) & 0xff;
+ int twsi_bus = (phy_addr >> 8) & 0xf;
+ int twsi_addr = 0x50; /* From SFP spec */
+ if (n == 0xff)
+ n = node;
+
+ /* Read bytes 0-3 from eeprom. Note read is big endian, so byte 0 is
+ bits 31:24 in the result */
+ int64_t eeprom_00_03 = bdk_twsix_read_ia(n, twsi_bus, twsi_addr, 0, 4, twsi_ia_width);
+ if (eeprom_00_03 == -1)
+ {
+ BDK_TRACE(INIT, "N%d.QLM%d: BGX%d.%d SFP/SFP+ eeprom access failed\n", node, qlm, bgx, index);
+ continue;
+ }
+ int64_t eeprom_04_07 = bdk_twsix_read_ia(n, twsi_bus, twsi_addr, 4, 4, twsi_ia_width);
+ if (eeprom_04_07 == -1)
+ {
+ BDK_TRACE(INIT, "N%d.QLM%d: BGX%d.%d SFP/SFP+ eeprom access failed\n", node, qlm, bgx, index);
+ continue;
+ }
+ int64_t eeprom_08_11 = bdk_twsix_read_ia(n, twsi_bus, twsi_addr, 8, 4, twsi_ia_width);
+ if (eeprom_08_11 == -1)
+ {
+ BDK_TRACE(INIT, "N%d.QLM%d: BGX%d.%d SFP/SFP+ eeprom access failed\n", node, qlm, bgx, index);
+ continue;
+ }
+ int64_t eeprom_12 = bdk_twsix_read_ia(n, twsi_bus, twsi_addr, 12, 1, twsi_ia_width);
+ if (eeprom_12 == -1)
+ {
+ BDK_TRACE(INIT, "N%d.QLM%d: BGX%d.%d SFP/SFP+ eeprom access failed\n", node, qlm, bgx, index);
+ continue;
+ }
+
+ /* Byte 0: Identifier, should be 0x03 for SFP/SFP+
+ 0x03 = SFP of SFP+
+ 0x0c = QSFP
+ 0x0d = QSFP+ */
+ if (bdk_extract(eeprom_00_03, 24, 8) != 0x03)
+ {
+ /* Byte 0 of eeprom should be 0x03 for SFP/SFP+ */
+ BDK_TRACE(INIT, "N%d.QLM%d: BGX%d.%d SFP/SFP+ not detected\n", node, qlm, bgx, index);
+ continue;
+ }
+ /* Byte 1: Extended Identifier, should be 0x04 */
+ if (bdk_extract(eeprom_00_03, 16, 8) != 0x04)
+ {
+ BDK_TRACE(INIT, "N%d.QLM%d: BGX%d.%d SFP/SFP+ incorrect extended identifier\n", node, qlm, bgx, index);
+ continue;
+ }
+ /* Byte 2: Connector
+ Value Description of connector
+ 00h Unknown or unspecified
+ 01h SC
+ 02h Fibre Channel Style 1 copper connector
+ 03h Fibre Channel Style 2 copper connector
+ 04h BNC/TNC
+ 05h Fibre Channel coaxial headers
+ 06h FiberJack
+ 07h LC
+ 08h MT-RJ
+ 09h MU
+ 0Ah SG
+ 0Bh Optical pigtail
+ 0Ch MPO Parallel Optic
+ 0Dh-1Fh Reserved, Unallocated
+ 20h HSSDC II
+ 21h Copper Pigtail
+ 22h RJ45
+ 23h-7Fh Reserved, Unallocated
+ 80-FFh Vendor specific */
+ bool isOptical = false;
+ switch (bdk_extract(eeprom_00_03, 8, 8))
+ {
+ case 0x01: /* SC - Short channel */
+ case 0x07: /* LC - Long channel */
+ case 0x0B: /* Optical pigtail */
+ isOptical = true;
+ break;
+ }
+ BDK_TRACE(INIT, "N%d.QLM%d: SFP/SFP+ eeprom Bytes[0:3] 0x%0llx, Bytes[4:7] 0x%08llx, [8:11] 0x%08llx [12] 0x%02llx\n",
+ node, qlm, eeprom_00_03, eeprom_04_07, eeprom_08_11, eeprom_12);
+ /* Byte 3: Transceiver info first byte. See comments below */
+ /* Byte 3, bits 4-7 correspond to 10G Ethernet speeds */
+ /* 10G Ethernet Compliance Codes
+ Byte 3[7] 10G BASE-ER (Fiber - Extended Reach)
+ Byte 3[6] 10G BASE-LRM (Fiber - Long reach multi-mode)
+ Byte 3[5] 10G BASE-LR (Fiber - Long reach)
+ Byte 3[4] 10G BASE-SR (Fiber - Short reach) */
+ bool isXFI = bdk_extract(eeprom_00_03, 0, 8) != 0;
+ /* Byte 6, bits 0-7 correspond to Gigabit Ethernet speeds */
+ /* Gigabit Ethernet Compliance Codes
+ Byte 6[7] BASE-PX
+ Byte 6[6] BASE-BX10
+ Byte 6[5] 100BASE-FX
+ Byte 6[4] 100BASE-LX/LX10 (Fiber)
+ Byte 6[3] 1000BASE-T (Twisted pair)
+ Byte 6[2] 1000BASE-CX (Shielded balanced copper)
+ Byte 6[1] 1000BASE-LX (Fiber)
+ Byte 6[0] 1000BASE-SX (Fiber) */
+ bool isSGMII = bdk_extract(eeprom_04_07, 8, 8) != 0;
+ /* Byte 12 is the nominal bit rate, units of 100 MBits/sec. */
+ int bit_rate = eeprom_12 * 100;
+ if (bit_rate)
+ {
+ BDK_TRACE(INIT, "N%d.QLM%d: Nominal bit rate %d MBits/sec\n",
+ node, qlm, bit_rate);
+ isXFI = (bit_rate >= 10000);
+ isSGMII = (bit_rate <= 2500);
+ }
+
+ if (isXFI)
+ {
+ mode = BDK_QLM_MODE_XFI_4X1;
+ if (isOptical)
+ BDK_TRACE(INIT, "N%d.QLM%d: SFP+ selecting XFI Optical\n", node, qlm);
+ else
+ BDK_TRACE(INIT, "N%d.QLM%d: SFP+ selecting XFI Copper\n", node, qlm);
+ }
+ else if (isSGMII)
+ {
+ mode = BDK_QLM_MODE_SGMII_4X1;
+ if (isOptical)
+ {
+ /* This should be 1000BASE-X, gigabit over fiber */
+ BDK_TRACE(INIT, "N%d.QLM%d: SFP selecting SGMII Optical\n", node, qlm);
+ }
+ else /* This should be SGMII, gigabit over copper */
+ BDK_TRACE(INIT, "N%d.QLM%d: SFP selecting SGMII Copper\n", node, qlm);
+ }
+ }
+ return mode;
+}
+
+/**
+ * Determine the DLM/QLM mode based on a QSFP/QSFP+ connected to
+ * the port. This code is sloppy about finding the BGX PHY for
+ * the DLM/QLM because not all lanes may be used.
+ *
+ * @param node Node to determine mode for
+ * @param qlm DLM/QLM the SFP/SFP+ is connected to
+ *
+ * @return QLM mode or -1 on failure
+ */
+static int init_qsfp(int node, int qlm)
+{
+ int mode = BDK_QLM_MODE_XLAUI_1X4; /* Default to XLAUI if detection fails */
+ int bgx = -1;
+ int bgx_lane_mask = 0;
+
+ find_bgx(node, qlm, &bgx, &bgx_lane_mask);
+ if (bgx == -1)
+ return mode;
+
+ BDK_TRACE(INIT, "N%d.QLM%d: Checking for QSFP/QSFP+\n", node, qlm);
+ int index = 0;
+
+ /* Lookup the PHY address for this BGX port */
+ int phy_addr = bdk_config_get_int(BDK_CONFIG_PHY_ADDRESS, node, bgx, index);
+ /* QSFP/QSFP+ are connected with TWSI, so only check ports with
+ PHYs connected with TWSI */
+ if ((phy_addr & BDK_IF_PHY_TYPE_MASK) != BDK_IF_PHY_TWSI)
+ return mode;
+
+ /* For TWSI:
+ Bits[31:24]: Node ID, 0xff for device node
+ Bits[23:16]: TWSI internal address width in bytes (0-2)
+ Bits[15:12]: 2=TWSI
+ Bits[11:8]: TWSI bus number
+ Bits[7:0]: TWSI address */
+ int n = (phy_addr >> 24) & 0xff;
+ int twsi_ia_width = (phy_addr >> 16) & 0xff;
+ int twsi_bus = (phy_addr >> 8) & 0xf;
+ int twsi_addr = 0x50; /* From SFP spec */
+ if (n == 0xff)
+ n = node;
+
+ /* Byte 0: Identifier, should be 0x03 for SFP/SFP+
+ 0x03 = SFP of SFP+
+ 0x0c = QSFP
+ 0x0d = QSFP+ */
+ int64_t eeprom_00 = bdk_twsix_read_ia(n, twsi_bus, twsi_addr, 0, 1, twsi_ia_width);
+ switch (eeprom_00)
+ {
+ case 0x03:
+ BDK_TRACE(INIT, "N%d.QLM%d: BGX%d QSFP/QSFP+ contains a SFP+\n", node, qlm, bgx);
+ mode = init_sfp(node, qlm);
+ break;
+ case 0x0c:
+ case 0x0d:
+ BDK_TRACE(INIT, "N%d.QLM%d: BGX%d Found a QSFP/QSFP+, assuming 40G\n", node, qlm, bgx);
+ mode = BDK_QLM_MODE_XLAUI_1X4;
+ break;
+ default:
+ BDK_TRACE(INIT, "N%d.QLM%d: BGX%d QSFP/QSFP+ not detected\n", node, qlm, bgx);
+ break;
+ }
+ return mode;
+}
+
+static void boot_init_qlm_mode(void)
+{
+ /* Check if QLM autoconfig is requested */
+ int qlm_auto = bdk_config_get_int(BDK_CONFIG_QLM_AUTO_CONFIG);
+ if (qlm_auto)
+ {
+ /* Auto configuration of QLMs
+ */
+ for (bdk_node_t n = BDK_NODE_0; n < BDK_NUMA_MAX_NODES; n++)
+ {
+ if (bdk_numa_exists(n))
+ {
+ BDK_TRACE(INIT, "Initializing QLMs on Node %d\n", n);
+ bdk_qlm_auto_config(n);
+ }
+ }
+ }
+ /*
+ * Check if QLM autoconfig from DIP switch settings is requested
+ */
+ else if (bdk_config_get_int(BDK_CONFIG_QLM_DIP_AUTO_CONFIG))
+ {
+ BDK_TRACE(INIT, "Reading DIP Switch settings for QLM Auto configuration\n");
+
+ /* Auto configuration of QLMs
+ */
+ for (bdk_node_t n = BDK_NODE_0; n < BDK_NUMA_MAX_NODES; n++)
+ {
+ if (bdk_numa_exists(n))
+ {
+ BDK_TRACE(INIT, "Initializing QLMs on Node %d\n", n);
+ if (bdk_qlm_dip_auto_config(n))
+ bdk_error("QLM Auto configuration failed!\n");
+ }
+ }
+
+ }
+ else
+ {
+ /* Initialize the QLMs based on configuration file settings
+ */
+
+ boot_init_qlm_clk();
+
+ for (bdk_node_t n = BDK_NODE_0; n < BDK_NUMA_MAX_NODES; n++)
+ {
+ if (!bdk_numa_exists(n))
+ continue;
+
+ int num_qlms = bdk_qlm_get_num(n);
+
+ BDK_TRACE(INIT, "Initializing QLMs on Node %d\n", n);
+ for (int qlm = 0; qlm < num_qlms; qlm++)
+ {
+ const char *cfg_val;
+
+ cfg_val = bdk_config_get_str(BDK_CONFIG_QLM_MODE, n, qlm);
+ if (!cfg_val)
+ continue;
+
+ int mode;
+ int freq;
+ /* Check for special token telling us to configure the QLM
+ based on the SFP/SFP+/QSFP/QSFP+ plugged into the system. */
+ if ((strcmp(cfg_val, "SFP+") == 0) || (strcmp(cfg_val, "QSFP+") == 0))
+ {
+ if (strcmp(cfg_val, "SFP+") == 0)
+ mode = init_sfp(n, qlm);
+ else
+ mode = init_qsfp(n, qlm);
+
+ if (mode == BDK_QLM_MODE_SGMII_4X1)
+ freq = 1250;
+ else
+ freq = 10321;
+ }
+ else
+ {
+ mode = bdk_qlm_cfg_string_to_mode(cfg_val);
+ freq = bdk_config_get_int(BDK_CONFIG_QLM_FREQ, n, qlm);
+ }
+ if (-1 == mode)
+ {
+ bdk_error("Invalid QLM mode string '%s' for QLM%d on node %d. "
+ "Not configuring.\n", cfg_val, qlm, n);
+ continue;
+ }
+ if (-1 == freq)
+ {
+ bdk_error("No frequency setting for QLM%d on node %d. "
+ "Not configuring.\n", qlm, n);
+ continue;
+ }
+
+ bdk_qlm_set_mode(n, qlm, mode, freq, 0);
+ }
+ }
+ }
+}
+
+/**
+ * Configure QLM on all nodes as part of booting
+ */
+void bdk_boot_qlm(void)
+{
+ boot_init_qlm_mode();
+}
diff --git a/src/vendorcode/cavium/bdk/libbdk-boot/bdk-boot-status.c b/src/vendorcode/cavium/bdk/libbdk-boot/bdk-boot-status.c
index 83ab14cbc7..c91f2dd1bb 100644
--- a/src/vendorcode/cavium/bdk/libbdk-boot/bdk-boot-status.c
+++ b/src/vendorcode/cavium/bdk/libbdk-boot/bdk-boot-status.c
@@ -38,6 +38,8 @@
***********************license end**************************************/
#include <bdk.h>
#include "libbdk-arch/bdk-csrs-mio_tws.h"
+#include "libbdk-boot/bdk-boot-status.h"
+#include <libbdk-hal/bdk-config.h>
/**
* Report boot status to the BMC or whomever might care. This function
diff --git a/src/vendorcode/cavium/bdk/libbdk-arch/bdk-platform.c b/src/vendorcode/cavium/bdk/libbdk-boot/bdk-boot-usb.c
index 8cac04a214..70ed44af4f 100644
--- a/src/vendorcode/cavium/bdk/libbdk-arch/bdk-platform.c
+++ b/src/vendorcode/cavium/bdk/libbdk-boot/bdk-boot-usb.c
@@ -37,23 +37,26 @@
* ARISING OUT OF USE OR PERFORMANCE OF THE SOFTWARE LIES WITH YOU.
***********************license end**************************************/
#include <bdk.h>
-#include "libbdk-arch/bdk-csrs-ocla.h"
+#include <libbdk-hal/bdk-usb.h>
+#include <libbdk-hal/bdk-config.h>
+#include <libbdk-boot/bdk-boot-usb.h>
-bdk_platform_t __bdk_platform;
-
-void __bdk_platform_init()
+/**
+ * Configure USB on all nodes as part of booting
+ */
+void bdk_boot_usb(void)
{
- BDK_CSR_INIT(c, bdk_numa_master(), BDK_OCLAX_CONST(0));
- if (c.u == 0)
- {
- __bdk_platform = BDK_PLATFORM_ASIM;
- }
- else
+ /* Initialize USB, ready for standard XHCI driver */
+ for (bdk_node_t n = BDK_NODE_0; n < BDK_NUMA_MAX_NODES; n++)
{
- int plat2 = bdk_fuse_read(bdk_numa_master(), 197);
- int plat1 = bdk_fuse_read(bdk_numa_master(), 196);
- int plat0 = bdk_fuse_read(bdk_numa_master(), 195);
- __bdk_platform = (plat2 << 2) | (plat1 << 1) | plat0;
+ if (bdk_numa_exists(n))
+ {
+ for (int p = 0; p < 2; p++)
+ {
+ int usb_refclock = bdk_config_get_int(BDK_CONFIG_USB_REFCLK_SRC, n,p);
+ BDK_TRACE(INIT, "Initializing USB%d on Node %d clock type %d\n", p, n, usb_refclock);
+ bdk_usb_initialize(n, p, usb_refclock);
+ }
+ }
}
}
-
diff --git a/src/vendorcode/cavium/bdk/libbdk-boot/bdk-boot.c b/src/vendorcode/cavium/bdk/libbdk-boot/bdk-boot.c
new file mode 100644
index 0000000000..15bcf4aa8c
--- /dev/null
+++ b/src/vendorcode/cavium/bdk/libbdk-boot/bdk-boot.c
@@ -0,0 +1,98 @@
+/***********************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 <string.h>
+#include "libbdk-hal/if/bdk-if.h"
+#include "libbdk-arch/bdk-csrs-pem.h"
+#include "libbdk-boot/bdk-boot-pcie.h"
+#include "libbdk-boot/bdk-boot-qlm.h"
+#include "libbdk-boot/bdk-boot-usb.h"
+#include "libbdk-hal/bdk-pcie.h"
+#include "libbdk-hal/bdk-mdio.h"
+#include "libbdk-hal/bdk-qlm.h"
+#include "libbdk-hal/bdk-ecam.h"
+#include "libbdk-hal/bdk-rng.h"
+#include "libbdk-boot/bdk-boot-gpio.h"
+#include "libbdk-arch/bdk-csrs-iobn.h"
+#include "libbdk-arch/bdk-csrs-dap.h"
+
+/**
+ * Configure hardware
+ */
+void bdk_boot(void)
+{
+ for (bdk_node_t n = BDK_NODE_0; n < BDK_NUMA_MAX_NODES; n++)
+ {
+ if (bdk_numa_exists(n))
+ {
+ /* Allow CAP access from cores so we can read system registers through
+ memory mapped addresses. See bdk_sysreg_read() */
+ BDK_CSR_MODIFY(c, n, BDK_DAP_IMP_DAR, c.s.caben = 1);
+
+ /* Enable IOBN */
+ if (CAVIUM_IS_MODEL(CAVIUM_CN88XX) || CAVIUM_IS_MODEL(CAVIUM_CN81XX))
+ {
+ BDK_CSR_MODIFY(c, n, BDK_IOBNX_NCB0_HP(0),
+ c.s.hp = 1);
+ if (CAVIUM_IS_MODEL(CAVIUM_CN88XX))
+ BDK_CSR_MODIFY(c, n, BDK_IOBNX_NCB0_HP(1),
+ c.s.hp = 0);
+ }
+
+ bdk_ecam_scan_all(n);
+ bdk_mdio_init(n);
+ bdk_qlm_init(n);
+ bdk_rng_init(n);
+ }
+ }
+
+ bdk_boot_gpio();
+ bdk_boot_usb();
+ bdk_boot_qlm();
+ bdk_boot_pcie();
+
+ /* Initialize PHYs */
+ for (bdk_node_t n = BDK_NODE_0; n < BDK_NUMA_MAX_NODES; n++)
+ {
+ if (bdk_numa_exists(n))
+ {
+ bdk_if_phy_setup(n);
+ }
+ }
+}
diff --git a/src/vendorcode/cavium/bdk/libbdk-boot/bdk-watchdog.c b/src/vendorcode/cavium/bdk/libbdk-boot/bdk-watchdog.c
deleted file mode 100644
index 48f955a7ef..0000000000
--- a/src/vendorcode/cavium/bdk/libbdk-boot/bdk-watchdog.c
+++ /dev/null
@@ -1,108 +0,0 @@
-/***********************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"
-
-/**
- * Setup the watchdog to expire in timeout_ms milliseconds. When the watchdog
- * expires, the chip three things happen:
- * 1) Expire 1: interrupt that is ignored by the BDK
- * 2) Expire 2: DEL3T interrupt, which is disabled and ignored
- * 3) Expire 3: Soft reset of the chip
- *
- * Since we want a soft reset, we actually program the watchdog to expire at
- * the timeout / 3.
- *
- * @param timeout_ms Timeout in milliseconds. If this is zero, the timeout is taken from the
- * global configuration option BDK_BRD_CFG_WATCHDOG_TIMEOUT
- */
-void bdk_watchdog_set(unsigned int timeout_ms)
-{
- if (timeout_ms == 0)
- timeout_ms = bdk_config_get_int(BDK_CONFIG_WATCHDOG_TIMEOUT);
-
- if (timeout_ms > 0)
- {
- uint64_t sclk = bdk_clock_get_rate(bdk_numa_local(), BDK_CLOCK_SCLK);
- uint64_t timeout_sclk = sclk * timeout_ms / 1000;
- /* Per comment above, we want the watchdog to expire at 3x the rate specified */
- timeout_sclk /= 3;
- /* Watchdog counts in 1024 cycle steps */
- uint64_t timeout_wdog = timeout_sclk >> 10;
- /* We can only specify the upper 16 bits of a 24 bit value. Round up */
- timeout_wdog = (timeout_wdog + 0xff) >> 8;
- /* If the timeout overflows the hardware limit, set max */
- if (timeout_wdog >= 0x10000)
- timeout_wdog = 0xffff;
-
- BDK_TRACE(INIT, "Watchdog: Set to expire %lu SCLK cycles\n", timeout_wdog << 18);
- BDK_CSR_MODIFY(c, bdk_numa_local(), BDK_GTI_CWD_WDOGX(bdk_get_core_num()),
- c.s.len = timeout_wdog;
- c.s.mode = 3);
- }
-}
-
-/**
- * Signal the watchdog that we are still running
- */
-void bdk_watchdog_poke(void)
-{
- BDK_CSR_WRITE(bdk_numa_local(), BDK_GTI_CWD_POKEX(bdk_get_core_num()), 0);
-}
-
-/**
- * Disable the hardware watchdog
- */
-void bdk_watchdog_disable(void)
-{
- BDK_CSR_WRITE(bdk_numa_local(), BDK_GTI_CWD_WDOGX(bdk_get_core_num()), 0);
- BDK_TRACE(INIT, "Watchdog: Disabled\n");
-}
-
-/**
- * Return true if the watchdog is configured and running
- *
- * @return Non-zero if watchdog is running
- */
-int bdk_watchdog_is_running(void)
-{
- BDK_CSR_INIT(wdog, bdk_numa_local(), BDK_GTI_CWD_WDOGX(bdk_get_core_num()));
- return wdog.s.mode != 0;
-}
-
diff --git a/src/vendorcode/cavium/bdk/libbdk-dram/bdk-dram-address.c b/src/vendorcode/cavium/bdk/libbdk-dram/bdk-dram-address.c
index 94d7d76752..acefe1751c 100644
--- a/src/vendorcode/cavium/bdk/libbdk-dram/bdk-dram-address.c
+++ b/src/vendorcode/cavium/bdk/libbdk-dram/bdk-dram-address.c
@@ -72,9 +72,9 @@ bdk_dram_address_extract_info(uint64_t address, int *node, int *lmc, int *dimm,
/* LMC number is probably aliased */
if (l2c_ctl.s.disidxalias)
- *lmc = EXTRACT(address, 7, xbits);
+ *lmc = EXTRACT(address, 7, xbits);
else
- *lmc = EXTRACT(address, 7, xbits) ^ EXTRACT(address, bitno, xbits) ^ EXTRACT(address, 12, xbits);
+ *lmc = EXTRACT(address, 7, xbits) ^ EXTRACT(address, bitno, xbits) ^ EXTRACT(address, 12, xbits);
/* Figure out the bank field width */
BDK_CSR_INIT(lmcx_config, *node, BDK_LMCX_CONFIG(*lmc));
@@ -176,7 +176,7 @@ bdk_dram_address_construct_info(bdk_node_t node, int lmc, int dimm,
BDK_CSR_INIT(l2c_ctl, node, BDK_L2C_CTL);
int new_lmc = lmc;
if (!l2c_ctl.s.disidxalias)
- new_lmc ^= EXTRACT(address, bitno, xbits) ^ EXTRACT(address, 12, xbits);
+ new_lmc ^= EXTRACT(address, bitno, xbits) ^ EXTRACT(address, 12, xbits);
INSERT(address, new_lmc, 7, xbits);
return address;
diff --git a/src/vendorcode/cavium/bdk/libbdk-dram/bdk-dram-config.c b/src/vendorcode/cavium/bdk/libbdk-dram/bdk-dram-config.c
index 3465c5d98b..5c104231dc 100644
--- a/src/vendorcode/cavium/bdk/libbdk-dram/bdk-dram-config.c
+++ b/src/vendorcode/cavium/bdk/libbdk-dram/bdk-dram-config.c
@@ -37,7 +37,9 @@
* ARISING OUT OF USE OR PERFORMANCE OF THE SOFTWARE LIES WITH YOU.
***********************license end**************************************/
#include <bdk.h>
-#include <unistd.h>
+#include <string.h>
+#include <libbdk-hal/bdk-config.h>
+#include <libbdk-hal/bdk-l2c.h>
BDK_REQUIRE_DEFINE(DRAM_CONFIG);
@@ -73,22 +75,6 @@ int bdk_dram_config(int node, int ddr_clock_override)
}
/**
- * Do DRAM configuration tuning
- *
- * @param node Node to tune
- *
- * @return Success or Fail
- */
-int bdk_dram_tune(int node)
-{
- int ret;
- BDK_TRACE(DRAM, "N%d: Starting DRAM tuning\n", node);
- ret = libdram_tune(node);
- BDK_TRACE(DRAM, "N%d: DRAM tuning returned %d\n", node, ret);
- return ret;
-}
-
-/**
* Do all the DRAM Margin tests
*
* @param node Node to test
@@ -144,7 +130,9 @@ uint64_t bdk_dram_get_top_of_bdk(void)
* the address to make it a physical offset. Doing this simplifies the
* address checks and calculations which only work with physical offsets.
*/
- uint64_t top_of_bdk = (bdk_ptr_to_phys(sbrk(0)) & bdk_build_mask(40));
+ /* FIXME(dhendrix): we only care about node 0 */
+// uint64_t top_of_bdk = (bdk_ptr_to_phys(sbrk(0)) & bdk_build_mask(40));
+ uint64_t top_of_bdk = 0;
uint64_t l2_size = bdk_l2c_get_cache_size_bytes(bdk_numa_master());
if (top_of_bdk <= l2_size)
{
diff --git a/src/vendorcode/cavium/bdk/libbdk-dram/bdk-dram-size.c b/src/vendorcode/cavium/bdk/libbdk-dram/bdk-dram-size.c
index 122afb2a18..8cd4594818 100644
--- a/src/vendorcode/cavium/bdk/libbdk-dram/bdk-dram-size.c
+++ b/src/vendorcode/cavium/bdk/libbdk-dram/bdk-dram-size.c
@@ -37,6 +37,8 @@
* ARISING OUT OF USE OR PERFORMANCE OF THE SOFTWARE LIES WITH YOU.
***********************license end**************************************/
#include <bdk.h>
+#include <libbdk-hal/bdk-utils.h>
+
/**
* Return the number of LMC controllers in use
@@ -92,7 +94,7 @@ static int __bdk_dram_is_lmc_in_dreset(bdk_node_t node, int lmc)
*
* @param node Node to probe
*
- */
+ */
uint32_t __bdk_dram_get_row_mask(bdk_node_t node, int lmc)
{
// PROTECT!!!
@@ -108,7 +110,7 @@ uint32_t __bdk_dram_get_row_mask(bdk_node_t node, int lmc)
*
* @param node Node to probe
*
- */
+ */
uint32_t __bdk_dram_get_col_mask(bdk_node_t node, int lmc)
{
// PROTECT!!!
@@ -124,7 +126,7 @@ uint32_t __bdk_dram_get_col_mask(bdk_node_t node, int lmc)
*
* @param node Node to probe
*
- */
+ */
// all DDR3, and DDR4 x16 today, use only 3 bank bits; DDR4 x4 and x8 always have 4 bank bits
// NOTE: this will change in the future, when DDR4 x16 devices can come with 16 banks!! FIXME!!
int __bdk_dram_get_num_bank_bits(bdk_node_t node, int lmc)
@@ -181,9 +183,6 @@ int __bdk_dram_is_rdimm(bdk_node_t node, int lmc)
*/
uint64_t bdk_dram_get_size_mbytes(int node)
{
- if (bdk_is_platform(BDK_PLATFORM_EMULATOR))
- return 2 << 10; /* 2GB is available on t88 and t81
- ** some t83 models have 8gb, but it is too long to init */
/* Return zero if dram isn't enabled */
if (!__bdk_is_dram_enabled(node))
return 0;
@@ -192,21 +191,13 @@ uint64_t bdk_dram_get_size_mbytes(int node)
const int num_dram_controllers = __bdk_dram_get_num_lmc(node);
for (int lmc = 0; lmc < num_dram_controllers; lmc++)
{
- if (bdk_is_platform(BDK_PLATFORM_ASIM))
- {
- /* Asim doesn't simulate the rank detection, fake 4GB per controller */
- memsize += 4ull << 30;
- }
- else
- {
- // PROTECT!!!
- if (__bdk_dram_is_lmc_in_dreset(node, lmc)) // check LMCn
- return 0;
- BDK_CSR_INIT(lmcx_config, node, BDK_LMCX_CONFIG(lmc));
- int num_ranks = bdk_pop(lmcx_config.s.init_status);
- uint64_t rank_size = 1ull << (28 + lmcx_config.s.pbank_lsb - lmcx_config.s.rank_ena);
- memsize += rank_size * num_ranks;
- }
+ // PROTECT!!!
+ if (__bdk_dram_is_lmc_in_dreset(node, lmc)) // check LMCn
+ return 0;
+ BDK_CSR_INIT(lmcx_config, node, BDK_LMCX_CONFIG(lmc));
+ int num_ranks = bdk_pop(lmcx_config.s.init_status);
+ uint64_t rank_size = 1ull << (28 + lmcx_config.s.pbank_lsb - lmcx_config.s.rank_ena);
+ memsize += rank_size * num_ranks;
}
return memsize >> 20;
}
diff --git a/src/vendorcode/cavium/bdk/libbdk-dram/bdk-dram-test-addrbus.c b/src/vendorcode/cavium/bdk/libbdk-dram/bdk-dram-test-addrbus.c
index 9fe8570454..834ade4c40 100644
--- a/src/vendorcode/cavium/bdk/libbdk-dram/bdk-dram-test-addrbus.c
+++ b/src/vendorcode/cavium/bdk/libbdk-dram/bdk-dram-test-addrbus.c
@@ -37,6 +37,7 @@
* ARISING OUT OF USE OR PERFORMANCE OF THE SOFTWARE LIES WITH YOU.
***********************license end**************************************/
#include "bdk.h"
+#include <libbdk-hal/bdk-utils.h>
/* Used for all memory reads/writes related to the test */
#define READ64(address) __bdk_dram_read64(address)
diff --git a/src/vendorcode/cavium/bdk/libbdk-dram/bdk-dram-test-databus.c b/src/vendorcode/cavium/bdk/libbdk-dram/bdk-dram-test-databus.c
index c3fa1ffd8d..b7a6f96880 100644
--- a/src/vendorcode/cavium/bdk/libbdk-dram/bdk-dram-test-databus.c
+++ b/src/vendorcode/cavium/bdk/libbdk-dram/bdk-dram-test-databus.c
@@ -38,6 +38,8 @@
***********************license end**************************************/
#include "bdk.h"
+#include <libbdk-hal/bdk-utils.h>
+
/* Used for all memory reads/writes related to the test */
#define READ64(address) __bdk_dram_read64(address)
#define WRITE64(address, data) __bdk_dram_write64(address, data)
@@ -97,7 +99,7 @@ static int read_data_bus_burst(uint64_t address, int bursts)
*/
static int write_data_bus_burst(uint64_t address, int bursts)
{
- BDK_TRACE(DRAM_TEST, "[0x%016lx:0x%016lx] Writing incrementing digits\n",
+ BDK_TRACE(DRAM_TEST, "[0x%016llx:0x%016llx] Writing incrementing digits\n",
address, address + 127);
/* Loop over the burst so people using a scope have time to capture
traces */
@@ -164,7 +166,7 @@ static int read_data_bus_walk(uint64_t address, int burst, uint64_t pattern)
*/
static void write_data_bus_walk(uint64_t address, int burst, uint64_t pattern)
{
- BDK_TRACE(DRAM_TEST, "[0x%016lx:0x%016lx] Writing walking pattern 0x%016lx\n",
+ BDK_TRACE(DRAM_TEST, "[0x%016llx:0x%016llx] Writing walking pattern 0x%016llx\n",
address, address + 127, pattern);
uint64_t a = address;
diff --git a/src/vendorcode/cavium/bdk/libbdk-dram/bdk-dram-test-fastscan.c b/src/vendorcode/cavium/bdk/libbdk-dram/bdk-dram-test-fastscan.c
index 46e205dd80..c89ef76103 100644
--- a/src/vendorcode/cavium/bdk/libbdk-dram/bdk-dram-test-fastscan.c
+++ b/src/vendorcode/cavium/bdk/libbdk-dram/bdk-dram-test-fastscan.c
@@ -37,6 +37,7 @@
* ARISING OUT OF USE OR PERFORMANCE OF THE SOFTWARE LIES WITH YOU.
***********************license end**************************************/
#include "bdk.h"
+#include <libbdk-hal/bdk-utils.h>
/* Used for all memory reads/writes related to the test */
#define READ64(address) __bdk_dram_read64(address)
diff --git a/src/vendorcode/cavium/bdk/libbdk-dram/bdk-dram-test-patfil.c b/src/vendorcode/cavium/bdk/libbdk-dram/bdk-dram-test-patfil.c
index e6c4b57721..6315172101 100644
--- a/src/vendorcode/cavium/bdk/libbdk-dram/bdk-dram-test-patfil.c
+++ b/src/vendorcode/cavium/bdk/libbdk-dram/bdk-dram-test-patfil.c
@@ -37,6 +37,8 @@
* ARISING OUT OF USE OR PERFORMANCE OF THE SOFTWARE LIES WITH YOU.
***********************license end**************************************/
#include "bdk.h"
+#include <libbdk-hal/bdk-rng.h>
+#include <libbdk-hal/bdk-utils.h>
// choose prediction-based algorithms for mem_xor and mem_rows tests
#define USE_PREDICTION_CODE_VERSIONS 1 // change to 0 to go back to the original versions
@@ -286,7 +288,7 @@ static int test_mem_march_c(uint64_t area, uint64_t max_address, uint64_t patter
int failures = 0;
/* Pass 1 ascending addresses, fill memory with pattern. */
- BDK_TRACE(DRAM_TEST, " [0x%016lx:0x%016lx] Phase1, address incrementing, pattern 0x%016lx\n", area, max_address-1, pattern);
+ BDK_TRACE(DRAM_TEST, " [0x%016llx:0x%016llx] Phase1, address incrementing, pattern 0x%016llx\n", area, max_address-1, pattern);
for (uint64_t address = area; address < max_address; address += 8)
WRITE64(address, pattern);
@@ -294,7 +296,7 @@ static int test_mem_march_c(uint64_t area, uint64_t max_address, uint64_t patter
BDK_DCACHE_INVALIDATE;
/* Pass 2: ascending addresses, read pattern and write ~pattern */
- BDK_TRACE(DRAM_TEST, " [0x%016lx:0x%016lx] Phase2, address incrementing, pattern 0x%016lx\n", area, max_address-1, ~pattern);
+ BDK_TRACE(DRAM_TEST, " [0x%016llx:0x%016llx] Phase2, address incrementing, pattern 0x%016llx\n", area, max_address-1, ~pattern);
for (uint64_t address = area; address < max_address; address += 8)
{
uint64_t data = READ64(address);
@@ -307,7 +309,7 @@ static int test_mem_march_c(uint64_t area, uint64_t max_address, uint64_t patter
BDK_DCACHE_INVALIDATE;
/* Pass 3: ascending addresses, read ~pattern and write pattern. */
- BDK_TRACE(DRAM_TEST, " [0x%016lx:0x%016lx] Phase3, address incrementing, pattern 0x%016lx\n", area, max_address-1, pattern);
+ BDK_TRACE(DRAM_TEST, " [0x%016llx:0x%016llx] Phase3, address incrementing, pattern 0x%016llx\n", area, max_address-1, pattern);
for (uint64_t address = area; address < max_address; address += 8)
{
uint64_t data = READ64(address);
@@ -320,7 +322,7 @@ static int test_mem_march_c(uint64_t area, uint64_t max_address, uint64_t patter
BDK_DCACHE_INVALIDATE;
/* Pass 4: descending addresses, read pattern and write ~pattern. */
- BDK_TRACE(DRAM_TEST, " [0x%016lx:0x%016lx] Phase4, address decrementing, pattern 0x%016lx\n", area, max_address-1, ~pattern);
+ BDK_TRACE(DRAM_TEST, " [0x%016llx:0x%016llx] Phase4, address decrementing, pattern 0x%016llx\n", area, max_address-1, ~pattern);
uint64_t end = max_address - sizeof(uint64_t);
for (uint64_t address = end; address >= area; address -= 8)
{
@@ -334,7 +336,7 @@ static int test_mem_march_c(uint64_t area, uint64_t max_address, uint64_t patter
BDK_DCACHE_INVALIDATE;
/* Pass 5: descending addresses, read ~pattern and write pattern. */
- BDK_TRACE(DRAM_TEST, " [0x%016lx:0x%016lx] Phase5, address decrementing, pattern 0x%016lx\n", area, max_address-1, pattern);
+ BDK_TRACE(DRAM_TEST, " [0x%016llx:0x%016llx] Phase5, address decrementing, pattern 0x%016llx\n", area, max_address-1, pattern);
for (uint64_t address = end; address >= area; address -= 8)
{
uint64_t data = READ64(address);
@@ -347,7 +349,7 @@ static int test_mem_march_c(uint64_t area, uint64_t max_address, uint64_t patter
BDK_DCACHE_INVALIDATE;
/* Pass 6: ascending addresses, read pattern. */
- BDK_TRACE(DRAM_TEST, " [0x%016lx:0x%016lx] Phase6, address incrementing\n", area, max_address-1);
+ BDK_TRACE(DRAM_TEST, " [0x%016llx:0x%016llx] Phase6, address incrementing\n", area, max_address-1);
for (uint64_t address = area; address < max_address; address += 8)
{
uint64_t data = READ64(address);
@@ -660,7 +662,7 @@ int __bdk_dram_test_mem_xor(uint64_t area, uint64_t max_address, int bursts)
WRITE64(address1 , p);
WRITE64(address1 + offset, p);
address1 += 8;
- p += pincr;
+ p += pincr;
}
__bdk_dram_flush_to_mem_range(area, max_address);
BDK_DCACHE_INVALIDATE;
@@ -674,7 +676,7 @@ int __bdk_dram_test_mem_xor(uint64_t area, uint64_t max_address, int bursts)
address1 = area;
this_pattern = bdk_rng_get_random64();
- pattern2 ^= this_pattern;
+ pattern2 ^= this_pattern;
while (address1 < area2)
{
@@ -693,13 +695,13 @@ int __bdk_dram_test_mem_xor(uint64_t area, uint64_t max_address, int bursts)
BDK_DCACHE_INVALIDATE;
/* Look for differences from the expected pattern in both areas.
- * If there is a mismatch, reset the appropriate memory location
- * with the correct pattern. Failing to do so
+ * If there is a mismatch, reset the appropriate memory location
+ * with the correct pattern. Failing to do so
* means that on all subsequent passes the erroring locations
- * will be out of sync, giving spurious errors.
+ * will be out of sync, giving spurious errors.
*/
address1 = area;
- ppred = pbase;
+ ppred = pbase;
while (address1 < area2)
{
@@ -712,21 +714,21 @@ int __bdk_dram_test_mem_xor(uint64_t area, uint64_t max_address, int bursts)
d1 = READ64(address1 );
d2 = READ64(address1 + offset);
- p = ppred ^ pattern2;
+ p = ppred ^ pattern2;
if (bdk_unlikely(d1 != p)) {
- failures += __bdk_dram_retry_failure(burst, address1, d1, p);
+ failures += __bdk_dram_retry_failure(burst, address1, d1, p);
// Synchronize the area, adjusting for the error.
//WRITE64(address1, p); // retries should do this
}
if (bdk_unlikely(d2 != p)) {
- failures += __bdk_dram_retry_failure(burst, address1 + offset, d2, p);
+ failures += __bdk_dram_retry_failure(burst, address1 + offset, d2, p);
// Synchronize the area, adjusting for the error.
//WRITE64(address1 + offset, p); // retries should do this
}
address1 += 8;
- ppred += pincr;
+ ppred += pincr;
} /* while (address1 < area2) */
} /* for (int burst = 0; burst < bursts; burst++) */
@@ -761,7 +763,7 @@ int __bdk_dram_test_mem_rows(uint64_t area, uint64_t max_address, int bursts)
WRITE64(address1 , pattern2);
WRITE64(address1 + offset, pattern2);
address1 += 8;
- pattern2 = ~pattern2; // flip for next slots
+ pattern2 = ~pattern2; // flip for next slots
}
__bdk_dram_flush_to_mem_range(area, max_address);
@@ -771,7 +773,7 @@ int __bdk_dram_test_mem_rows(uint64_t area, uint64_t max_address, int bursts)
for (burst = 0; burst < bursts; burst++)
{
/* Invert the data, applying the change to both memory areas. Thus on
- * alternate passes, the data flips from 0 to 1 and vice versa.
+ * alternate passes, the data flips from 0 to 1 and vice versa.
*/
address1 = area;
@@ -796,8 +798,8 @@ int __bdk_dram_test_mem_rows(uint64_t area, uint64_t max_address, int bursts)
* out of sync giving spurious errors.
*/
address1 = area;
- pattern1 = ~pattern1; // flip the starting pattern to match above loop
- pattern2 = pattern1; // slots have been flipped by the above loop
+ pattern1 = ~pattern1; // flip the starting pattern to match above loop
+ pattern2 = pattern1; // slots have been flipped by the above loop
while (address1 < area2)
{
@@ -810,18 +812,18 @@ int __bdk_dram_test_mem_rows(uint64_t area, uint64_t max_address, int bursts)
d2 = READ64(address1 + offset);
if (bdk_unlikely(d1 != pattern2)) {
- failures += __bdk_dram_retry_failure(burst, address1, d1, pattern2);
+ failures += __bdk_dram_retry_failure(burst, address1, d1, pattern2);
// Synchronize the area, adjusting for the error.
//WRITE64(address1, pattern2); // retries should do this
}
if (bdk_unlikely(d2 != pattern2)) {
- failures += __bdk_dram_retry_failure(burst, address1 + offset, d2, pattern2);
+ failures += __bdk_dram_retry_failure(burst, address1 + offset, d2, pattern2);
// Synchronize the two areas, adjusting for the error.
//WRITE64(address1 + offset, pattern2); // retries should do this
}
address1 += 8;
- pattern2 = ~pattern2; // flip for next pair of slots
+ pattern2 = ~pattern2; // flip for next pair of slots
}
}
return failures;
diff --git a/src/vendorcode/cavium/bdk/libbdk-dram/bdk-dram-test.c b/src/vendorcode/cavium/bdk/libbdk-dram/bdk-dram-test.c
index 53137502fc..4f54b69516 100644
--- a/src/vendorcode/cavium/bdk/libbdk-dram/bdk-dram-test.c
+++ b/src/vendorcode/cavium/bdk/libbdk-dram/bdk-dram-test.c
@@ -40,6 +40,14 @@
#include "libbdk-arch/bdk-csrs-gti.h"
#include "libbdk-arch/bdk-csrs-ocx.h"
+#include <bdk-minimal.h> /* for printf --> printk */
+#include <libbdk-dram/bdk-dram-test.h>
+#include <libbdk-hal/bdk-atomic.h>
+#include <libbdk-hal/bdk-clock.h>
+#include <libbdk-hal/bdk-utils.h>
+#include <libbdk-os/bdk-init.h>
+#include <libbdk-os/bdk-thread.h>
+
/* This code is an optional part of the BDK. It is only linked in
if BDK_REQUIRE() needs it */
BDK_REQUIRE_DEFINE(DRAM_TEST);
@@ -170,7 +178,7 @@ static void dram_test_thread(int arg, void *arg1)
start_address = bdk_numa_get_address(test_node, start_address);
end_address = bdk_numa_get_address(test_node, end_address);
/* Test the region */
- BDK_TRACE(DRAM_TEST, " Node %d, core %d, Testing [0x%011lx:0x%011lx]\n",
+ BDK_TRACE(DRAM_TEST, " Node %d, core %d, Testing [0x%011llx:0x%011llx]\n",
bdk_numa_local(), bdk_get_core_num() & 127, start_address, end_address - 1);
test_info->test_func(start_address, end_address, bursts);
@@ -197,7 +205,7 @@ static int __bdk_dram_run_test(const dram_test_info_t *test_info, uint64_t start
{
/* Figure out the addess of the byte one off the top of memory */
uint64_t max_address = bdk_dram_get_size_mbytes(bdk_numa_local());
- BDK_TRACE(DRAM_TEST, "DRAM available per node: %lu MB\n", max_address);
+ BDK_TRACE(DRAM_TEST, "DRAM available per node: %llu MB\n", max_address);
max_address <<= 20;
/* Make sure we have enough */
@@ -218,13 +226,13 @@ static int __bdk_dram_run_test(const dram_test_info_t *test_info, uint64_t start
if (max_address > (1ull << 43)) /* 43 bits in CN9XXX */
max_address = 1ull << 43;
}
- BDK_TRACE(DRAM_TEST, "DRAM max address: 0x%011lx\n", max_address-1);
+ BDK_TRACE(DRAM_TEST, "DRAM max address: 0x%011llx\n", max_address-1);
/* Make sure the start address is lower than the top of memory */
if (start_address >= max_address)
{
- bdk_error("Start address is larger than the amount of memory: 0x%011lx versus 0x%011lx\n",
- start_address, max_address);
+ bdk_error("Start address is larger than the amount of memory: 0x%011llx versus 0x%011llx\n",
+ start_address, max_address);
return -1;
}
if (length == (uint64_t)-1)
@@ -260,8 +268,8 @@ static int __bdk_dram_run_test(const dram_test_info_t *test_info, uint64_t start
}
}
if (!(flags & BDK_DRAM_TEST_NO_BANNERS))
- printf("Starting Test \"%s\" for [0x%011lx:0x%011lx] using %d core(s)\n",
- test_info->name, start_address, end_address - 1, total_cores_all_nodes);
+ printf("Starting Test \"%s\" for [0x%011llx:0x%011llx] using %d core(s)\n",
+ test_info->name, start_address, end_address - 1, total_cores_all_nodes);
/* Remember the LMC perf counters for stats after the test */
uint64_t start_dram_dclk[BDK_NUMA_MAX_NODES][4];
@@ -332,15 +340,15 @@ static int __bdk_dram_run_test(const dram_test_info_t *test_info, uint64_t start
/* Poke the watchdog */
BDK_CSR_WRITE(bdk_numa_local(), BDK_GTI_CWD_POKEX(0), 0);
- /* disable progress output when batch mode is ON */
+ /* disable progress output when batch mode is ON */
if (!(flags & BDK_DRAM_TEST_NO_PROGRESS)) {
/* Report progress percentage */
int percent_x10 = (work_address - start_address) * 1000 / (end_address - start_address);
- printf(" %3d.%d%% complete, testing [0x%011lx:0x%011lx]\r",
+ printf(" %3d.%d%% complete, testing [0x%011llx:0x%011llx]\r",
percent_x10 / 10, percent_x10 % 10, work_address, work_address + size - 1);
fflush(stdout);
- }
+ }
work_address += size;
@@ -357,17 +365,8 @@ static int __bdk_dram_run_test(const dram_test_info_t *test_info, uint64_t start
{
if (per_node >= max_cores)
break;
- int run_node = (flags & BDK_DRAM_TEST_USE_CCPI) ? node ^ 1 : node;
BDK_TRACE(DRAM_TEST, "Starting thread %d on node %d for memory test\n", per_node, node);
- if (bdk_thread_create(run_node, 0, dram_test_thread, per_node, (void *)test_info, 0))
- {
- bdk_error("Failed to create thread %d for memory test on node %d\n", per_node, node);
- }
- else
- {
- per_node++;
- total_count++;
- }
+ dram_test_thread(per_node, (void *)test_info);
}
}
}
@@ -384,7 +383,6 @@ static int __bdk_dram_run_test(const dram_test_info_t *test_info, uint64_t start
uint64_t period = bdk_clock_get_rate(bdk_numa_local(), BDK_CLOCK_TIME) * TIMEOUT_SECS; // FIXME?
uint64_t timeout = bdk_clock_get_count(BDK_CLOCK_TIME) + period;
do {
- bdk_thread_yield();
cur_count = bdk_atomic_get64(&dram_test_thread_done);
cur_time = bdk_clock_get_count(BDK_CLOCK_TIME);
if (cur_time >= timeout) {
@@ -430,7 +428,7 @@ static int __bdk_dram_run_test(const dram_test_info_t *test_info, uint64_t start
if (!(flags & BDK_DRAM_TEST_NO_PROGRESS)) {
/* Report progress percentage as complete */
- printf(" %3d.%d%% complete, testing [0x%011lx:0x%011lx]\n",
+ printf(" %3d.%d%% complete, testing [0x%011llx:0x%011llx]\n",
100, 0, start_address, end_address - 1);
fflush(stdout);
}
@@ -450,7 +448,7 @@ static int __bdk_dram_run_test(const dram_test_info_t *test_info, uint64_t start
if (dclk == 0)
dclk = 1;
uint64_t percent_x10 = ops * 1000 / dclk;
- printf(" Node %d, LMC%d: ops %lu, cycles %lu, used %lu.%lu%%\n",
+ printf(" Node %d, LMC%d: ops %llu, cycles %llu, used %llu.%llu%%\n",
node, i, ops, dclk, percent_x10 / 10, percent_x10 % 10);
}
}
@@ -471,7 +469,7 @@ static int __bdk_dram_run_test(const dram_test_info_t *test_info, uint64_t start
if (total == 0)
continue;
uint64_t percent_x10 = busy * 1000 / total;
- printf(" Node %d, CCPI%d: busy %lu, total %lu, used %lu.%lu%%\n",
+ printf(" Node %d, CCPI%d: busy %llu, total %llu, used %llu.%llu%%\n",
node, link, busy, total, percent_x10 / 10, percent_x10 % 10);
}
}
@@ -543,11 +541,13 @@ int bdk_dram_test(int test, uint64_t start_address, uint64_t length, bdk_dram_te
/* Clear ECC error counters before starting the test */
for (int chan = 0; chan < BDK_MAX_MEM_CHANS; chan++) {
- bdk_atomic_set64(&__bdk_dram_ecc_single_bit_errors[chan], 0);
- bdk_atomic_set64(&__bdk_dram_ecc_double_bit_errors[chan], 0);
+ bdk_atomic_set64(&__bdk_dram_ecc_single_bit_errors[chan], 0);
+ bdk_atomic_set64(&__bdk_dram_ecc_double_bit_errors[chan], 0);
}
/* Make sure at least one core from each node is running */
+ /* FIXME(dhendrix): we only care about core0 on node0 for now */
+#if 0
for (bdk_node_t node = BDK_NODE_0; node < BDK_NUMA_MAX_NODES; node++)
{
if (flags & (1<<node))
@@ -557,17 +557,11 @@ int bdk_dram_test(int test, uint64_t start_address, uint64_t length, bdk_dram_te
bdk_init_cores(use_node, 1);
}
}
+#endif
/* This returns any data compare errors found */
int errors = __bdk_dram_run_test(&TEST_INFO[test], start_address, length, flags);
- /* Poll for any errors right now to make sure any ECC errors are reported */
- for (bdk_node_t node = BDK_NODE_0; node < BDK_NUMA_MAX_NODES; node++)
- {
- if (bdk_numa_exists(node) && bdk_error_check)
- bdk_error_check(node);
- }
-
/* Check ECC error counters after the test */
int64_t ecc_single = 0;
int64_t ecc_double = 0;
@@ -582,14 +576,14 @@ int bdk_dram_test(int test, uint64_t start_address, uint64_t length, bdk_dram_te
/* Always print any ECC errors */
if (ecc_single || ecc_double)
{
- printf("Test \"%s\": ECC errors, %ld/%ld/%ld/%ld corrected, %ld/%ld/%ld/%ld uncorrected\n",
- name,
- ecc_single_errs[0], ecc_single_errs[1], ecc_single_errs[2], ecc_single_errs[3],
- ecc_double_errs[0], ecc_double_errs[1], ecc_double_errs[2], ecc_double_errs[3]);
+ printf("Test \"%s\": ECC errors, %lld/%lld/%lld/%lld corrected, %lld/%lld/%lld/%lld uncorrected\n",
+ name,
+ ecc_single_errs[0], ecc_single_errs[1], ecc_single_errs[2], ecc_single_errs[3],
+ ecc_double_errs[0], ecc_double_errs[1], ecc_double_errs[2], ecc_double_errs[3]);
}
if (errors || ecc_double || ecc_single) {
- printf("Test \"%s\": FAIL: %ld single, %ld double, %d compare errors\n",
- name, ecc_single, ecc_double, errors);
+ printf("Test \"%s\": FAIL: %lld single, %lld double, %d compare errors\n",
+ name, ecc_single, ecc_double, errors);
}
else
BDK_TRACE(DRAM_TEST, "Test \"%s\": PASS\n", name);
@@ -610,7 +604,7 @@ static void __bdk_dram_report_address_decode(uint64_t address, char *buffer, int
bdk_dram_address_extract_info(address, &node, &lmc, &dimm, &prank, &lrank, &bank, &row, &col);
snprintf(buffer, len, "[0x%011lx] (N%d,LMC%d,DIMM%d,Rank%d/%d,Bank%02d,Row 0x%05x,Col 0x%04x)",
- address, node, lmc, dimm, prank, lrank, bank, row, col);
+ address, node, lmc, dimm, prank, lrank, bank, row, col);
}
/**
@@ -632,22 +626,22 @@ static void __bdk_dram_report_address_decode_new(uint64_t address, uint64_t orig
for (int i = 0; i < 8; i++) {
bits = xor & 0xffULL;
xor >>= 8;
- if (bits) {
- if (byte != 8) {
- byte = 9; // means more than 1 byte-lane was present
+ if (bits) {
+ if (byte != 8) {
+ byte = 9; // means more than 1 byte-lane was present
print_bits = orig_xor; // print the full original
- break; // quit now
- } else {
- byte = i; // keep checking
+ break; // quit now
+ } else {
+ byte = i; // keep checking
print_bits = bits;
- }
- }
+ }
+ }
}
-
+
bdk_dram_address_extract_info(address, &node, &lmc, &dimm, &prank, &lrank, &bank, &row, &col);
snprintf(buffer, len, "N%d.LMC%d: CMP byte %d xor 0x%02lx (DIMM%d,Rank%d/%d,Bank%02d,Row 0x%05x,Col 0x%04x)[0x%011lx]",
- node, lmc, byte, print_bits, dimm, prank, lrank, bank, row, col, address);
+ node, lmc, byte, print_bits, dimm, prank, lrank, bank, row, col, address);
}
/**
@@ -671,15 +665,15 @@ void __bdk_dram_report_error(uint64_t address, uint64_t data, uint64_t correct,
if (errors < MAX_ERRORS_TO_REPORT)
{
- if (fails < 0) {
- snprintf(failbuf, sizeof(failbuf), " ");
- } else {
+ if (fails < 0) {
+ snprintf(failbuf, sizeof(failbuf), " ");
+ } else {
int percent_x10 = fails * 1000 / RETRY_LIMIT;
- snprintf(failbuf, sizeof(failbuf), ", retries failed %3d.%d%%",
+ snprintf(failbuf, sizeof(failbuf), ", retries failed %3d.%d%%",
percent_x10 / 10, percent_x10 % 10);
- }
+ }
- __bdk_dram_report_address_decode_new(address, xor, buffer, sizeof(buffer));
+ __bdk_dram_report_address_decode_new(address, xor, buffer, sizeof(buffer));
bdk_error("%s%s\n", buffer, failbuf);
if (errors == MAX_ERRORS_TO_REPORT-1)
@@ -702,26 +696,26 @@ void __bdk_dram_report_error(uint64_t address, uint64_t data, uint64_t correct,
* @return Zero if a message was logged, non-zero if the error limit has been reached
*/
void __bdk_dram_report_error2(uint64_t address1, uint64_t data1, uint64_t address2, uint64_t data2,
- int burst, int fails)
+ int burst, int fails)
{
int64_t errors = bdk_atomic_fetch_and_add64(&dram_test_thread_errors, 1);
if (errors < MAX_ERRORS_TO_REPORT)
{
- char buffer1[80], buffer2[80];
- char failbuf[32];
-
- if (fails < 0) {
- snprintf(failbuf, sizeof(failbuf), " ");
- } else {
- snprintf(failbuf, sizeof(failbuf), ", retried %d failed %d", RETRY_LIMIT, fails);
- }
- __bdk_dram_report_address_decode(address1, buffer1, sizeof(buffer1));
- __bdk_dram_report_address_decode(address2, buffer2, sizeof(buffer2));
-
- bdk_error("compare: data1: 0x%016lx, xor: 0x%016lx%s\n"
- " %s\n %s\n",
- data1, data1 ^ data2, failbuf,
- buffer1, buffer2);
+ char buffer1[80], buffer2[80];
+ char failbuf[32];
+
+ if (fails < 0) {
+ snprintf(failbuf, sizeof(failbuf), " ");
+ } else {
+ snprintf(failbuf, sizeof(failbuf), ", retried %d failed %d", RETRY_LIMIT, fails);
+ }
+ __bdk_dram_report_address_decode(address1, buffer1, sizeof(buffer1));
+ __bdk_dram_report_address_decode(address2, buffer2, sizeof(buffer2));
+
+ bdk_error("compare: data1: 0x%016llx, xor: 0x%016llx%s\n"
+ " %s\n %s\n",
+ data1, data1 ^ data2, failbuf,
+ buffer1, buffer2);
if (errors == MAX_ERRORS_TO_REPORT-1)
bdk_error("No further DRAM errors will be reported\n");
@@ -741,23 +735,23 @@ int __bdk_dram_retry_failure(int burst, uint64_t address, uint64_t data, uint64_
// bypass the retries if we are already over the limit...
if (bdk_atomic_get64(&dram_test_thread_errors) < MAX_ERRORS_TO_REPORT) {
- /* Try re-reading the memory location. A transient error may fail
- * on one read and work on another. Keep on retrying even when a
- * read succeeds.
- */
- for (int i = 0; i < RETRY_LIMIT; i++) {
+ /* Try re-reading the memory location. A transient error may fail
+ * on one read and work on another. Keep on retrying even when a
+ * read succeeds.
+ */
+ for (int i = 0; i < RETRY_LIMIT; i++) {
- __bdk_dram_flush_to_mem(address);
- BDK_DCACHE_INVALIDATE;
+ __bdk_dram_flush_to_mem(address);
+ BDK_DCACHE_INVALIDATE;
- uint64_t new = __bdk_dram_read64(address);
+ uint64_t new = __bdk_dram_read64(address);
- if (new != expected) {
- refail++;
- }
- }
+ if (new != expected) {
+ refail++;
+ }
+ }
} else
- refail = -1;
+ refail = -1;
// this will increment the errors always, but maybe not print...
__bdk_dram_report_error(address, data, expected, burst, refail);
@@ -779,20 +773,20 @@ int __bdk_dram_retry_failure2(int burst, uint64_t address1, uint64_t data1, uint
// bypass the retries if we are already over the limit...
if (bdk_atomic_get64(&dram_test_thread_errors) < MAX_ERRORS_TO_REPORT) {
- for (int i = 0; i < RETRY_LIMIT; i++) {
- __bdk_dram_flush_to_mem(address1);
- __bdk_dram_flush_to_mem(address2);
- BDK_DCACHE_INVALIDATE;
+ for (int i = 0; i < RETRY_LIMIT; i++) {
+ __bdk_dram_flush_to_mem(address1);
+ __bdk_dram_flush_to_mem(address2);
+ BDK_DCACHE_INVALIDATE;
- uint64_t d1 = __bdk_dram_read64(address1);
- uint64_t d2 = __bdk_dram_read64(address2);
+ uint64_t d1 = __bdk_dram_read64(address1);
+ uint64_t d2 = __bdk_dram_read64(address2);
- if (d1 != d2) {
- refail++;
- }
- }
+ if (d1 != d2) {
+ refail++;
+ }
+ }
} else
- refail = -1;
+ refail = -1;
// this will increment the errors always, but maybe not print...
__bdk_dram_report_error2(address1, data1, address2, data2, burst, refail);
@@ -854,7 +848,7 @@ void bdk_dram_test_inject_error(uint64_t address, int bit)
BDK_CSR_WRITE(node, BDK_LMCX_CHAR_MASK2(lmc), 0);
/* Read back the data, which should now cause an error */
- printf("Loading the injected error address 0x%lx, node=%d, lmc=%d, dimm=%d, rank=%d/%d, bank=%d, row=%d, col=%d\n",
+ printf("Loading the injected error address 0x%llx, node=%d, lmc=%d, dimm=%d, rank=%d/%d, bank=%d, row=%d, col=%d\n",
address, node, lmc, dimm, prank, lrank, bank, row, col);
__bdk_dram_read64(aligned_address);
}
diff --git a/src/vendorcode/cavium/bdk/libbdk-driver/bdk-driver-mdio.c b/src/vendorcode/cavium/bdk/libbdk-driver/bdk-driver-mdio.c
new file mode 100644
index 0000000000..7f13d7ca32
--- /dev/null
+++ b/src/vendorcode/cavium/bdk/libbdk-driver/bdk-driver-mdio.c
@@ -0,0 +1,351 @@
+/***********************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-pccpf.h>
+#include <libbdk-arch/bdk-csrs-smi.h>
+#include <libbdk-hal/device/bdk-device.h>
+#include <libbdk-hal/bdk-mdio.h>
+
+/* This code is an optional part of the BDK. It is only linked in
+ if BDK_REQUIRE() needs it */
+BDK_REQUIRE_DEFINE(MDIO);
+
+/* To maintain backwards compatibility for the old MDIO API we need
+ to lookup the MDIO device on the ECAM bus by ID. This defines
+ the ID */
+#define MDIO_DEVID ((BDK_PCC_PROD_E_GEN << 24) | BDK_PCC_VENDOR_E_CAVIUM | (BDK_PCC_DEV_IDL_E_SMI << 16))
+
+#define BDK_MDIO_TIMEOUT 100000 /* 100 millisec */
+
+/* Operating request encodings. */
+#define MDIO_CLAUSE_22_WRITE 0
+#define MDIO_CLAUSE_22_READ 1
+
+#define MDIO_CLAUSE_45_ADDRESS 0
+#define MDIO_CLAUSE_45_WRITE 1
+#define MDIO_CLAUSE_45_READ_INC 2
+#define MDIO_CLAUSE_45_READ 3
+
+/**
+ * Helper function to put MDIO interface into clause 45 mode
+ *
+ * @param bus_id
+ */
+static void __bdk_mdio_set_clause45_mode(const bdk_device_t *device, int bus_id)
+{
+ bdk_smi_x_clk_t smi_clk;
+ /* Put bus into clause 45 mode */
+ smi_clk.u = BDK_BAR_READ(device, BDK_SMI_X_CLK(bus_id));
+ if (smi_clk.s.mode != 1)
+ {
+ smi_clk.s.mode = 1;
+ smi_clk.s.preamble = 1;
+ BDK_BAR_WRITE(device, BDK_SMI_X_CLK(bus_id), smi_clk.u);
+ }
+}
+
+/**
+ * Helper function to put MDIO interface into clause 22 mode
+ *
+ * @param bus_id
+ */
+static void __bdk_mdio_set_clause22_mode(const bdk_device_t *device, int bus_id)
+{
+ bdk_smi_x_clk_t smi_clk;
+ /* Put bus into clause 22 mode */
+ smi_clk.u = BDK_BAR_READ(device, BDK_SMI_X_CLK(bus_id));
+ if (smi_clk.s.mode != 0)
+ {
+ smi_clk.s.mode = 0;
+ BDK_BAR_WRITE(device, BDK_SMI_X_CLK(bus_id), smi_clk.u);
+ }
+}
+
+/**
+ * @INTERNAL
+ * Function to read SMIX_RD_DAT and check for timeouts. This
+ * code sequence is done fairly often, so put in in one spot.
+ *
+ * @param bus_id SMI/MDIO bus to read
+ *
+ * @return Value of SMIX_RD_DAT. pending will be set on
+ * a timeout.
+ */
+static bdk_smi_x_rd_dat_t __bdk_mdio_read_rd_dat(const bdk_device_t *device, int bus_id)
+{
+ bdk_smi_x_rd_dat_t smi_rd;
+ uint64_t done = bdk_clock_get_count(BDK_CLOCK_TIME) + (uint64_t)BDK_MDIO_TIMEOUT *
+ bdk_clock_get_rate(bdk_numa_local(), BDK_CLOCK_TIME) / 1000000;
+ do
+ {
+ smi_rd.u = BDK_BAR_READ(device, BDK_SMI_X_RD_DAT(bus_id));
+ } while (smi_rd.s.pending && (bdk_clock_get_count(BDK_CLOCK_TIME) < done));
+ return smi_rd;
+}
+
+
+/**
+ * Perform an MII read. This function is used to read PHY
+ * registers controlling auto negotiation.
+ *
+ * @param bus_id MDIO bus number. Zero on most chips, but some chips (ex CN56XX)
+ * support multiple busses.
+ * @param phy_id The MII phy id
+ * @param location Register location to read
+ *
+ * @return Result from the read or -1 on failure
+ */
+int bdk_mdio_read(bdk_node_t node, int bus_id, int phy_id, int location)
+{
+ const bdk_device_t *device = bdk_device_lookup(node, MDIO_DEVID, 0);
+ if (!device)
+ {
+ bdk_error("MDIO: ECAM device not found\n");
+ return -1;
+ }
+ bdk_smi_x_cmd_t smi_cmd;
+ bdk_smi_x_rd_dat_t smi_rd;
+
+ __bdk_mdio_set_clause22_mode(device, bus_id);
+
+ smi_cmd.u = 0;
+ smi_cmd.s.phy_op = MDIO_CLAUSE_22_READ;
+ smi_cmd.s.phy_adr = phy_id;
+ smi_cmd.s.reg_adr = location;
+ BDK_BAR_WRITE(device, BDK_SMI_X_CMD(bus_id), smi_cmd.u);
+
+ smi_rd = __bdk_mdio_read_rd_dat(device, bus_id);
+ if (smi_rd.s.val)
+ return smi_rd.s.dat;
+ else
+ return -1;
+}
+
+
+/**
+ * Perform an MII write. This function is used to write PHY
+ * registers controlling auto negotiation.
+ *
+ * @param bus_id MDIO bus number. Zero on most chips, but some chips (ex CN56XX)
+ * support multiple busses.
+ * @param phy_id The MII phy id
+ * @param location Register location to write
+ * @param val Value to write
+ *
+ * @return -1 on error
+ * 0 on success
+ */
+int bdk_mdio_write(bdk_node_t node, int bus_id, int phy_id, int location, int val)
+{
+ const bdk_device_t *device = bdk_device_lookup(node, MDIO_DEVID, 0);
+ if (!device)
+ {
+ bdk_error("MDIO: ECAM device not found\n");
+ return -1;
+ }
+ bdk_smi_x_cmd_t smi_cmd;
+ bdk_smi_x_wr_dat_t smi_wr;
+
+ __bdk_mdio_set_clause22_mode(device, bus_id);
+
+ smi_wr.u = 0;
+ smi_wr.s.dat = val;
+ BDK_BAR_WRITE(device, BDK_SMI_X_WR_DAT(bus_id), smi_wr.u);
+
+ smi_cmd.u = 0;
+ smi_cmd.s.phy_op = MDIO_CLAUSE_22_WRITE;
+ smi_cmd.s.phy_adr = phy_id;
+ smi_cmd.s.reg_adr = location;
+ BDK_BAR_WRITE(device, BDK_SMI_X_CMD(bus_id), smi_cmd.u);
+
+ if (BDK_BAR_WAIT_FOR_FIELD(device, BDK_SMI_X_WR_DAT(bus_id), pending, ==, 0, BDK_MDIO_TIMEOUT))
+ return -1;
+
+ return 0;
+}
+
+/**
+ * Perform an IEEE 802.3 clause 45 MII read. This function is used to read PHY
+ * registers controlling auto negotiation.
+ *
+ * @param bus_id MDIO bus number. Zero on most chips, but some chips (ex CN56XX)
+ * support multiple busses.
+ * @param phy_id The MII phy id
+ * @param device MDIO Manageable Device (MMD) id
+ * @param location Register location to read
+ *
+ * @return Result from the read or -1 on failure
+ */
+
+int bdk_mdio_45_read(bdk_node_t node, int bus_id, int phy_id, int device, int location)
+{
+ const bdk_device_t *ecam_device = bdk_device_lookup(node, MDIO_DEVID, 0);
+ if (!ecam_device)
+ {
+ bdk_error("MDIO: ECAM device not found\n");
+ return -1;
+ }
+ bdk_smi_x_cmd_t smi_cmd;
+ bdk_smi_x_rd_dat_t smi_rd;
+ bdk_smi_x_wr_dat_t smi_wr;
+
+ __bdk_mdio_set_clause45_mode(ecam_device, bus_id);
+
+ smi_wr.u = 0;
+ smi_wr.s.dat = location;
+ BDK_BAR_WRITE(ecam_device, BDK_SMI_X_WR_DAT(bus_id), smi_wr.u);
+
+ smi_cmd.u = 0;
+ smi_cmd.s.phy_op = MDIO_CLAUSE_45_ADDRESS;
+ smi_cmd.s.phy_adr = phy_id;
+ smi_cmd.s.reg_adr = device;
+ BDK_BAR_WRITE(ecam_device, BDK_SMI_X_CMD(bus_id), smi_cmd.u);
+
+ if (BDK_BAR_WAIT_FOR_FIELD(ecam_device, BDK_SMI_X_WR_DAT(bus_id), pending, ==, 0, BDK_MDIO_TIMEOUT))
+ {
+ bdk_error("bdk_mdio_45_read: bus_id %d phy_id %2d device %2d register %2d TIME OUT(address)\n", bus_id, phy_id, device, location);
+ return -1;
+ }
+
+ smi_cmd.u = 0;
+ smi_cmd.s.phy_op = MDIO_CLAUSE_45_READ;
+ smi_cmd.s.phy_adr = phy_id;
+ smi_cmd.s.reg_adr = device;
+ BDK_BAR_WRITE(ecam_device, BDK_SMI_X_CMD(bus_id), smi_cmd.u);
+
+ smi_rd = __bdk_mdio_read_rd_dat(ecam_device, bus_id);
+ if (smi_rd.s.pending)
+ {
+ bdk_error("bdk_mdio_45_read: bus_id %d phy_id %2d device %2d register %2d TIME OUT(data)\n", bus_id, phy_id, device, location);
+ return -1;
+ }
+
+ if (smi_rd.s.val)
+ return smi_rd.s.dat;
+ else
+ {
+ bdk_error("bdk_mdio_45_read: bus_id %d phy_id %2d device %2d register %2d INVALID READ\n", bus_id, phy_id, device, location);
+ return -1;
+ }
+}
+
+/**
+ * Perform an IEEE 802.3 clause 45 MII write. This function is used to write PHY
+ * registers controlling auto negotiation.
+ *
+ * @param bus_id MDIO bus number. Zero on most chips, but some chips (ex CN56XX)
+ * support multiple busses.
+ * @param phy_id The MII phy id
+ * @param device MDIO Manageable Device (MMD) id
+ * @param location Register location to write
+ * @param val Value to write
+ *
+ * @return -1 on error
+ * 0 on success
+ */
+int bdk_mdio_45_write(bdk_node_t node, int bus_id, int phy_id, int device, int location,
+ int val)
+{
+ const bdk_device_t *ecam_device = bdk_device_lookup(node, MDIO_DEVID, 0);
+ if (!ecam_device)
+ {
+ bdk_error("MDIO: ECAM device not found\n");
+ return -1;
+ }
+ bdk_smi_x_cmd_t smi_cmd;
+ bdk_smi_x_wr_dat_t smi_wr;
+
+ __bdk_mdio_set_clause45_mode(ecam_device, bus_id);
+
+ smi_wr.u = 0;
+ smi_wr.s.dat = location;
+ BDK_BAR_WRITE(ecam_device, BDK_SMI_X_WR_DAT(bus_id), smi_wr.u);
+
+ smi_cmd.u = 0;
+ smi_cmd.s.phy_op = MDIO_CLAUSE_45_ADDRESS;
+ smi_cmd.s.phy_adr = phy_id;
+ smi_cmd.s.reg_adr = device;
+ BDK_BAR_WRITE(ecam_device, BDK_SMI_X_CMD(bus_id), smi_cmd.u);
+
+ if (BDK_BAR_WAIT_FOR_FIELD(ecam_device, BDK_SMI_X_WR_DAT(bus_id), pending, ==, 0, BDK_MDIO_TIMEOUT))
+ return -1;
+
+ smi_wr.u = 0;
+ smi_wr.s.dat = val;
+ BDK_BAR_WRITE(ecam_device, BDK_SMI_X_WR_DAT(bus_id), smi_wr.u);
+
+ smi_cmd.u = 0;
+ smi_cmd.s.phy_op = MDIO_CLAUSE_45_WRITE;
+ smi_cmd.s.phy_adr = phy_id;
+ smi_cmd.s.reg_adr = device;
+ BDK_BAR_WRITE(ecam_device, BDK_SMI_X_CMD(bus_id), smi_cmd.u);
+
+ if (BDK_BAR_WAIT_FOR_FIELD(ecam_device, BDK_SMI_X_WR_DAT(bus_id), pending, ==, 0, BDK_MDIO_TIMEOUT))
+ return -1;
+
+ return 0;
+}
+
+/**
+ * MDIO init() function
+ *
+ * @param device MDIO/SMI to initialize
+ *
+ * @return Zero on success, negative on failure
+ */
+int bdk_mdio_init(bdk_node_t node)
+{
+ const bdk_device_t *device = bdk_device_lookup(node, MDIO_DEVID, 0);
+ if (!device)
+ {
+ bdk_error("MDIO: ECAM device not found\n");
+ return -1;
+ }
+ /* Change drive strength bits to fix issues when a QLM cable
+ is connected, creating a long spur path */
+ BDK_CSR_MODIFY(c, device->node, BDK_SMI_DRV_CTL,
+ c.s.pctl = 7; /* 30 ohm */
+ c.s.nctl = 7); /* 30 ohm */
+
+ for (int i = 0; i < 2; i++)
+ BDK_BAR_MODIFY(c, device, BDK_SMI_X_EN(i), c.s.en = 1);
+
+ return 0;
+}
+
diff --git a/src/vendorcode/cavium/bdk/libbdk-driver/bdk-driver-rnm.c b/src/vendorcode/cavium/bdk/libbdk-driver/bdk-driver-rnm.c
index 8394ad8c5e..c3a71f79dc 100644
--- a/src/vendorcode/cavium/bdk/libbdk-driver/bdk-driver-rnm.c
+++ b/src/vendorcode/cavium/bdk/libbdk-driver/bdk-driver-rnm.c
@@ -22,7 +22,8 @@
*
* 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
+* associateint bdk_rng_init(bdk_node_t node)
+* d 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"
@@ -40,6 +41,10 @@
#include "libbdk-arch/bdk-csrs-pccpf.h"
#include "libbdk-arch/bdk-csrs-rnm.h"
+#include <libbdk-hal/bdk-rng.h>
+#include <libbdk-hal/device/bdk-device.h>
+#define RNG_DEVID ((BDK_PCC_PROD_E_GEN << 24) | BDK_PCC_VENDOR_E_CAVIUM | (BDK_PCC_DEV_IDL_E_RNM << 16))
+
BDK_REQUIRE_DEFINE(RNM);
/**
@@ -84,32 +89,26 @@ uint64_t bdk_rng_get_random64(void)
}
/**
- * The RNM probe function
- *
- * @param device RNM to probe
- *
- * @return Zero on success, negative on failure
- */
-static int probe(bdk_device_t *device)
-{
- bdk_device_rename(device, "N%d.RNM%d", device->node, device->instance);
- return 0;
-}
-
-/**
* RNM init() function
*
* @param device RNM to initialize
*
* @return Zero on success, negative on failure
*/
-static int init(bdk_device_t *device)
+int bdk_rng_init(bdk_node_t node)
{
+ const bdk_device_t *device = bdk_device_lookup(node, RNG_DEVID, 0);
+ if (!device)
+ {
+ bdk_error("RNM: ECAM device not found\n");
+ return -1;
+ }
BDK_BAR_MODIFY(c, device, BDK_RNM_CTL_STATUS,
c.s.ent_en = 1;
c.s.rng_en = 1);
- /* Read back after enable so we know it is done. Needed on t88 pass 2.0 emulator */
+ /* Read back after enable so we know it is done. Needed on t88 pass 2.0 emulator and t81 real hardware !!!! */
BDK_BAR_READ(device, BDK_RNM_CTL_STATUS);
+
/* Errata (RNM-22528) First consecutive reads to RNM_RANDOM return same
value. Before using the random entropy, read RNM_RANDOM at least once
and discard the data */
@@ -117,8 +116,3 @@ static int init(bdk_device_t *device)
return 0;
}
-bdk_driver_t __bdk_driver_rnm = {
- .id = (BDK_PCC_PROD_E_GEN << 24) | BDK_PCC_VENDOR_E_CAVIUM | (BDK_PCC_DEV_IDL_E_RNM << 16),
- .probe = probe,
- .init = init,
-};
diff --git a/src/vendorcode/cavium/bdk/libbdk-hal/bdk-access.c b/src/vendorcode/cavium/bdk/libbdk-hal/bdk-access.c
new file mode 100644
index 0000000000..ebced00715
--- /dev/null
+++ b/src/vendorcode/cavium/bdk/libbdk-hal/bdk-access.c
@@ -0,0 +1,70 @@
+/***********************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-uaa.h"
+#include "libbdk-arch/bdk-csrs-rst.h"
+
+/**
+ * Perform a soft reset of the chip
+ *
+ * @return
+ */
+void bdk_reset_chip(bdk_node_t node)
+{
+ fflush(NULL);
+
+ /* Wait for TX fifo to empty */
+ while (1)
+ {
+ BDK_CSR_INIT(fr, node, BDK_UAAX_FR(0));
+ if (fr.s.txfe)
+ break;
+ }
+
+ /* RST_OCX is not cleared by a chip reset. Clear it now to avoid repeated
+ resets due to CCPI state changes during reset */
+ BDK_CSR_WRITE(node, BDK_RST_OCX, 0);
+ BDK_CSR_READ(node, BDK_RST_OCX);
+
+ bdk_rst_soft_rst_t rst_soft_rst;
+ rst_soft_rst.u = 0;
+ rst_soft_rst.s.soft_rst = 1;
+ BDK_CSR_WRITE(node, BDK_RST_SOFT_RST, rst_soft_rst.u);
+}
+
diff --git a/src/vendorcode/cavium/bdk/libbdk-hal/bdk-clock.c b/src/vendorcode/cavium/bdk/libbdk-hal/bdk-clock.c
index f81285dffd..b8b0952de4 100644
--- a/src/vendorcode/cavium/bdk/libbdk-hal/bdk-clock.c
+++ b/src/vendorcode/cavium/bdk/libbdk-hal/bdk-clock.c
@@ -37,123 +37,10 @@
* 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);
- }
- }
-}
+#include <libbdk-arch/bdk-csrs-gti.h>
+#include <libbdk-arch/bdk-csrs-ocx.h>
+#include <libbdk-hal/bdk-clock.h>
+#include <libbdk-arch/bdk-csrs-rst.h>
/**
* Get cycle count based on the clock type.
@@ -165,12 +52,6 @@ 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)
{
@@ -199,12 +80,6 @@ uint64_t __bdk_clock_get_rate_slow(bdk_node_t node, bdk_clock_t clock)
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:
diff --git a/src/vendorcode/cavium/bdk/libbdk-hal/bdk-config.c b/src/vendorcode/cavium/bdk/libbdk-hal/bdk-config.c
index d4b412d439..91f05d3ae7 100644
--- a/src/vendorcode/cavium/bdk/libbdk-hal/bdk-config.c
+++ b/src/vendorcode/cavium/bdk/libbdk-hal/bdk-config.c
@@ -1,81 +1,265 @@
-/***********************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**************************************/
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright (c) 2003-2017 Cavium Inc. (support@cavium.com). All rights
+ * reserved.
+ * Copyright 2018-present Facebook, Inc.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * This file consists of data imported from bdk-config.c
+ */
+
#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"
+#include <libbdk-hal/bdk-config.h>
+#include <string.h>
+#include <assert.h>
+#include <lame_string.h>
+
+static struct bdk_devicetree_key_value *config_fdt;
+
+#if !defined(__PRE_RAM__)
+static struct bdk_devicetree_key_value *bdk_config_duplicate(
+ const struct bdk_devicetree_key_value *old,
+ size_t free_space)
+{
+ struct bdk_devicetree_key_value *new;
+ size_t len = sizeof(struct bdk_devicetree_key_value) + free_space;
+ const struct bdk_devicetree_key_value *iter = old;
+ while (iter->key) {
+ iter++;
+ len += sizeof(struct bdk_devicetree_key_value);
+ }
+ new = malloc(len);
+ if (!new)
+ return NULL;
-/* 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
+ memcpy(new, old, len);
+
+ return new;
+}
+#endif
+/**
+ * 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(const struct bdk_devicetree_key_value *fdt)
+{
+#if !defined(__PRE_RAM__)
+ config_fdt = bdk_config_duplicate(fdt, 0);
+#else
+ config_fdt = (void *)fdt;
+#endif
+ return 0;
+}
-typedef enum
+/**
+ * Look up a configuration item in the environment and replace it.
+ *
+ * @param name
+ *
+ * @return
+ */
+static void set_value(const char *name, const char *val)
{
- BDK_CONFIG_TYPE_INT,
- BDK_CONFIG_TYPE_STR,
- BDK_CONFIG_TYPE_STR_LIST,
- BDK_CONFIG_TYPE_BINARY,
-} bdk_config_type_t;
+#if !defined(__PRE_RAM__)
+ struct bdk_devicetree_key_value *iter;
+ char n[64];
+
+ strncpy(n, name, sizeof(n));
+ n[sizeof(n)-1] = '\0';
+
+ iter = config_fdt;
+ while (iter->key) {
+ if (strcmp(iter->key, n) == 0) {
+ // we are leaking memory here...
+ iter->value = (const char *)strdup(val);
+ return;
+ }
+ iter++;
+ }
+ /* Not found: Create one */
+ iter = bdk_config_duplicate(config_fdt,
+ sizeof(struct bdk_devicetree_key_value));
+ if (!iter)
+ return;
-typedef struct
+ free(config_fdt);
+ config_fdt = iter;
+ while (iter->key) {
+ iter++;
+ }
+ iter->key = (const char *)strdup(name);
+ iter->value = (const char *)strdup(val);
+ iter++;
+ iter->key = 0;
+ iter->value = 0;
+#endif
+}
+
+/**
+ * Look up a configuration item in the environment.
+ *
+ * @param name
+ *
+ * @return
+ */
+static const char *get_value(const char *name)
{
- 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;
+ const struct bdk_devicetree_key_value *iter;
+ char n[64];
-static void config_set_defaults(void);
+ strncpy(n, name, sizeof(n));
+ n[sizeof(n)-1] = '\0';
-/* Tracing defaults to the level specified here before config files are loaded */
-uint64_t bdk_trace_enables = BDK_TRACE_OVERRIDE;
+ while (*n) {
+ iter = config_fdt;
+ while (iter->key) {
+ if (strcmp(iter->key, n) == 0)
+ return iter->value;
+ iter++;
+ }
-/* Global variables that contain the config inside a FDT */
-static void *config_fdt;
-static int config_node;
+ char *p = strrchr(n, '.');
+ if (p)
+ *p = '\0';
+ else
+ break;
+ }
+ return NULL;
+}
-static bdk_config_info_t config_info[__BDK_CONFIG_END] = {
+/**
+ * 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, ...)
+{
+ char name[64];
+ size_t count;
+ int64_t tmp;
+
+ assert(cfg_item < __BDK_CONFIG_END);
+
+ /* Make sure the correct access function was called */
+ assert(config_info[cfg_item].ctype == BDK_CONFIG_TYPE_INT);
+
+ if (!config_fdt)
+ return config_info[cfg_item].default_value;
+
+ 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);
+ if (!val)
+ return config_info[cfg_item].default_value;
+
+#if 0
+ if ((val[0] == '0') && (val[1] == 'x'))
+ count = sscanf(val + 2, "%lx", &tmp);
+ else
+ count = sscanf(val, "%li", &tmp);
+#endif
+
+ if ((val[0] == '0') && (val[1] == 'x'))
+ count = str_to_hex(val + 2, &tmp);
+ else
+ count = str_to_int(val, &tmp);
+ if (count == 1) {
+ if ((tmp < config_info[cfg_item].min_value) ||
+ (tmp > config_info[cfg_item].max_value)) {
+ printk(BIOS_WARNING, "Out of range for %s = %s, using "
+ "default\n", name, val);
+ return config_info[cfg_item].default_value;
+ }
+ return tmp;
+ }
+
+ printk(BIOS_WARNING, "Failed to parse %s = %s, using default\n",
+ name, val);
+ return config_info[cfg_item].default_value;
+}
+
+/**
+ * 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, ...)
+{
+ char name[64], val[32];
+
+ assert(cfg_item < __BDK_CONFIG_END);
+
+ /* Make sure the correct access function was called */
+ assert(config_info[cfg_item].ctype == BDK_CONFIG_TYPE_INT);
+
+ if (!config_fdt)
+ return;
+
+ va_list args;
+ va_start(args, cfg_item);
+ vsnprintf(name, sizeof(name)-1, config_info[cfg_item].format, args);
+ va_end(args);
+
+ snprintf(val, sizeof(val), "0x%016llx", value);
+ set_value(name, val);
+}
+
+/**
+ * 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, ...)
+{
+ char name[64];
+
+ /* Make sure the correct access function was called */
+ assert(config_info[cfg_item].ctype == BDK_CONFIG_TYPE_STR);
+
+ if (!config_fdt)
+ return (const char *)config_info[cfg_item].default_value;
+
+ 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);
+ if (val)
+ printk(BIOS_WARNING, "%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);
+ if (val)
+ return val;
+ else
+ return (const char *)config_info[cfg_item].default_value;
+}
+
+bdk_config_info_t config_info[] = {
/* Board manufacturing data */
[BDK_CONFIG_BOARD_MODEL] = {
.format = "BOARD-MODEL", /* String, No parameters */
@@ -251,11 +435,11 @@ static bdk_config_info_t config_info[__BDK_CONFIG_END] = {
.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,
+ .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 */
@@ -264,6 +448,13 @@ static bdk_config_info_t config_info[__BDK_CONFIG_END] = {
.min_value = -1,
.max_value = 8191,
},
+ [BDK_CONFIG_PCIE_SKIP_LINK_TRAIN] = {
+ .format = "PCIE-SKIP-LINK-TRAIN.N%d.PORT%d", /* Parameters: Node, Port */
+ .ctype = BDK_CONFIG_TYPE_INT,
+ .default_value = 0, /* Define which physical slot we connect to on the board */
+ .min_value = 0,
+ .max_value = 1,
+ },
[BDK_CONFIG_PCIE_FLASH] = {
.format = "PCIE-FLASH.N%d.PORT%d", /* Parameters: Node, Port */
.ctype = BDK_CONFIG_TYPE_STR_LIST,
@@ -361,7 +552,6 @@ static bdk_config_info_t config_info[__BDK_CONFIG_END] = {
.min_value = -1,
.max_value = 40,
},
-
/* DRAM configuration options */
[BDK_CONFIG_DDR_SPEED] = {
.format = "DDR-SPEED.N%d", /* Parameters: Node */
@@ -862,1085 +1052,3 @@ static bdk_config_info_t config_info[__BDK_CONFIG_END] = {
},
};
-/**
- * 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-ecam-io.c b/src/vendorcode/cavium/bdk/libbdk-hal/bdk-ecam-io.c
new file mode 100644
index 0000000000..8120820626
--- /dev/null
+++ b/src/vendorcode/cavium/bdk/libbdk-hal/bdk-ecam-io.c
@@ -0,0 +1,373 @@
+/***********************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-ecam.h"
+#include "libbdk-arch/bdk-csrs-gser.h"
+#include "libbdk-arch/bdk-csrs-pccpf.h"
+#include "libbdk-arch/bdk-csrs-pem.h"
+#include "libbdk-hal/device/bdk-device.h"
+#include "libbdk-hal/bdk-ecam.h"
+
+#if 1 /* Support CN88XX pass 1.0 */
+/*******************************************************************
+ *******************************************************************
+ These functions are related to CN88XX pass 1.0 errata and do not
+ apply to any other chip
+ *******************************************************************
+ *******************************************************************/
+
+/**
+ * Errata (ECAM-22630) ECAM function accesses can fault
+ * For some errata workaround we need a check to tell if a ECAM access is to a
+ * valid intenral device. This function decodes a pcc_dev_con_e enumeration and
+ * checks if the supplied arguments match it. This should only
+ * ever be called on CN88XX pass 1.0.
+ *
+ * @param ecam ECAM to check
+ * @param bus ECAM bus number
+ * @param dev Device to check
+ * @param fn sub function of device
+ * @param dev_con Enumeration to match against
+ *
+ * @return Non zero if the device matches
+ */
+static int is_internal_cn88xxp1_0(const bdk_device_t *device, int dev_con)
+{
+ union bdk_pcc_dev_con_s d = { .u = dev_con };
+ return (d.cn8.ecam == device->ecam) && (d.s.bus == device->bus) && (d.s.func == ((device->dev<<3)|device->func));
+}
+
+/**
+ * Errata (ECAM-22630) ECAM function accesses can fault
+ * This is a companion to the function above to determine if the ECAM device is
+ * any of the valid internal devices. This should only ever be
+ * called on CN88XX pass 1.0.
+ *
+ * @param ecam ECAM to check
+ * @param bus ECAM bus number
+ * @param dev Device to check
+ * @param fn sub function of device
+ *
+ * @return Non zero if the device matches
+ */
+static int is_any_internal_cn88xxp1_0(const bdk_device_t *device)
+{
+ /* Errata (ECAM-22630) ECAM function accesses can fault
+ CN88XXP1.0: The ECAM has a bug where accessing a non-existent
+ device causes an exception. This is a list of all valid devices
+ for CN88XX pass 1.0 */
+ static const uint32_t INTERNAL_DEVICES_CN88XXP1_0[] = {
+ BDK_PCC_DEV_CON_E_BGXX(0),
+ BDK_PCC_DEV_CON_E_BGXX(1),
+ BDK_PCC_DEV_CON_E_DAP,
+ BDK_PCC_DEV_CON_E_DFA,
+ BDK_PCC_DEV_CON_E_FUSF,
+ BDK_PCC_DEV_CON_E_GIC_CN8,
+ BDK_PCC_DEV_CON_E_GPIO_CN8,
+ BDK_PCC_DEV_CON_E_GSERX(0),
+ BDK_PCC_DEV_CON_E_GSERX(1),
+ BDK_PCC_DEV_CON_E_GSERX(10),
+ BDK_PCC_DEV_CON_E_GSERX(11),
+ BDK_PCC_DEV_CON_E_GSERX(12),
+ BDK_PCC_DEV_CON_E_GSERX(13),
+ BDK_PCC_DEV_CON_E_GSERX(2),
+ BDK_PCC_DEV_CON_E_GSERX(3),
+ BDK_PCC_DEV_CON_E_GSERX(4),
+ BDK_PCC_DEV_CON_E_GSERX(5),
+ BDK_PCC_DEV_CON_E_GSERX(6),
+ BDK_PCC_DEV_CON_E_GSERX(7),
+ BDK_PCC_DEV_CON_E_GSERX(8),
+ BDK_PCC_DEV_CON_E_GSERX(9),
+ BDK_PCC_DEV_CON_E_GTI_CN8,
+ BDK_PCC_DEV_CON_E_IOBNX(0),
+ BDK_PCC_DEV_CON_E_IOBNX(1),
+ BDK_PCC_DEV_CON_E_KEY,
+ BDK_PCC_DEV_CON_E_L2C,
+ BDK_PCC_DEV_CON_E_L2C_CBCX(0),
+ BDK_PCC_DEV_CON_E_L2C_CBCX(1),
+ BDK_PCC_DEV_CON_E_L2C_CBCX(2),
+ BDK_PCC_DEV_CON_E_L2C_CBCX(3),
+ BDK_PCC_DEV_CON_E_L2C_MCIX(0),
+ BDK_PCC_DEV_CON_E_L2C_MCIX(1),
+ BDK_PCC_DEV_CON_E_L2C_MCIX(2),
+ BDK_PCC_DEV_CON_E_L2C_MCIX(3),
+ BDK_PCC_DEV_CON_E_L2C_TADX(0),
+ BDK_PCC_DEV_CON_E_L2C_TADX(1),
+ BDK_PCC_DEV_CON_E_L2C_TADX(2),
+ BDK_PCC_DEV_CON_E_L2C_TADX(3),
+ BDK_PCC_DEV_CON_E_L2C_TADX(4),
+ BDK_PCC_DEV_CON_E_L2C_TADX(5),
+ BDK_PCC_DEV_CON_E_L2C_TADX(6),
+ BDK_PCC_DEV_CON_E_L2C_TADX(7),
+ BDK_PCC_DEV_CON_E_LMCX(0),
+ BDK_PCC_DEV_CON_E_LMCX(1),
+ BDK_PCC_DEV_CON_E_LMCX(2),
+ BDK_PCC_DEV_CON_E_LMCX(3),
+ BDK_PCC_DEV_CON_E_MIO_BOOT,
+ BDK_PCC_DEV_CON_E_MIO_EMM,
+ BDK_PCC_DEV_CON_E_MIO_FUS,
+ BDK_PCC_DEV_CON_E_MIO_PTP,
+ BDK_PCC_DEV_CON_E_MIO_TWSX(0),
+ BDK_PCC_DEV_CON_E_MIO_TWSX(1),
+ BDK_PCC_DEV_CON_E_MIO_TWSX(2),
+ BDK_PCC_DEV_CON_E_MIO_TWSX(3),
+ BDK_PCC_DEV_CON_E_MIO_TWSX(4),
+ BDK_PCC_DEV_CON_E_MIO_TWSX(5),
+ BDK_PCC_DEV_CON_E_MPI,
+ BDK_PCC_DEV_CON_E_MRML,
+ BDK_PCC_DEV_CON_E_NCSI,
+ BDK_PCC_DEV_CON_E_NIC_CN88XX,
+ BDK_PCC_DEV_CON_E_OCLAX_CN8(0),
+ BDK_PCC_DEV_CON_E_OCLAX_CN8(1),
+ BDK_PCC_DEV_CON_E_OCLAX_CN8(2),
+ BDK_PCC_DEV_CON_E_OCLAX_CN8(3),
+ BDK_PCC_DEV_CON_E_OCLAX_CN8(4),
+ BDK_PCC_DEV_CON_E_OCX,
+ BDK_PCC_DEV_CON_E_PCCBR_DFA,
+ BDK_PCC_DEV_CON_E_PCCBR_MRML,
+ BDK_PCC_DEV_CON_E_PCCBR_NIC_CN88XX,
+ BDK_PCC_DEV_CON_E_PCCBR_RAD_CN88XX,
+ BDK_PCC_DEV_CON_E_PCCBR_ZIP_CN88XX,
+ BDK_PCC_DEV_CON_E_PCIERC0_CN88XX,
+ BDK_PCC_DEV_CON_E_PCIERC1_CN88XX,
+ BDK_PCC_DEV_CON_E_PCIERC2_CN88XX,
+ BDK_PCC_DEV_CON_E_PCIERC3_CN88XX,
+ BDK_PCC_DEV_CON_E_PCIERC4,
+ BDK_PCC_DEV_CON_E_PCIERC5,
+ BDK_PCC_DEV_CON_E_PEMX(0),
+ BDK_PCC_DEV_CON_E_PEMX(1),
+ BDK_PCC_DEV_CON_E_PEMX(2),
+ BDK_PCC_DEV_CON_E_PEMX(3),
+ BDK_PCC_DEV_CON_E_PEMX(4),
+ BDK_PCC_DEV_CON_E_PEMX(5),
+ BDK_PCC_DEV_CON_E_RAD_CN88XX,
+ BDK_PCC_DEV_CON_E_RNM_CN88XX,
+ BDK_PCC_DEV_CON_E_RST,
+ BDK_PCC_DEV_CON_E_SATA0_CN88XX,
+ BDK_PCC_DEV_CON_E_SATA1_CN88XX,
+ BDK_PCC_DEV_CON_E_SATA10,
+ BDK_PCC_DEV_CON_E_SATA11,
+ BDK_PCC_DEV_CON_E_SATA12,
+ BDK_PCC_DEV_CON_E_SATA13,
+ BDK_PCC_DEV_CON_E_SATA14,
+ BDK_PCC_DEV_CON_E_SATA15,
+ BDK_PCC_DEV_CON_E_SATA2,
+ BDK_PCC_DEV_CON_E_SATA3,
+ BDK_PCC_DEV_CON_E_SATA4,
+ BDK_PCC_DEV_CON_E_SATA5,
+ BDK_PCC_DEV_CON_E_SATA6,
+ BDK_PCC_DEV_CON_E_SATA7,
+ BDK_PCC_DEV_CON_E_SATA8,
+ BDK_PCC_DEV_CON_E_SATA9,
+ BDK_PCC_DEV_CON_E_SGP,
+ BDK_PCC_DEV_CON_E_SLI0_CN88XX,
+ BDK_PCC_DEV_CON_E_SLI1,
+ BDK_PCC_DEV_CON_E_SMI,
+ BDK_PCC_DEV_CON_E_SMMU0_CN8,
+ BDK_PCC_DEV_CON_E_SMMU1,
+ BDK_PCC_DEV_CON_E_SMMU2,
+ BDK_PCC_DEV_CON_E_SMMU3,
+ BDK_PCC_DEV_CON_E_TNS,
+ BDK_PCC_DEV_CON_E_UAAX_CN8(0),
+ BDK_PCC_DEV_CON_E_UAAX_CN8(1),
+ BDK_PCC_DEV_CON_E_USBHX(0),
+ BDK_PCC_DEV_CON_E_USBHX(1),
+ BDK_PCC_DEV_CON_E_VRMX(0),
+ BDK_PCC_DEV_CON_E_VRMX(1),
+ BDK_PCC_DEV_CON_E_ZIP_CN88XX,
+ 0,
+ };
+
+ int loc = 0;
+ while (INTERNAL_DEVICES_CN88XXP1_0[loc])
+ {
+ if (is_internal_cn88xxp1_0(device, INTERNAL_DEVICES_CN88XXP1_0[loc]))
+ return 1;
+ loc++;
+ }
+ return 0;
+}
+
+static int is_accessable_cn88xxp1_0(const bdk_device_t *device)
+{
+ /* Errata (ECAM-22630) ECAM function accesses can fault */
+ /* Skip internal devices that don't exists */
+ if (!is_any_internal_cn88xxp1_0(device))
+ return 0;
+
+ /* Errata (ECAM-23020) PCIERC transactions fault unless PEM is
+ out of reset. The PCIe ports don't work until the PEM is
+ turned on. Check for one of the PCIe ports */
+ int pem = -1;
+ if (is_internal_cn88xxp1_0(device, BDK_PCC_DEV_CON_E_PCIERC0_CN88XX))
+ pem = 0;
+ if (is_internal_cn88xxp1_0(device, BDK_PCC_DEV_CON_E_PCIERC1_CN88XX))
+ pem = 1;
+ if (is_internal_cn88xxp1_0(device, BDK_PCC_DEV_CON_E_PCIERC2_CN88XX))
+ pem = 2;
+ if (is_internal_cn88xxp1_0(device, BDK_PCC_DEV_CON_E_PCIERC3_CN88XX))
+ pem = 3;
+ if (is_internal_cn88xxp1_0(device, BDK_PCC_DEV_CON_E_PCIERC4))
+ pem = 4;
+ if (is_internal_cn88xxp1_0(device, BDK_PCC_DEV_CON_E_PCIERC5))
+ pem = 5;
+ if (pem != -1)
+ {
+ BDK_CSR_INIT(pem_on, device->node, BDK_PEMX_ON(pem));
+ if (!pem_on.s.pemon || !pem_on.s.pemoor)
+ return 0;
+ }
+
+ {
+ /* SATA ports should be hidden if they aren't configured at the QLM */
+ int qlm = -1;
+ if (is_internal_cn88xxp1_0(device, BDK_PCC_DEV_CON_E_SATA0_CN88XX) ||
+ is_internal_cn88xxp1_0(device, BDK_PCC_DEV_CON_E_SATA1_CN88XX) ||
+ is_internal_cn88xxp1_0(device, BDK_PCC_DEV_CON_E_SATA2) ||
+ is_internal_cn88xxp1_0(device, BDK_PCC_DEV_CON_E_SATA3))
+ qlm = 2;
+ if (is_internal_cn88xxp1_0(device, BDK_PCC_DEV_CON_E_SATA4) ||
+ is_internal_cn88xxp1_0(device, BDK_PCC_DEV_CON_E_SATA5) ||
+ is_internal_cn88xxp1_0(device, BDK_PCC_DEV_CON_E_SATA6) ||
+ is_internal_cn88xxp1_0(device, BDK_PCC_DEV_CON_E_SATA7))
+ qlm = 3;
+ if (is_internal_cn88xxp1_0(device, BDK_PCC_DEV_CON_E_SATA8) ||
+ is_internal_cn88xxp1_0(device, BDK_PCC_DEV_CON_E_SATA9) ||
+ is_internal_cn88xxp1_0(device, BDK_PCC_DEV_CON_E_SATA10) ||
+ is_internal_cn88xxp1_0(device, BDK_PCC_DEV_CON_E_SATA11))
+ qlm = 6;
+ if (is_internal_cn88xxp1_0(device, BDK_PCC_DEV_CON_E_SATA12) ||
+ is_internal_cn88xxp1_0(device, BDK_PCC_DEV_CON_E_SATA13) ||
+ is_internal_cn88xxp1_0(device, BDK_PCC_DEV_CON_E_SATA14) ||
+ is_internal_cn88xxp1_0(device, BDK_PCC_DEV_CON_E_SATA15))
+ qlm = 7;
+ if (qlm != -1)
+ {
+ BDK_CSR_INIT(cfg, device->node, BDK_GSERX_CFG(qlm));
+ if (!cfg.s.sata)
+ return 0;
+ }
+ }
+ return 1;
+}
+
+#endif /* Support CN88XX pass 1.0 */
+
+/**
+ * Build an ECAM config space request address for a device
+ *
+ * @param device Device being accessed
+ * @param reg Register to access
+ *
+ * @return 64bit IO address
+ */
+uint64_t __bdk_ecam_build_address(const bdk_device_t *device, int reg)
+{
+ /* CN88XX pass 1.0 had a plethora of errata related to ECAM access. This
+ checks to make sure we're allowed to access this location based on
+ the various errata */
+ if (CAVIUM_IS_MODEL(CAVIUM_CN88XX_PASS1_0) && !is_accessable_cn88xxp1_0(device))
+ return 0;
+
+ if (CAVIUM_IS_MODEL(CAVIUM_CN8XXX))
+ {
+ /* Build the address */
+ union bdk_ecam_cfg_addr_s address;
+ address.u = BDK_ECAM_BAR_E_ECAMX_PF_BAR2(device->ecam);
+ address.s.node = device->node;
+ address.s.bus = device->bus;
+ address.s.func = device->dev << 3 | device->func;
+ address.s.addr = reg;
+ return address.u;
+ }
+ else
+ {
+ /* Build the address. The architects decided to make it different
+ from CN8XXX for no obvious reason */
+ union bdk_ecam_cfg_addr_s address;
+ address.u = BDK_ECAM_BAR_E_ECAMX_PF_BAR2(0);
+ address.s.node = device->node;
+ address.s.dmn = device->ecam;
+ address.s.bus = device->bus;
+ address.s.func = device->dev << 3 | device->func;
+ address.s.addr = reg;
+ return address.u;
+ }
+}
+
+/**
+ * Read from an ECAM
+ *
+ * @param device Device to read from
+ * @param reg Register to read
+ *
+ * @return Result of the read of -1 on failure
+ */
+uint32_t bdk_ecam_read32(const bdk_device_t *device, int reg)
+{
+ uint64_t address = __bdk_ecam_build_address(device, reg);
+ uint32_t result;
+ if (address)
+ result = bdk_le32_to_cpu(bdk_read64_uint32(address));
+ else
+ result = 0xffffffff;
+
+ /* Errata ECAM-22630: CN88XX pass 1.x, except pass 1.0, will return zero
+ for non-existent devices instead of ones. We look for this special case
+ for 32bit reads for reg=0 so we can scan device properly */
+ if (CAVIUM_IS_MODEL(CAVIUM_CN88XX_PASS1_X) && (reg == 0) && (result == 0))
+ result = 0xffffffff;
+
+ return result;
+}
+
+/**
+ * Write to an ECAM register
+ *
+ * @param device Device to write to
+ * @param reg Register to write
+ * @param value Value to write
+ */
+void bdk_ecam_write32(const bdk_device_t *device, int reg, uint32_t value)
+{
+ uint64_t address = __bdk_ecam_build_address(device, reg);
+ if (address)
+ bdk_write64_uint32(address, bdk_cpu_to_le32(value));
+}
+
diff --git a/src/vendorcode/cavium/bdk/libbdk-hal/bdk-ecam.c b/src/vendorcode/cavium/bdk/libbdk-hal/bdk-ecam.c
new file mode 100644
index 0000000000..f79eb587f4
--- /dev/null
+++ b/src/vendorcode/cavium/bdk/libbdk-hal/bdk-ecam.c
@@ -0,0 +1,216 @@
+/***********************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 <string.h>
+#include "libbdk-arch/bdk-csrs-ecam.h"
+#include "libbdk-arch/bdk-csrs-pccbr.h"
+#include "libbdk-arch/bdk-csrs-pccpf.h"
+#include "libbdk-arch/bdk-csrs-rvu.h"
+#include "libbdk-hal/device/bdk-device.h"
+#include "libbdk-hal/bdk-ecam.h"
+
+/* This code is an optional part of the BDK. It is only linked in
+ if BDK_REQUIRE() needs it */
+BDK_REQUIRE_DEFINE(ECAM);
+
+/**
+ * Walk an ECAM finding all internal devices. Each internal
+ * device is then added to the list of device maintained by
+ * bdk-device.
+ *
+ * @param node Node to walk
+ * @param ecam Ecam to walk
+ * @param bus Zero on first call. Will be non-zero when sub busses are walked
+ */
+static void ecam_walk_internal_bus(bdk_node_t node, int ecam, int bus)
+{
+ /* Create a fake bdk-device to pass around until we create the
+ real device */
+ bdk_device_t device;
+ memset(&device, 0, sizeof(device));
+ device.node = node;
+ device.ecam = ecam;
+ device.bus = bus;
+
+ /* Scan all possible device IDs on the bus */
+ for (int dev = 0; dev < 32; dev++)
+ {
+ /* Update the current scan location */
+ device.dev = dev;
+ device.func = 0;
+
+ uint32_t device_id = bdk_ecam_read32(&device, BDK_PCCPF_XXX_ID);
+
+ /* Only add devices that exist. Our internal devices can have function
+ zero missing. The all ones we get back matches the multi-function
+ check, but not a bridge. This means the later code works fine */
+ if (device_id != (uint32_t)-1)
+ bdk_device_add(device.node, device.ecam, device.bus, device.dev, device.func);
+
+ /* Check for Multi function and Bridge devices */
+ BDK_CSR_DEFINE(clsize, BDK_PCCPF_XXX_CLSIZE);
+ clsize.u = bdk_ecam_read32(&device, BDK_PCCPF_XXX_CLSIZE);
+ int ismultifunction = (clsize.s.hdrtype & 0x80);
+ int isbridge = (clsize.s.hdrtype & 0x7f) == 1;
+
+ if (ismultifunction)
+ {
+ /* Scan for other functions on multifunction devices */
+ for (int func = 1; func < 8; func++)
+ {
+ /* Check if we're past all functions */
+ device.func = func;
+ device_id = bdk_ecam_read32(&device, BDK_PCCPF_XXX_ID);
+ if (device_id != (uint32_t)-1)
+ bdk_device_add(device.node, device.ecam, device.bus, device.dev, device.func);
+ }
+ device.func = 0;
+ }
+ if (isbridge)
+ {
+ /* Internal bus numbers are hard coded. Read the bus ID */
+ bdk_pccbr_xxx_bus_t ibus;
+ ibus.u = bdk_ecam_read32(&device, BDK_PCCBR_XXX_BUS);
+ /* Asim used to have a bug where bus number were zero, report errors
+ for those */
+ if (ibus.s.sbnum == 0)
+ {
+ bdk_error("N%d:E%d:%d:%d.%d: Secondary bus number is zero\n",
+ device.node, device.ecam, device.bus, device.dev, device.func);
+ }
+ /* Real PCIe external device use high bus numbers, so skip them */
+ else if (ibus.s.sbnum < 16)
+ {
+ ecam_walk_internal_bus(node, ecam, ibus.s.sbnum);
+ }
+ }
+ }
+}
+
+/**
+ * Return the number of internal ECAMS on a node.
+ *
+ * @param node Node to query
+ *
+ * @return Number of ECAMs available
+ */
+int bdk_ecam_get_num(bdk_node_t node)
+{
+ /* CN88XX lacks the ECAM_CONST for finding the number of ECAMs */
+ if (CAVIUM_IS_MODEL(CAVIUM_CN88XX))
+ return 4;
+ else if (CAVIUM_IS_MODEL(CAVIUM_CN93XX))
+ return 3; /* Map ECAMs to the first 3 domains */
+ else
+ {
+ BDK_CSR_INIT(ecam_const, node, BDK_ECAMX_CONST(0));
+ if (ecam_const.s.ecams == 0)
+ {
+ bdk_error("N%d.ECAM: Number of ecams incorrect in ECAMX_CONST\n", node);
+ return 1;
+ }
+ return ecam_const.s.ecams;
+ }
+}
+
+/**
+ * Initialize RVU functions for use by the BDK. This doesn't setup the hardware
+ * behind RVU, juse allows register access to it. The BDK uses a static RVU
+ * configuration where everything is accessable from RVU PF0.
+ *
+ * @param node Node to initialize
+ *
+ * @return Zero on success, negative on failure
+ */
+static int __bdk_ecam_rvu_init(bdk_node_t node)
+{
+ const int rvu_pf = 0;
+ /* Enable PF access to all blocks */
+ BDK_CSR_MODIFY(c, node, BDK_RVU_PRIV_PFX_CPTX_CFG(rvu_pf, 0),
+ c.s.num_lfs = 1); // FIXME: How many LFs?
+ BDK_CSR_MODIFY(c, node, BDK_RVU_PRIV_PFX_INT_CFG(rvu_pf),
+ c.s.msix_offset = 0);
+ BDK_CSR_MODIFY(c, node, BDK_RVU_PRIV_PFX_MSIX_CFG(rvu_pf),
+ c.s.pf_msixt_offset = 0;
+ c.s.pf_msixt_sizem1 = 0;
+ c.s.vf_msixt_offset = 0;
+ c.s.vf_msixt_sizem1 = 0);
+ BDK_CSR_MODIFY(c, node, BDK_RVU_PRIV_PFX_NIXX_CFG(rvu_pf, 0),
+ c.s.has_lf = 1);
+ BDK_CSR_MODIFY(c, node, BDK_RVU_PRIV_PFX_NPA_CFG(rvu_pf),
+ c.s.has_lf = 1);
+ BDK_CSR_MODIFY(c, node, BDK_RVU_PRIV_PFX_SSO_CFG(rvu_pf),
+ c.s.num_lfs = 1); // FIXME: How many LFs?
+ BDK_CSR_MODIFY(c, node, BDK_RVU_PRIV_PFX_SSOW_CFG(rvu_pf),
+ c.s.num_lfs = 1); // FIXME: How many LFs?
+ BDK_CSR_MODIFY(c, node, BDK_RVU_PRIV_PFX_TIM_CFG(rvu_pf),
+ c.s.num_lfs = 1); // FIXME: How many LFs?
+ /* Enable RVU with full access */
+ BDK_CSR_MODIFY(c, node, BDK_RVU_PRIV_PFX_CFG(rvu_pf),
+ c.s.me_flr_ena = 1;
+ c.s.af_ena = 1;
+ c.s.ena = 1;
+ c.s.nvf = 0;
+ c.s.first_hwvf = 0);
+ return 0;
+}
+
+/**
+ * Scan all ECAMs for devices and add them to bdk-device
+ *
+ * @param node Node to scan
+ *
+ * @return Zero on success, negative on failure
+ */
+int bdk_ecam_scan_all(bdk_node_t node)
+{
+ /* RVU must be setup before we scan the bus otherwise it doesn't
+ show up */
+ if (CAVIUM_IS_MODEL(CAVIUM_CN9XXX))
+ __bdk_ecam_rvu_init(node);
+
+ int num_ecams = bdk_ecam_get_num(node);
+ for (int ecam = 0; ecam < num_ecams; ecam++)
+ ecam_walk_internal_bus(node, ecam, 0);
+
+ bdk_device_init();
+
+ return 0;
+}
+
diff --git a/src/vendorcode/cavium/bdk/libbdk-hal/bdk-gpio.c b/src/vendorcode/cavium/bdk/libbdk-hal/bdk-gpio.c
index 55f0dbf3f2..986f68fac3 100644
--- a/src/vendorcode/cavium/bdk/libbdk-hal/bdk-gpio.c
+++ b/src/vendorcode/cavium/bdk/libbdk-hal/bdk-gpio.c
@@ -38,6 +38,7 @@
***********************license end**************************************/
#include <bdk.h>
#include "libbdk-arch/bdk-csrs-gpio.h"
+#include "libbdk-hal/bdk-gpio.h"
/* This code is an optional part of the BDK. It is only linked in
if BDK_REQUIRE() needs it */
diff --git a/src/vendorcode/cavium/bdk/libbdk-hal/bdk-l2c.c b/src/vendorcode/cavium/bdk/libbdk-hal/bdk-l2c.c
index b1e2a88ce1..6c163da2d4 100644
--- a/src/vendorcode/cavium/bdk/libbdk-hal/bdk-l2c.c
+++ b/src/vendorcode/cavium/bdk/libbdk-hal/bdk-l2c.c
@@ -41,6 +41,8 @@
#include "libbdk-arch/bdk-csrs-l2c.h"
#include "libbdk-arch/bdk-csrs-l2c_cbc.h"
#include "libbdk-arch/bdk-csrs-mio_fus.h"
+#include "libbdk-hal/bdk-l2c.h"
+#include "libbdk-hal/bdk-utils.h"
typedef struct
{
@@ -51,56 +53,6 @@ typedef struct
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;
@@ -120,82 +72,11 @@ int bdk_l2c_set_hw_way_partition(bdk_node_t node, uint32_t 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;
@@ -254,17 +135,22 @@ int bdk_l2c_get_num_assoc(bdk_node_t 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)
+int bdk_l2c_unlock_mem_region(bdk_node_t node, uint64_t start, uint64_t len)
{
- /* 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;
-}
+ /* 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;
+}
diff --git a/src/vendorcode/cavium/bdk/libbdk-hal/bdk-nic.c b/src/vendorcode/cavium/bdk/libbdk-hal/bdk-nic.c
new file mode 100644
index 0000000000..b6a9384e10
--- /dev/null
+++ b/src/vendorcode/cavium/bdk/libbdk-hal/bdk-nic.c
@@ -0,0 +1,1090 @@
+/***********************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 <malloc.h>
+#include "libbdk-arch/bdk-csrs-nic.h"
+
+#define MAX_MTU 9212
+#define CQ_ENTRIES_QSIZE 0
+#define CQ_ENTRIES (1024 << CQ_ENTRIES_QSIZE)
+#define SQ_ENTRIES_QSIZE 0
+#define SQ_ENTRIES (1024 << SQ_ENTRIES_QSIZE)
+#define RBDR_ENTRIES_QSIZE 0
+#define RBDR_ENTRIES (8192 << RBDR_ENTRIES_QSIZE)
+
+typedef struct
+{
+ /* VNIC related config */
+ bdk_node_t node : 8; /* Node the NIC is on */
+ bdk_nic_type_t ntype : 8; /* They type of device this NIC is connected to */
+ uint8_t nic_vf; /* NIC VF index number (0 - MAX_VNIC-1) */
+ uint8_t sq; /* Send Queue (SQ) inside NIC VF (0-7) */
+ uint8_t cq; /* Complete Queue (CQ) inside NIC VF (0-7) */
+ uint8_t rq; /* Receive Queue (RQ) inside NIC VF (0-7) */
+ uint8_t rbdr; /* Receive Buffer Descriptor Ring (RBDR) inside NIC VF (0-1) */
+ uint8_t bpid; /* Backpressure ID (0-127) */
+ bdk_if_handle_t handle; /* bdk-if handle associated with this NIC */
+
+ /* Transmit */
+ void * sq_base; /* Pointer to the beginning of the SQ in memory */
+ int sq_loc; /* Location where the next send should go */
+ int sq_available; /* Amount of space left in the queue (fuzzy) */
+} nic_t;
+
+typedef struct
+{
+ void *base;
+ int loc;
+} nic_rbdr_state_t;
+
+typedef struct
+{
+ int num_nic_vf;
+ int next_free_nic_vf;
+ int next_free_cpi;
+ int next_free_rssi;
+ int next_free_bpid;
+ nic_t *nic_map[0]; /* Indexed by handle->nic_id */
+} nic_node_state_t;
+
+static nic_node_state_t *global_node_state[BDK_NUMA_MAX_NODES];
+static int global_buffer_size = 0;
+
+/**
+ * Setup a receive Completion Queue (CQ). CQ can be shared across multiple NICs
+ * to save space. This happens if the NIC has "shares_cq" set.
+ *
+ * @param nic NIC to setup
+ *
+ * @return Zero on success, negative on failure
+ */
+static int vnic_setup_cq(nic_t *nic)
+{
+ /* CN88XX pass 1.x had the drop level reset value too low */
+ BDK_CSR_MODIFY(c, nic->node, BDK_NIC_PF_CQM_CFG,
+ c.s.drop_level = 128);
+
+ /* All devices using the same NIC VF use the same CQ */
+ if (nic->handle->index == 0)
+ {
+ BDK_TRACE(NIC, "%s: Setting up CQ(%d, %d)\n", nic->handle->name, nic->nic_vf, nic->cq);
+ /* Note that the completion queue requires 512 byte alignment */
+ void *cq_memory = memalign(512, 512 * CQ_ENTRIES);
+ if (!cq_memory)
+ {
+ bdk_error("%s: Failed to allocate memory for completion queue\n", nic->handle->name);
+ return -1;
+ }
+ /* Configure the completion queue (CQ) */
+ BDK_CSR_WRITE(nic->node, BDK_NIC_QSX_CQX_BASE(nic->nic_vf, nic->cq),
+ bdk_ptr_to_phys(cq_memory));
+ BDK_CSR_MODIFY(c, nic->node, BDK_NIC_QSX_CQX_CFG(nic->nic_vf, nic->cq),
+ c.s.ena = 1;
+ c.s.caching = 1;
+ c.s.qsize = CQ_ENTRIES_QSIZE);
+ }
+
+ /* Configure our vnic to send to the CQ */
+ BDK_CSR_MODIFY(c, nic->node, BDK_NIC_PF_QSX_SQX_CFG(nic->nic_vf, nic->sq),
+ c.s.cq_qs = nic->nic_vf;
+ c.s.cq_idx = nic->cq);
+ return 0;
+}
+
+/**
+ * Add buffers to a receive buffer descriptor ring (RBDR). Note that RBDRs are
+ * shared between NICs using the same CQ.
+ *
+ * @param nic NIC using the RBDR
+ * @param rbdr_free Number of buffers to add
+ */
+static void vnic_fill_receive_buffer(const nic_t *nic, int rbdr_free)
+{
+ int nic_vf = nic->nic_vf;
+ int rbdr = nic->rbdr;
+
+ BDK_CSR_INIT(rbdr_base, nic->node, BDK_NIC_QSX_RBDRX_BASE(nic_vf, rbdr));
+ BDK_CSR_INIT(rbdr_tail, nic->node, BDK_NIC_QSX_RBDRX_TAIL(nic_vf, rbdr));
+ BDK_TRACE(NIC, "%s: In Filling RBDR(%d, %d) base 0x%lx\n", nic->handle->name, nic->nic_vf, nic->rbdr, rbdr_base.u);
+
+ uint64_t *rbdr_ptr = bdk_phys_to_ptr(rbdr_base.u);
+ int loc = rbdr_tail.s.tail_ptr;
+ BDK_TRACE(NIC, "%s: In Filling RBDR(%d, %d) loc %d\n", nic->handle->name, nic->nic_vf, nic->rbdr, loc);
+
+ int added = 0;
+ for (int i = 0; i < rbdr_free; i++)
+ {
+ bdk_if_packet_t packet;
+ if (bdk_if_alloc(&packet, global_buffer_size))
+ {
+ bdk_error("%s: Failed to allocate buffer for RX ring (added %d)\n", nic->handle->name, added);
+ break;
+ }
+ rbdr_ptr[loc] = bdk_cpu_to_le64(packet.packet[0].s.address);
+ BDK_TRACE(NIC, "%s: In Filling RBDR(%d, %d) loc %d = 0x%lx\n", nic->handle->name, nic->nic_vf, nic->rbdr, loc, rbdr_ptr[loc]);
+ loc++;
+ loc &= RBDR_ENTRIES - 1;
+ added++;
+ }
+ BDK_WMB;
+ BDK_CSR_WRITE(nic->node, BDK_NIC_QSX_RBDRX_DOOR(nic_vf, rbdr), added);
+ BDK_TRACE(NIC, "%s: In Filling RBDR(%d, %d) added %d\n", nic->handle->name, nic->nic_vf, nic->rbdr, added);
+}
+
+/**
+ * Setup a receive buffer descriptor ring (RBDR). Note that NIC share the RBDR if
+ * "share_cq" is set.
+ *
+ * @param nic NIC to setup RBDR for
+ *
+ * @return Zero on success, negative on failure
+ */
+static int vnic_setup_rbdr(nic_t *nic)
+{
+ bool do_fill;
+
+ /* All devices using the same NIC VF use the same RBDRs. Don't fill them
+ for and ports except the first */
+ if (nic->handle->index)
+ {
+ do_fill = false;
+ }
+ else
+ {
+ BDK_TRACE(NIC, "%s: Setting up RBDR(%d, %d)\n", nic->handle->name, nic->nic_vf, nic->rbdr);
+ void *rbdr_base = memalign(BDK_CACHE_LINE_SIZE, 8 * RBDR_ENTRIES);
+ if (!rbdr_base)
+ {
+ bdk_error("%s: Failed to allocate memory for RBDR\n", nic->handle->name);
+ return -1;
+ }
+ /* Configure the receive buffer ring (RBDR) */
+ BDK_CSR_WRITE(nic->node, BDK_NIC_QSX_RBDRX_BASE(nic->nic_vf, nic->rbdr),
+ bdk_ptr_to_phys(rbdr_base));
+ BDK_CSR_MODIFY(c, nic->node, BDK_NIC_QSX_RBDRX_CFG(nic->nic_vf, nic->rbdr),
+ c.s.ena = 1;
+ c.s.ldwb = BDK_USE_DWB;
+ c.s.qsize = RBDR_ENTRIES_QSIZE;
+ c.s.lines = global_buffer_size / BDK_CACHE_LINE_SIZE);
+ do_fill = true;
+ }
+
+ BDK_TRACE(NIC, "%s: Setting up RQ(%d, %d)\n", nic->handle->name, nic->nic_vf, nic->rq);
+ /* Configure our vnic to use the RBDR */
+ /* Connect this RQ to the RBDR. Both the first and next buffers come from
+ the same RBDR */
+ BDK_CSR_MODIFY(c, nic->node, BDK_NIC_PF_QSX_RQX_CFG(nic->nic_vf, nic->rq),
+ c.s.caching = 1; /* Allocate to L2 */
+ c.s.cq_qs = nic->nic_vf;
+ c.s.cq_idx = nic->cq;
+ c.s.rbdr_cont_qs = nic->nic_vf;
+ c.s.rbdr_cont_idx = nic->rbdr;
+ c.s.rbdr_strt_qs = nic->nic_vf;
+ c.s.rbdr_strt_idx = nic->rbdr);
+ /* NIC_PF_CQM_CFG is configure to drop everything if the CQ has 128 or
+ less entries available. Start backpressure when we have 256 or less */
+ int cq_bp = 256;
+ int rbdr_bp = 256;
+ BDK_CSR_MODIFY(c, nic->node, BDK_NIC_PF_QSX_RQX_BP_CFG(nic->nic_vf, nic->rq),
+ c.s.rbdr_bp_ena = 1;
+ c.s.cq_bp_ena = 1;
+ c.s.rbdr_bp = rbdr_bp * 256 / RBDR_ENTRIES; /* Zero means no buffers, 256 means lots available */
+ c.s.cq_bp = cq_bp * 256 / CQ_ENTRIES; /* Zero means full, 256 means idle */
+ c.s.bpid = nic->bpid);
+ /* Errata (NIC-21269) Limited NIC receive scenario verification */
+ /* RED drop set with pass=drop, so no statistical dropping */
+ BDK_CSR_MODIFY(c, nic->node, BDK_NIC_PF_QSX_RQX_DROP_CFG(nic->nic_vf, nic->rq),
+ c.s.rbdr_red = 0;
+ c.s.cq_red = 0;
+ c.s.rbdr_pass = 0; /* Zero means no buffers, 256 means lots available */
+ c.s.rbdr_drop = 0;
+ c.s.cq_pass = 0; /* Zero means full, 256 means idle */
+ c.s.cq_drop = 0);
+
+ if (do_fill)
+ {
+ BDK_TRACE(NIC, "%s: Filling RBDR(%d, %d)\n", nic->handle->name, nic->nic_vf, nic->rbdr);
+ /* We probably don't have enough space to completely fill the RBDR. Use
+ 1/8 of the buffers available */
+ int fill_num = bdk_config_get_int(BDK_CONFIG_NUM_PACKET_BUFFERS) / 8;
+ if (CAVIUM_IS_MODEL(CAVIUM_CN83XX)) fill_num = fill_num/3; /* CN83XX has more nics */
+ /* Note that RBDR must leave one spot empty */
+ if (fill_num > RBDR_ENTRIES - 1)
+ fill_num = RBDR_ENTRIES - 1;
+ vnic_fill_receive_buffer(nic, fill_num);
+ }
+
+ return 0;
+}
+
+/**
+ * Setup traffic shapping for a NIC. This put the shappers in passthrough mode
+ * where no shapping is applied.
+ *
+ * @param nic NIC to configure shaping for
+ *
+ * @return Zero on success, negative on failure
+ */
+static int vnic_setup_tx_shaping(nic_t *nic)
+{
+ int tl1_index = -1;
+ int tl2_index = -1;
+ int tl3_index = -1;
+ int tl4_index = -1;
+ int nic_chan_e = -1;
+
+ BDK_TRACE(NIC, "%s: Setting up shaping(%d, %d)\n", nic->handle->name, nic->nic_vf, nic->sq);
+
+ if (CAVIUM_IS_MODEL(CAVIUM_CN88XX))
+ {
+ /* TL1 feeds the DMA engines. One for each BGX */
+ tl1_index = nic->handle->interface;
+ /* TL2 feeds TL1 based on the top/bottom half. Use an independent TL1
+ entry for each BGX port */
+ tl2_index = tl1_index * 32 + nic->handle->index;
+ /* Each block of 4 TL3 feed TL2 */
+ tl3_index = tl2_index * 4;
+ /* Each block of 4 TL4 feed TL3 */
+ tl4_index = tl3_index * 4;
+ nic_chan_e = BDK_NIC_CHAN_E_BGXX_PORTX_CHX(nic->handle->interface, nic->handle->index, 0/*channel*/);
+ }
+ else if (CAVIUM_IS_MODEL(CAVIUM_CN83XX))
+ {
+ switch (nic->ntype)
+ {
+ case BDK_NIC_TYPE_BGX:
+ tl1_index = BDK_NIC_LMAC_E_BGXX_LMACX(nic->handle->interface, nic->handle->index);
+ nic_chan_e = 0 ; /* Channel is lmac-relative */
+ break;
+ case BDK_NIC_TYPE_LBK:
+ tl1_index = BDK_NIC_LMAC_E_LBKX_CN83XX((nic->handle->interface == 3) ? 1 : 0);
+ nic_chan_e = nic->handle->index; /* Channel is lmac-relative */
+ break;
+ default:
+ bdk_error("%s: Unsupported NIC TYPE %d\n", nic->handle->name, nic->ntype);
+ return -1;
+ }
+ /* TL1 index by NIC_LMAC_E */
+ /* Set in above switch statement */
+ /* TL2 index is software defined, make it the same as TL1 for straight through */
+ tl2_index = tl1_index;
+ /* Each block of 4 TL3 feed TL2. This assumes there are never more than 4 ports per interface */
+ tl3_index = tl2_index * 4 + nic->handle->index;
+ /* TL4 index is the same as TL3, 1:1 hookup */
+ tl4_index = tl3_index;
+ }
+ else if (CAVIUM_IS_MODEL(CAVIUM_CN81XX))
+ {
+ switch (nic->ntype)
+ {
+ case BDK_NIC_TYPE_BGX:
+ tl1_index = BDK_NIC_LMAC_E_BGXX_LMACX(nic->handle->interface, nic->handle->index);
+ nic_chan_e = BDK_NIC_CHAN_E_BGXX_LMACX_CHX(nic->handle->interface, nic->handle->index, 0/*channel*/);
+ break;
+ case BDK_NIC_TYPE_RGMII:
+ tl1_index = BDK_NIC_LMAC_E_RGXX_LMACX(nic->handle->interface, nic->handle->index);
+ nic_chan_e = 0; /* Channel is lmac-relative */
+ break;
+ case BDK_NIC_TYPE_LBK:
+ tl1_index = BDK_NIC_LMAC_E_LBKX_CN81XX(nic->handle->interface);
+ nic_chan_e = nic->handle->index; /* Channel is lmac-relative */
+ break;
+ default:
+ bdk_error("%s: Unsupported NIC TYPE %d\n", nic->handle->name, nic->ntype);
+ return -1;
+ }
+ /* TL1 index by NIC_LMAC_E */
+ /* Set in above switch statement */
+ /* TL2 index is software defined, make it the same as TL1 for straight through */
+ tl2_index = tl1_index;
+ /* Each block of 4 TL3 feed TL2. This assumes there are never more than 4 ports per interface */
+ tl3_index = tl2_index * 4 + nic->handle->index;
+ /* TL4 index is the same as TL3, 1:1 hookup */
+ tl4_index = tl3_index;
+ }
+ else
+ {
+ bdk_error("%s: Unsupported chip (NIC shaping)\n", nic->handle->name);
+ return -1;
+ }
+
+ /* Setup TL2 to TL1 mappings */
+ BDK_CSR_MODIFY(c, nic->node, BDK_NIC_PF_TL2X_CFG(tl2_index),
+ c.s.rr_quantum = (MAX_MTU+4) / 4);
+ BDK_CSR_MODIFY(c, nic->node, BDK_NIC_PF_TL2X_PRI(tl2_index),
+ c.s.rr_pri = 0);
+ if (!CAVIUM_IS_MODEL(CAVIUM_CN88XX))
+ {
+ BDK_CSR_MODIFY(c, nic->node, BDK_NIC_PF_TL2X_LMAC(tl2_index),
+ c.s.lmac = tl1_index);
+ }
+
+ /* TL3 feeds Tl2 */
+ BDK_CSR_MODIFY(c, nic->node, BDK_NIC_PF_TL3AX_CFG(tl3_index / 4),
+ c.s.tl3a = tl2_index);
+ BDK_CSR_MODIFY(c, nic->node, BDK_NIC_PF_TL3X_CFG(tl3_index),
+ c.s.rr_quantum = (MAX_MTU+4) / 4);
+ BDK_CSR_MODIFY(c, nic->node, BDK_NIC_PF_TL3X_CHAN(tl3_index),
+ c.s.chan = nic_chan_e);
+
+ /* TL4 feeds TL3 */
+ if (CAVIUM_IS_MODEL(CAVIUM_CN88XX))
+ {
+ BDK_CSR_MODIFY(c, nic->node, BDK_NIC_PF_TL4AX_CFG(tl4_index / 4),
+ c.s.tl4a = tl3_index);
+ }
+ BDK_CSR_MODIFY(c, nic->node, BDK_NIC_PF_TL4X_CFG(tl4_index),
+ c.s.sq_qs = nic->nic_vf;
+ c.s.sq_idx = nic->sq;
+ c.s.rr_quantum = (MAX_MTU+4) / 4);
+
+ /* SQ feeds TL4 */
+ BDK_CSR_MODIFY(c, nic->node, BDK_NIC_PF_QSX_SQX_CFG2(nic->nic_vf, nic->sq),
+ c.s.tl4 = tl4_index);
+
+ return 0;
+}
+
+/**
+ * Free the buffers in a packet to the RBDR used by the port
+ *
+ * @param priv Determines which RBDR is used
+ * @param packet Packet to put in RBDR
+ */
+static void if_free_to_rbdr(bdk_if_packet_t *packet, nic_rbdr_state_t *vnic_rbdr_state)
+{
+ uint64_t *rbdr_ptr = vnic_rbdr_state->base;
+ int loc = vnic_rbdr_state->loc;
+
+ for (int s = 0; s < packet->segments; s++)
+ {
+ /* Make sure we strip off any padding added by the hardware in the address */
+ uint64_t address = packet->packet[s].s.address & -BDK_CACHE_LINE_SIZE;
+ rbdr_ptr[loc] = bdk_cpu_to_le64(address);
+ loc++;
+ loc &= RBDR_ENTRIES - 1;
+ }
+ vnic_rbdr_state->loc = loc;
+}
+
+/**
+ * Process a CQ receive entry
+ *
+ * @param node Node containing the CQ
+ * @param vnic_rbdr_state
+ * Current RBDR state for the RBDR connected to the CQ
+ * @param cq_header CQ header to process
+ * @param use_cqe_rx2
+ * True of the CQ will contain an extended CQE_RX2 header
+ *
+ * @return Returns the amount the RBDR doorbell needs to increment
+ */
+static int if_process_complete_rx(int node, nic_rbdr_state_t *vnic_rbdr_state, const union bdk_nic_cqe_rx_s *cq_header, const union bdk_nic_cqe_rx_s *cq_header_le, bool use_cqe_rx2)
+{
+ nic_node_state_t *node_state = global_node_state[node];
+ int nic_id = cq_header->s.rq_qs * 8 + cq_header->s.rq_idx;
+
+ bdk_if_packet_t packet;
+ packet.length = cq_header->s.len;
+ packet.segments = cq_header->s.rb_cnt;
+ packet.if_handle = node_state->nic_map[nic_id]->handle;
+ /* Combine the errlev and errop into a single 11 bit number. Errop
+ is 8 bits, so errlev will be in the top byte */
+ packet.rx_error = cq_header->s.errlev;
+ packet.rx_error <<= 8;
+ packet.rx_error |= cq_header->s.errop;
+
+ const uint16_t *rb_sizes = (void*)cq_header_le + 24; /* Offset of RBSZ0 */
+ const uint64_t *rb_addresses = (uint64_t*)(cq_header_le+1);
+ /* Update offset if nic_cqe_rx2_s is used */
+ if (use_cqe_rx2)
+ rb_addresses += sizeof(union bdk_nic_cqe_rx2_s) / 8;
+ int segment_length = 0;
+
+ for (int s = 0; s < packet.segments; s++)
+ {
+ uint64_t addr = bdk_le64_to_cpu(rb_addresses[s]);
+ BDK_PREFETCH(bdk_phys_to_ptr(addr), 0);
+ packet.packet[s].u = addr;
+ packet.packet[s].s.size = bdk_le16_to_cpu(rb_sizes[s]);
+ BDK_TRACE(NIC, " Receive segment size %d address 0x%lx\n", packet.packet[s].s.size, addr);
+ segment_length += packet.packet[s].s.size;
+ }
+
+ /* If we ran out of buffer the packet could be truncated */
+ if (segment_length < packet.length)
+ packet.length = segment_length;
+
+ if (bdk_likely(packet.if_handle))
+ {
+ /* Do RX stats in software as it is fast and I don't really trust
+ the hardware. The hardware tends to count packets that are received
+ and dropped in some weird way. Hopefully the hardware counters
+ looking for drops can find these. It is important that they
+ aren't counted as good */
+ packet.if_handle->stats.rx.packets++;
+ packet.if_handle->stats.rx.octets += packet.length;
+ if (packet.if_handle->flags & BDK_IF_FLAGS_HAS_FCS)
+ packet.if_handle->stats.rx.octets += 4;
+ if (packet.rx_error)
+ packet.if_handle->stats.rx.errors++;
+ bdk_if_dispatch_packet(&packet);
+ }
+ else
+ {
+ bdk_error("Unable to determine interface for NIC %d.%d\n", cq_header->s.rq_qs, cq_header->s.rq_idx);
+ }
+
+ if_free_to_rbdr(&packet, vnic_rbdr_state);
+ return packet.segments;
+}
+
+/**
+ * Process all entries in a completion queue (CQ). Note that a CQ is shared
+ * among many ports, so packets will be dispatch for other port handles.
+ *
+ * @param handle Interface handle connected to the CQ
+ *
+ * @return Number of packets received
+ */
+static void if_receive(int unused, void *hand)
+{
+ const nic_t *nic = hand;
+
+ /* Sadly the hardware team decided to change the meaning of NIC_PF_RX_CFG
+ for chips after CN88XX. This stupid spec change was really hard to
+ find */
+ bool use_cqe_rx2 = !CAVIUM_IS_MODEL(CAVIUM_CN88XX);
+
+ /* Figure out which completion queue we're using */
+ int nic_vf = nic->nic_vf;
+ int rbdr = nic->rbdr;
+ int cq = nic->cq;
+
+ BDK_CSR_INIT(cq_base, nic->node, BDK_NIC_QSX_CQX_BASE(nic_vf, cq));
+ const void *cq_ptr = bdk_phys_to_ptr(cq_base.u);
+
+ /* Find the current CQ location */
+ BDK_CSR_INIT(cq_head, nic->node, BDK_NIC_QSX_CQX_HEAD(nic_vf, cq));
+ int loc = cq_head.s.head_ptr;
+
+ /* Store the RBDR data locally to avoid contention */
+ BDK_CSR_INIT(rbdr_base, nic->node, BDK_NIC_QSX_RBDRX_BASE(nic_vf, rbdr));
+ BDK_CSR_INIT(rbdr_tail, nic->node, BDK_NIC_QSX_RBDRX_TAIL(nic_vf, rbdr));
+ nic_rbdr_state_t vnic_rbdr_state;
+ vnic_rbdr_state.base = bdk_phys_to_ptr(rbdr_base.u);
+ vnic_rbdr_state.loc = rbdr_tail.s.tail_ptr;
+
+ BDK_TRACE(NIC, "%s: Receive thread for CQ(%d, %d) started\n", nic->handle->name, nic->nic_vf, nic->cq);
+
+ while (1)
+ {
+ /* Exit immediately if the CQ is empty */
+ BDK_CSR_INIT(cq_status, nic->node, BDK_NIC_QSX_CQX_STATUS(nic_vf, cq));
+ int pending_count = cq_status.s.qcount;
+ if (bdk_likely(!pending_count))
+ {
+ bdk_wait_usec(1);
+ continue;
+ }
+
+ /* Loop through all pending CQs */
+ int rbdr_doorbell = 0;
+ int count = 0;
+ const union bdk_nic_cqe_rx_s *cq_next = cq_ptr + loc * 512;
+ BDK_TRACE(NIC, "%s: Receive thread CQ(%d, %d): %d pending\n", nic->handle->name, nic->nic_vf, nic->cq, pending_count);
+ while (count < pending_count)
+ {
+ const union bdk_nic_cqe_rx_s *cq_header = cq_next;
+ const union bdk_nic_cqe_rx_s *cq_header_le = cq_header;
+#if __BYTE_ORDER == __BIG_ENDIAN
+ union bdk_nic_cqe_rx_s cq_be;
+ for (int i = 0; i < 6; i++)
+ cq_be.u[i] = bdk_le64_to_cpu(cq_header_le->u[i]);
+ cq_header = &cq_be;
+#endif
+ BDK_TRACE(NIC, "%s: Receive HDR[%p] = 0x%lx 0x%lx 0x%lx 0x%lx\n",
+ nic->handle->name, cq_header_le, cq_header->u[0], cq_header->u[1], cq_header->u[2], cq_header->u[3]);
+ loc++;
+ loc &= CQ_ENTRIES - 1;
+ cq_next = cq_ptr + loc * 512;
+ BDK_PREFETCH(cq_next, 0);
+ if (bdk_likely(cq_header->s.cqe_type == BDK_NIC_CQE_TYPE_E_RX))
+ rbdr_doorbell += if_process_complete_rx(nic->node, &vnic_rbdr_state, cq_header, cq_header_le, use_cqe_rx2);
+ else
+ bdk_error("Unsupported CQ header type %d\n", cq_header->s.cqe_type);
+ count++;
+ }
+ /* Ring the RBDR doorbell for all packets */
+ BDK_WMB;
+ BDK_CSR_WRITE(nic->node, BDK_NIC_QSX_RBDRX_DOOR(nic_vf, rbdr), rbdr_doorbell);
+ /* Free all the CQs that we've processed */
+ BDK_CSR_WRITE(nic->node, BDK_NIC_QSX_CQX_DOOR(nic_vf, cq), count);
+ /* Yield before going through more packets. The low core count chips
+ don't have enough cores to dedicate for TX and RX. This forces
+ sharing under load. If there are enough cores, the yield does
+ nothing */
+ bdk_thread_yield();
+ }
+}
+
+/**
+ * Configure NIC for a specific port. This is called for each
+ * port on every interface that connects to NIC.
+ *
+ * @param handle Handle for port to config
+ * @param ntype Type of LMAC this NIC connects to
+ * @param lmac_credits
+ * Size of the LMAC buffer in bytes. Used to configure the number of credits to
+ * setup between the NIC and LMAC
+ *
+ * @return Zero on success, negative on failure
+ */
+int bdk_nic_port_init(bdk_if_handle_t handle, bdk_nic_type_t ntype, int lmac_credits)
+{
+ int nic_chan_idx_e; /* Flow channel for the CPI */
+ bool has_rx_nic = (-1 == handle->pki_channel); /* true when nic rx channel exists - may be BGX or LBK-NIC*/
+ bool has_tx_nic = (-1 == handle->pko_queue); /* true when nic tx channel exists - may be BGX or LBK-NIC*/
+ int nic_intf_e = -1; /* Interface enumeration */
+ int nic_intf_block_e; /* Interface Block ID Enumeration */
+ int nic_lmac_e=-1; /* LMAC enumeration */
+
+ if (global_buffer_size == 0)
+ global_buffer_size = bdk_config_get_int(BDK_CONFIG_PACKET_BUFFER_SIZE);
+
+ if (!has_rx_nic && !has_tx_nic) return 0;
+
+ if (CAVIUM_IS_MODEL(CAVIUM_CN88XX))
+ {
+ /* Flow here is a compressed NIC_CHAN_E enum value. Flow is bit[8] and
+ bit[6:0] from NIC_CHAN_E. This works out as:
+ bit 7: BGX interface number(0-1)
+ bit 6:4: BGX port number(0-3)
+ bit 3:0: BGX channel on a port (0-15) */
+ nic_chan_idx_e = (handle->interface) ? 0x80 : 0x00;
+ nic_chan_idx_e += handle->index * 16;
+ nic_chan_idx_e += 0; /* channel */
+ nic_intf_e = BDK_NIC_INTF_E_BGXX(handle->interface);
+ nic_intf_block_e = BDK_NIC_INTF_BLOCK_E_BGXX_BLOCK(handle->interface);
+ nic_lmac_e = BDK_NIC_LMAC_E_BGXX_LMACX(handle->interface, handle->index);
+ }
+ else if (CAVIUM_IS_MODEL(CAVIUM_CN83XX))
+ {
+ switch (ntype)
+ {
+ case BDK_NIC_TYPE_BGX:
+ nic_chan_idx_e = BDK_NIC_CHAN_IDX_E_BGXX_LMACX_CHX(handle->interface, handle->index, 0/*channel*/);
+ nic_intf_e = BDK_NIC_INTF_E_BGXX(handle->interface);
+ nic_intf_block_e = BDK_NIC_INTF_BLOCK_E_BGXX(handle->interface);
+ nic_lmac_e = BDK_NIC_LMAC_E_BGXX_LMACX(handle->interface, handle->index);
+ break;
+ case BDK_NIC_TYPE_LBK:
+ nic_chan_idx_e = BDK_NIC_CHAN_IDX_E_LBKX_CHX_CN83XX((handle->interface == 3) ? 1 : 0, handle->index);
+ // rx interface
+ if (3 == handle->interface) {
+ nic_intf_e = BDK_NIC_INTF_E_LBKX_CN83XX(1);
+ } else if (2 == handle->interface) {
+ nic_intf_e = BDK_NIC_INTF_E_LBKX_CN83XX(0);
+ }
+ nic_intf_block_e = BDK_NIC_INTF_BLOCK_E_LBKX(handle->interface);
+ // tx interface
+ if (3 == handle->interface) {
+ nic_lmac_e = BDK_NIC_LMAC_E_LBKX_CN83XX(1);
+ } else if (1 == handle->interface) {
+ nic_lmac_e = BDK_NIC_LMAC_E_LBKX_CN83XX(0);
+ }
+ break;
+ default:
+ bdk_error("%s: Unsupported NIC TYPE %d\n", handle->name, ntype);
+ return -1;
+ }
+ }
+ else if (CAVIUM_IS_MODEL(CAVIUM_CN81XX))
+ {
+ switch (ntype)
+ {
+ case BDK_NIC_TYPE_BGX:
+ nic_chan_idx_e = BDK_NIC_CHAN_IDX_E_BGXX_LMACX_CHX(handle->interface, handle->index, 0/*channel*/);
+ nic_intf_e = BDK_NIC_INTF_E_BGXX(handle->interface);
+ nic_intf_block_e = BDK_NIC_INTF_BLOCK_E_BGXX(handle->interface);
+ nic_lmac_e = BDK_NIC_LMAC_E_BGXX_LMACX(handle->interface, handle->index);
+ break;
+ case BDK_NIC_TYPE_RGMII:
+ nic_chan_idx_e = BDK_NIC_CHAN_IDX_E_RGXX_LMACX_CHX(handle->interface, handle->index, 0/*channel*/);
+ nic_intf_e = BDK_NIC_INTF_E_RGXX(handle->index);
+ nic_intf_block_e = BDK_NIC_INTF_BLOCK_E_BGXX(handle->interface + 2);
+ nic_lmac_e = BDK_NIC_LMAC_E_RGXX_LMACX(handle->interface, handle->index);
+ break;
+ case BDK_NIC_TYPE_LBK:
+ nic_chan_idx_e = BDK_NIC_CHAN_IDX_E_LBKX_CHX_CN81XX(handle->interface, handle->index);
+ nic_intf_e = BDK_NIC_INTF_E_LBKX_CN81XX(handle->interface);
+ nic_intf_block_e = BDK_NIC_INTF_BLOCK_E_LBKX(handle->interface);
+ nic_lmac_e = BDK_NIC_LMAC_E_LBKX_CN81XX(handle->interface);
+ break;
+ default:
+ bdk_error("%s: Unsupported NIC TYPE %d\n", handle->name, ntype);
+ return -1;
+ }
+ }
+ else
+ {
+ bdk_error("%s: Unsupported chip (NIC init)\n", handle->name);
+ return -1;
+ }
+
+ /* Make sure the node global state has been allocated */
+ if (global_node_state[handle->node] == NULL)
+ {
+ int num_nic_vf;
+ if (CAVIUM_IS_MODEL(CAVIUM_CN88XX))
+ {
+ /* NIC_PF_CONST1 didn't exist on this chip */
+ num_nic_vf = 128;
+ }
+ else
+ {
+ BDK_CSR_INIT(nic_pf_const1, handle->node, BDK_NIC_PF_CONST1);
+ num_nic_vf = nic_pf_const1.s.vnics;
+ }
+ global_node_state[handle->node] = calloc(1, sizeof(nic_node_state_t) + sizeof(handle) * num_nic_vf * 8);
+ if (global_node_state[handle->node] == NULL)
+ {
+ bdk_error("N%d.NIC: Failed to allocate node state\n", handle->node);
+ return -1;
+ }
+ global_node_state[handle->node]->num_nic_vf = num_nic_vf;
+ }
+ nic_node_state_t *node_state = global_node_state[handle->node];
+
+ /* See if we have a free VF */
+ if (!handle->index && (node_state->next_free_nic_vf >= node_state->num_nic_vf))
+ {
+ bdk_error("N%d.NIC: Ran out of NIC VFs\n", handle->node);
+ return -1;
+ }
+
+ /* VNIC setup requirements
+ The code in this file makes the following assumptions:
+ 1) One RBDR for each CQ. No locking is done on RBDR
+ 2) A CQ can be shared across multiple ports, saving space as the
+ cost of performance.
+ 3) One SQ per physical port, no locking on TX
+ 4) One RQ per physical port, many RQ may share RBDR/CQ
+
+ Current setup without DRAM:
+ 1) One NIC VF is used for an entire interface (BGX, LBK). The variable
+ nic_vf represents the NIC virtual function.
+ 2) SQs are allocated one per port. SQ index equals handle->index
+ 3) RQs are allocated one per port. RQ index equals handle->index
+ 4) One CQ is allcoated per entire interface, using index 0
+ 5) One RBDR is used for the CQ, index 0
+
+ Current setup with DRAM:
+ FIXME: Same as without DRAM. There are not enough RBDR to have
+ independent CQs without locking.
+ */
+ void *sq_memory = NULL;
+ if (has_tx_nic) {
+ sq_memory = memalign(BDK_CACHE_LINE_SIZE, 16 * SQ_ENTRIES);
+ if (!sq_memory)
+ {
+ bdk_error("%s: Unable to allocate queues\n", handle->name);
+ return -1;
+ }
+ }
+ nic_t *nic = calloc(1, sizeof(nic_t));
+ if (!nic)
+ {
+ if (sq_memory) free(sq_memory);
+ bdk_error("%s: Unable to NIC state\n", handle->name);
+ return -1;
+ }
+
+ /* Fill in the various NIC indexes */
+ nic->node = handle->node;
+ nic->ntype = ntype;
+ if (handle->index)
+ nic->nic_vf = node_state->next_free_nic_vf - 1; /* reuse last one */
+ else
+ nic->nic_vf = node_state->next_free_nic_vf++; /* New nic */
+ nic->sq = handle->index;
+ nic->cq = 0;
+ nic->rq = handle->index;
+ nic->rbdr = 0;
+ nic->bpid = node_state->next_free_bpid++;
+ nic->handle = handle;
+ BDK_TRACE(NIC, "%s: Creating NIC(%d, sq=%d, cq=%d, rq=%d, rbdr=%d, bpid=%d)\n",
+ nic->handle->name, nic->nic_vf, nic->sq, nic->cq, nic->rq, nic->rbdr, nic->bpid);
+
+ /* Connect this NIC to the handle */
+ handle->nic_id = nic->nic_vf * 8 + nic->rq;
+ node_state->nic_map[handle->nic_id] = nic;
+
+ /* Enable global BP state updates */
+ BDK_CSR_MODIFY(c, nic->node, BDK_NIC_PF_BP_CFG,
+ c.s.bp_poll_ena = 1;
+ c.s.bp_poll_dly = 3);
+
+ /* Enable interface level backpresure */
+ if (-1 != nic_intf_e) {
+ BDK_CSR_MODIFY(c, nic->node, BDK_NIC_PF_INTFX_BP_CFG(nic_intf_e),
+ c.s.bp_ena = 1;
+ c.s.bp_type = ((nic->ntype == BDK_NIC_TYPE_BGX) ||
+ (nic->ntype == BDK_NIC_TYPE_RGMII)) ? 0 : 1; /* 0=BGX, 1=LBK/TNS */
+ c.s.bp_id = nic_intf_block_e);
+ }
+ if (has_tx_nic) {
+ /* Configure the submit queue (SQ) */
+ nic->sq_base = sq_memory;
+ nic->sq_loc = 0;
+ nic->sq_available = SQ_ENTRIES;
+ BDK_CSR_WRITE(nic->node, BDK_NIC_QSX_SQX_BASE(nic->nic_vf, nic->sq),
+ bdk_ptr_to_phys(sq_memory));
+ BDK_CSR_MODIFY(c, nic->node, BDK_NIC_QSX_SQX_CFG(nic->nic_vf, nic->sq),
+ if (!CAVIUM_IS_MODEL(CAVIUM_CN88XX_PASS1_X))
+ c.s.cq_limit = 1;
+ c.s.ena = 1;
+ c.s.ldwb = BDK_USE_DWB;
+ c.s.qsize = SQ_ENTRIES_QSIZE);
+ }
+ int cpi=0;
+ int rssi=0;
+ if (has_rx_nic) {
+ /* Configure the receive queue (RQ) */
+ BDK_CSR_MODIFY(c, nic->node, BDK_NIC_QSX_RQ_GEN_CFG(nic->nic_vf),
+ c.s.vlan_strip = 0;
+ c.s.len_l4 = 0;
+ c.s.len_l3 = 0;
+ c.s.csum_l4 = 0;
+ c.s.ip6_udp_opt = 0;
+ c.s.splt_hdr_ena = 0;
+ c.s.cq_hdr_copy = 0;
+ c.s.max_tcp_reass = 0;
+ c.s.cq_pkt_size = 0;
+ c.s.later_skip = 0;
+ c.s.first_skip = 0);
+ BDK_CSR_MODIFY(c, nic->node, BDK_NIC_QSX_RQX_CFG(nic->nic_vf, nic->rq),
+ c.s.ena = 1;
+ c.s.tcp_ena = 0);
+
+ cpi = node_state->next_free_cpi++; /* Allocate a new Channel Parse Index (CPI) */
+ rssi = node_state->next_free_rssi++;/* Allocate a new Receive-Side Scaling Index (RSSI) */
+ /* NIC_CHAN_E hard mapped to "flow". Flow chooses the CPI */
+
+ BDK_CSR_MODIFY(c, nic->node, BDK_NIC_PF_CHANX_RX_CFG(nic_chan_idx_e),
+ c.s.cpi_alg = BDK_NIC_CPI_ALG_E_NONE;
+ c.s.cpi_base = cpi);
+ /* Setup backpressure */
+ BDK_CSR_MODIFY(c, nic->node, BDK_NIC_PF_CHANX_RX_BP_CFG(nic_chan_idx_e),
+ c.s.ena = 1;
+ c.s.bpid = nic->bpid);
+ }
+ if ( has_tx_nic) {
+ BDK_CSR_MODIFY(c, nic->node, BDK_NIC_PF_CHANX_TX_CFG(nic_chan_idx_e),
+ c.s.bp_ena = 1);
+ }
+
+ if (has_rx_nic) {
+ /* CPI is the output of the above alogrithm, this is used to lookup the
+ VNIC for receive and RSSI */
+ BDK_CSR_MODIFY(c, nic->node, BDK_NIC_PF_CPIX_CFG(cpi),
+ c.cn88xxp1.vnic = nic->nic_vf; /* TX and RX use the same VNIC */
+ c.cn88xxp1.rss_size = 0; /* RSS hash is disabled */
+ c.s.padd = 0; /* Used if we have multiple channels per port */
+ c.cn88xxp1.rssi_base = rssi); /* Base RSSI */
+
+ if (!CAVIUM_IS_MODEL(CAVIUM_CN88XX_PASS1_X))
+ {
+ /* CN88XX pass 2 moved some fields to a different CSR */
+ BDK_CSR_MODIFY(c, nic->node, BDK_NIC_PF_MPIX_CFG(cpi),
+ c.s.vnic = nic->nic_vf; /* TX and RX use the same VNIC */
+ c.s.rss_size = 0; /* RSS hash is disabled */
+ c.s.rssi_base = rssi); /* Base RSSI */
+ }
+
+ /* The RSSI is used to determine which Receive Queue (RQ) we use */
+ BDK_CSR_MODIFY(c, nic->node, BDK_NIC_PF_RSSIX_RQ(rssi),
+ c.s.rq_qs = nic->nic_vf;
+ c.s.rq_idx = nic->rq);
+ /* Set the min and max packet size. PKND comes from BGX. It is always zero
+ for now */
+ BDK_CSR_MODIFY(c, nic->node, BDK_NIC_PF_PKINDX_CFG(handle->pknd),
+ c.s.lenerr_en = 0;
+ c.s.minlen = 0;
+ c.s.maxlen = 65535);
+ }
+
+ if (CAVIUM_IS_MODEL(CAVIUM_CN88XX))
+ {
+ /* Bypass the TNS */
+ BDK_CSR_MODIFY(c, nic->node, BDK_NIC_PF_INTFX_SEND_CFG(handle->interface),
+ c.s.tns_nonbypass = 0;
+ c.s.block = 0x8 + handle->interface);
+ }
+
+ /* Errata (NIC-21858) If NIC_PF_QS()_CFG ENA is set after RRM enabled...RRM breaks */
+ /* Do global vnic init */
+ BDK_CSR_MODIFY(c, nic->node, BDK_NIC_PF_QSX_CFG(nic->nic_vf),
+ c.s.ena = 1;
+ c.s.vnic = nic->nic_vf);
+
+ if (has_tx_nic && vnic_setup_tx_shaping(nic))
+ return -1;
+
+ /* Completion queue may be used by both tx and rx.
+ ** Define it even if only one of rx/tx is in use
+ */
+ if (vnic_setup_cq(nic))
+ return -1;
+ /* RBDR is defined regardless of rx_nic to avoid possible backpressure */
+ if ( vnic_setup_rbdr(nic))
+ return -1;
+
+ /* Program LMAC credits */
+ if ((has_tx_nic) && (-1 != nic_lmac_e)) {
+ int credit;
+ if ((BDK_NIC_TYPE_LBK == nic->ntype) && CAVIUM_IS_MODEL(CAVIUM_CN83XX) )
+ credit = 512; /* HRM guidance */
+ else
+ credit = (lmac_credits - MAX_MTU) / 16;
+ BDK_CSR_MODIFY(c, nic->node, BDK_NIC_PF_LMACX_CREDIT(nic_lmac_e),
+ c.s.cc_unit_cnt = credit;
+ c.s.cc_packet_cnt = 0x1ff;
+ c.s.cc_enable = 1);
+
+ /* Pad packets to 60 bytes, 15 32bit words (before FCS) */
+ if (nic->ntype != BDK_NIC_TYPE_LBK)
+ BDK_CSR_MODIFY(c, nic->node, BDK_NIC_PF_LMACX_CFG(nic_lmac_e),
+ c.s.min_pkt_size = 15);
+ }
+ /* Create a receive thread if this handle has its own CQ/RBDR */
+ if (handle->index == 0)
+ {
+ /* FIXME
+ * At this time thread monitors both CQ and RBDR and uses it only for receive
+ * Setting up RBDR for tx only nics is wasteful.
+ * When nic_tx in bdk starts using CQ, thread needs to change
+ */
+ if (has_rx_nic && bdk_thread_create(nic->node, 0, if_receive, 0, nic, 0))
+ {
+ bdk_error("%s: Failed to allocate receive thread\n", handle->name);
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+/**
+ * Send a packet
+ *
+ * @param handle Handle of port to send on
+ * @param packet Packet to send
+ *
+ * @return Zero on success, negative on failure
+ */
+int bdk_nic_transmit(bdk_if_handle_t handle, const bdk_if_packet_t *packet)
+{
+ /* The SQ can't be filled completely as it reguires at least one free
+ entry so the head and pointer don't look like empty. SQ_SLOP is the
+ amount of SQ space we reserve to make sure of this */
+ const int SQ_SLOP = 1;
+ const nic_node_state_t *node_state = global_node_state[handle->node];
+ nic_t *nic = node_state->nic_map[handle->nic_id];
+ BDK_TRACE(NIC, "%s: Transmit packet of %d bytes, %d segments\n",
+ nic->handle->name, packet->length, packet->segments);
+
+ /* Update the SQ available if we're out of space. The NIC should have sent
+ packets, making more available. This allows us to only read the STATUS
+ CSR when really necessary, normally using the L1 cached value */
+ if (nic->sq_available < packet->segments + 1 + SQ_SLOP)
+ {
+ BDK_CSR_INIT(sq_status, nic->node, BDK_NIC_QSX_SQX_STATUS(nic->nic_vf, nic->sq));
+ nic->sq_available = SQ_ENTRIES - sq_status.s.qcount;
+ /* Re-Check for space. A packets is a header plus its segments */
+ if (nic->sq_available < packet->segments + 1 + SQ_SLOP)
+ {
+ BDK_TRACE(NIC, "%s: Transmit fail, queue full\n", nic->handle->name);
+ return -1;
+ }
+ }
+
+ /* Build the command */
+ void *sq_ptr = nic->sq_base;
+ int loc = nic->sq_loc;
+ union bdk_nic_send_hdr_s send_hdr;
+ send_hdr.u[0] = 0;
+ send_hdr.u[1] = 0;
+ send_hdr.s.subdc = BDK_NIC_SEND_SUBDC_E_HDR;
+ send_hdr.s.subdcnt = packet->segments;
+ send_hdr.s.total = packet->length;
+ switch (packet->packet_type)
+ {
+ case BDK_IF_TYPE_UNKNOWN:
+ break;
+ case BDK_IF_TYPE_UDP4:
+ send_hdr.s.ckl3 = 1; /* L3 - IPv4 checksum enable */
+ send_hdr.s.l3ptr = 14; /* L2 header is 14 bytes */
+ send_hdr.s.ckl4 = BDK_NIC_SEND_CKL4_E_UDP; /* L4 - UDP checksum enable */
+ send_hdr.s.l4ptr = 14 + 20; /* 14 bytes L2 + 20 bytes IPv4 */
+ break;
+ case BDK_IF_TYPE_TCP4:
+ send_hdr.s.ckl3 = 1; /* L3 - IPv4 checksum enable */
+ send_hdr.s.l3ptr = 14; /* L2 header is 14 bytes */
+ send_hdr.s.ckl4 = BDK_NIC_SEND_CKL4_E_TCP; /* L4 - TCP checksum enable */
+ send_hdr.s.l4ptr = 14 + 20; /* 14 bytes L2 + 20 bytes IPv4 */
+ if (packet->mtu)
+ {
+ int headers = 14 + 20 + 20;
+ send_hdr.s.tso = 1; /* Use TCP offload */
+ send_hdr.s.tso_sb = headers; /* 14 bytes L2 + 20 bytes IPv4, 20 bytes TCP */
+ send_hdr.s.tso_mps = packet->mtu - headers; /* Max TCP data payload size */
+ }
+ break;
+ }
+ volatile uint64_t *wptr = (uint64_t *)(sq_ptr + loc * 16);
+ wptr[0] = bdk_cpu_to_le64(send_hdr.u[0]);
+ wptr[1] = bdk_cpu_to_le64(send_hdr.u[1]);
+ BDK_TRACE(NIC, "%s: Transmit HDR[%p] = 0x%lx 0x%lx\n",
+ nic->handle->name, sq_ptr + loc * 16, send_hdr.u[0], send_hdr.u[1]);
+ loc++;
+ loc &= SQ_ENTRIES - 1;
+ for (int s = 0; s < packet->segments; s++)
+ {
+ union bdk_nic_send_gather_s gather;
+ gather.u[0] = 0;
+ gather.u[1] = 0;
+ gather.s.addr = packet->packet[s].s.address;
+ gather.s.subdc = BDK_NIC_SEND_SUBDC_E_GATHER;
+ gather.s.ld_type = (BDK_USE_DWB) ? BDK_NIC_SEND_LD_TYPE_E_LDWB : BDK_NIC_SEND_LD_TYPE_E_LDD;
+ gather.s.size = packet->packet[s].s.size;
+ wptr = (uint64_t *)(sq_ptr + loc * 16);
+ wptr[0] = bdk_cpu_to_le64(gather.u[0]);
+ wptr[1] = bdk_cpu_to_le64(gather.u[1]);
+ BDK_TRACE(NIC, "%s: Transmit Gather[%p] = 0x%lx 0x%lx\n",
+ nic->handle->name, sq_ptr + loc * 16, gather.u[0], gather.u[1]);
+ loc++;
+ loc &= SQ_ENTRIES - 1;
+ }
+
+ BDK_WMB;
+
+ /* Ring the doorbell */
+ BDK_CSR_WRITE(nic->node, BDK_NIC_QSX_SQX_DOOR(nic->nic_vf, nic->sq),
+ packet->segments + 1);
+ BDK_TRACE(NIC, "%s: Transmit Doorbell %d\n", nic->handle->name, packet->segments + 1);
+
+ /* Update our cached state */
+ nic->sq_available -= packet->segments + 1;
+ nic->sq_loc = loc;
+ if (handle->iftype != BDK_IF_BGX) {
+ /* Update stats as we do them in software for non-BGX */
+ handle->stats.tx.packets++;
+ handle->stats.tx.octets += packet->length;
+ if (handle->flags & BDK_IF_FLAGS_HAS_FCS)
+ handle->stats.tx.octets += 4;
+ }
+ return 0;
+}
+
+/**
+ * Get the current TX queue depth. Note that this operation may be slow
+ * and adversly affect packet IO performance.
+ *
+ * @param handle Port to check
+ *
+ * @return Depth of the queue in packets
+ */
+int bdk_nic_get_queue_depth(bdk_if_handle_t handle)
+{
+ const nic_node_state_t *node_state = global_node_state[handle->node];
+ const nic_t *nic = node_state->nic_map[handle->nic_id];
+ BDK_CSR_INIT(sq_status, nic->node, BDK_NIC_QSX_SQX_STATUS(nic->nic_vf, nic->sq));
+ return sq_status.s.qcount;
+}
+
+/**
+ * Query NIC and fill in the transmit stats for the supplied
+ * interface handle.
+ *
+ * @param handle Port handle
+ */
+void bdk_nic_fill_tx_stats(bdk_if_handle_t handle)
+{
+ const int vnic = handle->nic_id >> 3;
+
+ /* Transmit stats are done in software due to CN81XX not having enough NICs */
+
+ /* Note drops are shared across a BGX. People will be confused */
+ BDK_CSR_INIT(drps, handle->node, BDK_NIC_VNICX_TX_STATX(vnic, BDK_NIC_STAT_VNIC_TX_E_TX_DROP));
+ handle->stats.tx.dropped_packets = bdk_update_stat_with_overflow(drps.u, handle->stats.tx.dropped_packets, 48);
+ /* Dropped Octets are not available */
+}
+
+/**
+ * Query NIC and fill in the receive stats for the supplied
+ * interface handle.
+ *
+ * @param handle Port handle
+ */
+void bdk_nic_fill_rx_stats(bdk_if_handle_t handle)
+{
+ /* Account for RX FCS */
+ const int bytes_off_rx = (handle->flags & BDK_IF_FLAGS_HAS_FCS) ? 4 : 0;
+ const int vnic = handle->nic_id >> 3;
+
+ /* Note stats are shared across a BGX. People will be confused */
+
+ /* Read the RX statistics. These do not include the ethernet FCS */
+ BDK_CSR_INIT(rx_red, handle->node, BDK_NIC_VNICX_RX_STATX(vnic, BDK_NIC_STAT_VNIC_RX_E_RX_RED));
+ BDK_CSR_INIT(rx_red_octets, handle->node, BDK_NIC_VNICX_RX_STATX(vnic, BDK_NIC_STAT_VNIC_RX_E_RX_RED_OCTS));
+ BDK_CSR_INIT(rx_ovr, handle->node, BDK_NIC_VNICX_RX_STATX(vnic, BDK_NIC_STAT_VNIC_RX_E_RX_ORUN));
+ BDK_CSR_INIT(rx_ovr_octets, handle->node, BDK_NIC_VNICX_RX_STATX(vnic, BDK_NIC_STAT_VNIC_RX_E_RX_ORUN_OCTS));
+ uint64_t drops = rx_red.u + rx_ovr.u;
+ uint64_t drop_octets = rx_red_octets.u + rx_ovr_octets.u;
+
+ /* Drop and error counters */
+ handle->stats.rx.dropped_octets -= handle->stats.rx.dropped_packets * bytes_off_rx;
+ handle->stats.rx.dropped_octets = bdk_update_stat_with_overflow(drop_octets, handle->stats.rx.dropped_octets, 48);
+ handle->stats.rx.dropped_packets = bdk_update_stat_with_overflow(drops, handle->stats.rx.dropped_packets, 48);
+ handle->stats.rx.dropped_octets += handle->stats.rx.dropped_packets * bytes_off_rx;
+
+ /* Normal RX stats are done by software on receive */
+}
+
diff --git a/src/vendorcode/cavium/bdk/libbdk-hal/bdk-pcie-cn8xxx.c b/src/vendorcode/cavium/bdk/libbdk-hal/bdk-pcie-cn8xxx.c
new file mode 100644
index 0000000000..16034d27c3
--- /dev/null
+++ b/src/vendorcode/cavium/bdk/libbdk-hal/bdk-pcie-cn8xxx.c
@@ -0,0 +1,1263 @@
+/***********************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 <string.h>
+#include "libbdk-arch/bdk-csrs-dtx.h"
+#include "libbdk-arch/bdk-csrs-gser.h"
+#include "libbdk-arch/bdk-csrs-gic.h"
+#include "libbdk-arch/bdk-csrs-pem.h"
+#include "libbdk-arch/bdk-csrs-pcierc.h"
+#include "libbdk-arch/bdk-csrs-sli.h"
+#include "libbdk-arch/bdk-csrs-rst.h"
+#include "libbdk-hal/bdk-pcie.h"
+#include "libbdk-hal/bdk-config.h"
+#include "libbdk-hal/bdk-utils.h"
+#include "libbdk-hal/if/bdk-if.h"
+#include "libbdk-hal/bdk-qlm.h"
+#include "libbdk-hal/device/bdk-device.h"
+#include "libbdk-hal/bdk-ecam.h"
+
+/**
+ * Return the number of possible PCIe ports on a node. The actual number
+ * of configured ports may be less and may also be disjoint.
+ *
+ * @param node Node to query
+ *
+ * @return Number of PCIe ports that are possible
+ */
+int bdk_pcie_get_num_ports(bdk_node_t node)
+{
+ if (CAVIUM_IS_MODEL(CAVIUM_CN88XX))
+ return 6;
+ else if (CAVIUM_IS_MODEL(CAVIUM_CN83XX))
+ return 4;
+ else if (CAVIUM_IS_MODEL(CAVIUM_CN81XX))
+ return 3;
+ else
+ return 0;
+}
+
+
+/**
+ * Given a PCIe port, determine which SLI controls its memory regions
+ *
+ * @param node Node for the PCIe port
+ * @param pcie_port The PCIe port
+ * @param sli The SLI index is written to this integer pointer
+ * @param sli_group The index of the PCIe port on the SLI is returned here. This is a sequencial
+ * number for each PCIe on an SLI. Use this to index SLI regions.
+ */
+static void __bdk_pcie_get_sli(bdk_node_t node, int pcie_port, int *sli, int *sli_group)
+{
+ /* This mapping should be determined by find the SLI number on the
+ same ECAM bus as the PCIERC bridge. That is fairly complex, so it is
+ hardcoded for now */
+ if (CAVIUM_IS_MODEL(CAVIUM_CN88XX))
+ {
+ /* Ports 0-2 goto SLI0, ports 3-5 goto SLI1 */
+ *sli = (pcie_port >= 3) ? 1 : 0;
+ *sli_group = pcie_port - *sli * 3;
+ return;
+ }
+ else if (CAVIUM_IS_MODEL(CAVIUM_CN83XX) || CAVIUM_IS_MODEL(CAVIUM_CN81XX))
+ {
+ /* Only one SLI */
+ *sli = 0;
+ *sli_group = pcie_port;
+ return;
+ }
+ else
+ bdk_fatal("Unable to determine SLI for PCIe port. Update __bdk_pcie_get_sli()\n");
+}
+
+/**
+ * Return the Core physical base address for PCIe MEM access. Memory is
+ * read/written as an offset from this address.
+ *
+ * @param node Node to use in a Numa setup
+ * @param pcie_port PCIe port the memory is on
+ * @param mem_type Type of memory
+ *
+ * @return 64bit physical address for read/write
+ */
+uint64_t bdk_pcie_get_base_address(bdk_node_t node, int pcie_port, bdk_pcie_mem_t mem_type)
+{
+ /* See __bdk_pcie_sli_initialize() for a description about how SLI regions work */
+ int sli;
+ int sli_group;
+ __bdk_pcie_get_sli(node, pcie_port, &sli, &sli_group);
+ int region = (sli_group << 6) | (mem_type << 4);
+ union bdk_sli_s2m_op_s s2m_op;
+ s2m_op.u = 0;
+ s2m_op.s.io = 1;
+ s2m_op.s.node = node;
+ s2m_op.s.did_hi = 0x8 + sli;
+ s2m_op.s.region = region;
+ return s2m_op.u;
+}
+
+/**
+ * Size of the Mem address region returned at address
+ * bdk_pcie_get_base_address()
+ *
+ * @param node Node to use in a Numa setup
+ * @param pcie_port PCIe port the IO is for
+ * @param mem_type Type of memory
+ *
+ * @return Size of the Mem window
+ */
+uint64_t bdk_pcie_get_base_size(bdk_node_t node, int pcie_port, bdk_pcie_mem_t mem_type)
+{
+ return 1ull << 36;
+}
+
+/**
+ * @INTERNAL
+ * Initialize the RC config space CSRs
+ *
+ * @param pcie_port PCIe port to initialize
+ */
+static void __bdk_pcie_rc_initialize_config_space(bdk_node_t node, int pcie_port)
+{
+ int sli;
+ int sli_group;
+ __bdk_pcie_get_sli(node, pcie_port, &sli, &sli_group);
+
+ /* The reset default for config retries is too short. Set it to 48ms, which
+ is what the Octeon SDK team is using. There is no documentation about
+ where they got the 48ms number */
+ int cfg_retry = 48 * 1000000 / (bdk_clock_get_rate(node, BDK_CLOCK_SCLK) >> 16);
+ if (cfg_retry >= 0x10000)
+ cfg_retry = 0xfffff;
+ BDK_CSR_MODIFY(c, node, BDK_PEMX_CTL_STATUS(pcie_port),
+ c.cn83xx.cfg_rtry = cfg_retry);
+
+
+ /* Max Payload Size (PCIE*_CFG030[MPS]) */
+ /* Max Read Request Size (PCIE*_CFG030[MRRS]) */
+ /* Relaxed-order, no-snoop enables (PCIE*_CFG030[RO_EN,NS_EN] */
+ /* Error Message Enables (PCIE*_CFG030[CE_EN,NFE_EN,FE_EN,UR_EN]) */
+ BDK_CSR_MODIFY(c, node, BDK_PCIERCX_CFG030(pcie_port),
+ c.s.mps = 1; /* Support 256 byte MPS */
+ c.s.mrrs = 0x5; /* Support 4KB MRRS */
+ c.s.ro_en = 1; /* Enable relaxed order processing. This will allow devices to affect read response ordering */
+ c.s.ns_en = 1; /* Enable no snoop processing. Not used */
+ c.s.ce_en = 1; /* Correctable error reporting enable. */
+ c.s.nfe_en = 1; /* Non-fatal error reporting enable. */
+ c.s.fe_en = 1; /* Fatal error reporting enable. */
+ c.s.ur_en = 1); /* Unsupported request reporting enable. */
+
+ /* Configure the PCIe slot number if specified */
+ int slot_num = bdk_config_get_int(BDK_CONFIG_PCIE_PHYSICAL_SLOT, node, pcie_port);
+ if (slot_num != -1)
+ {
+ BDK_CSR_MODIFY(c, node, BDK_PCIERCX_CFG028(pcie_port),
+ c.s.si = 1); /* Slot Implemented*/
+ BDK_CSR_MODIFY(c, node, BDK_PCIERCX_CFG033(pcie_port),
+ c.s.ps_num = slot_num);
+ }
+
+ /* Disable ECRC Generation as not all card support it. The OS can enable it
+ later if desired (PCIE*_CFG070[GE,CE]) */
+ BDK_CSR_MODIFY(c, node, BDK_PCIERCX_CFG070(pcie_port),
+ c.s.ge = 0; /* ECRC generation disable. */
+ c.s.ce = 0); /* ECRC check disable. */
+
+ /* Access Enables (PCIE*_CFG001[MSAE,ME]) */
+ /* ME and MSAE should always be set. */
+ /* Interrupt Disable (PCIE*_CFG001[I_DIS]) */
+ /* System Error Message Enable (PCIE*_CFG001[SEE]) */
+ BDK_CSR_MODIFY(c, node, BDK_PCIERCX_CFG001(pcie_port),
+ c.s.msae = 1; /* Memory space enable. */
+ c.s.me = 1; /* Bus master enable. */
+ c.s.i_dis = 1; /* INTx assertion disable. */
+ c.s.see = 1); /* SERR# enable */
+
+ /* Advanced Error Recovery Message Enables */
+ /* (PCIE*_CFG066,PCIE*_CFG067,PCIE*_CFG069) */
+ BDK_CSR_WRITE(node, BDK_PCIERCX_CFG066(pcie_port), 0);
+ /* Use BDK_PCIERCX_CFG067 hardware default */
+ BDK_CSR_WRITE(node, BDK_PCIERCX_CFG069(pcie_port), 0);
+
+
+ /* Active State Power Management (PCIE*_CFG032[ASLPC]) */
+ BDK_CSR_MODIFY(c, node, BDK_PCIERCX_CFG032(pcie_port),
+ c.s.aslpc = 0); /* Active state Link PM control. */
+
+ /* Link Width Mode (PCIERCn_CFG452[LME]) - Set during bdk_pcie_rc_initialize_link() */
+ /* Primary Bus Number (PCIERCn_CFG006[PBNUM]) */
+ /* Use bus numbers as follows:
+ 0 - 31: Reserved for internal ECAM
+ 32 - 87: First PCIe on SLI
+ 88 - 143: Second PCIe on SLI
+ 144 - 199: Third PCIe on SLI
+ 200 - 255: Fourth PCIe on SLI
+ Start bus = 32 + pcie * 56 */
+ const int BUSSES_PER_PCIE = 56;
+ int bus = 32 + sli_group * BUSSES_PER_PCIE;
+ BDK_CSR_MODIFY(c, node, BDK_PCIERCX_CFG006(pcie_port),
+ c.s.pbnum = 0;
+ c.s.sbnum = bus;
+ c.s.subbnum = bus + BUSSES_PER_PCIE - 1);
+
+ /* Memory-mapped I/O BAR (PCIERCn_CFG008) */
+ uint64_t mem_base = bdk_pcie_get_base_address(node, pcie_port, BDK_PCIE_MEM_NORMAL);
+ uint64_t mem_limit = mem_base + bdk_pcie_get_base_size(node, pcie_port, BDK_PCIE_MEM_NORMAL) - 1;
+ BDK_CSR_MODIFY(c, node, BDK_PCIERCX_CFG008(pcie_port),
+ c.s.mb_addr = mem_base >> 16;
+ c.s.ml_addr = mem_limit >> 16);
+
+ /* Prefetchable BAR (PCIERCn_CFG009,PCIERCn_CFG010,PCIERCn_CFG011) */
+ uint64_t prefetch_base = bdk_pcie_get_base_address(node, pcie_port, BDK_PCIE_MEM_PREFETCH);
+ uint64_t prefetch_limit = prefetch_base + bdk_pcie_get_base_size(node, pcie_port, BDK_PCIE_MEM_PREFETCH) - 1;
+ BDK_CSR_MODIFY(c, node, BDK_PCIERCX_CFG009(pcie_port),
+ c.s.lmem_base = prefetch_base >> 16;
+ c.s.lmem_limit = prefetch_limit >> 16);
+ BDK_CSR_MODIFY(c, node, BDK_PCIERCX_CFG010(pcie_port),
+ c.s.umem_base = prefetch_base >> 32);
+ BDK_CSR_MODIFY(c, node, BDK_PCIERCX_CFG011(pcie_port),
+ c.s.umem_limit = prefetch_limit >> 32);
+
+ /* System Error Interrupt Enables (PCIERCn_CFG035[SECEE,SEFEE,SENFEE]) */
+ /* PME Interrupt Enables (PCIERCn_CFG035[PMEIE]) */
+ BDK_CSR_MODIFY(c, node, BDK_PCIERCX_CFG035(pcie_port),
+ c.s.secee = 1; /* System error on correctable error enable. */
+ c.s.sefee = 1; /* System error on fatal error enable. */
+ c.s.senfee = 1; /* System error on non-fatal error enable. */
+ c.s.pmeie = 1); /* PME interrupt enable. */
+
+ /* Advanced Error Recovery Interrupt Enables */
+ /* (PCIERCn_CFG075[CERE,NFERE,FERE]) */
+ BDK_CSR_MODIFY(c, node, BDK_PCIERCX_CFG075(pcie_port),
+ c.s.cere = 1; /* Correctable error reporting enable. */
+ c.s.nfere = 1; /* Non-fatal error reporting enable. */
+ c.s.fere = 1); /* Fatal error reporting enable. */
+
+ /* Make sure the PEM agrees with GSERX about the speed its going to try */
+ BDK_CSR_INIT(pem_cfg, node, BDK_PEMX_CFG(pcie_port));
+ switch (pem_cfg.cn83xx.md)
+ {
+ case 0: /* Gen 1 */
+ /* Set the target link speed */
+ BDK_CSR_MODIFY(c, node, BDK_PCIERCX_CFG040(pcie_port),
+ c.s.tls = 1);
+ break;
+ case 1: /* Gen 2 */
+ /* Set the target link speed */
+ BDK_CSR_MODIFY(c, node, BDK_PCIERCX_CFG040(pcie_port),
+ c.s.tls = 2);
+ break;
+ case 2: /* Gen 3 */
+ /* Set the target link speed */
+ BDK_CSR_MODIFY(c, node, BDK_PCIERCX_CFG040(pcie_port),
+ c.s.tls = 3);
+ break;
+ default:
+ bdk_error("N%d.PCIe%d: Unexpected rate of %d\n", node, pcie_port, pem_cfg.cn83xx.md);
+ break;
+ }
+
+ BDK_CSR_INIT(pemx_cfg, node, BDK_PEMX_CFG(pcie_port));
+ BDK_CSR_INIT(cfg452, node, BDK_PCIERCX_CFG452(pcie_port));
+ BDK_CSR_INIT(cfg031, node, BDK_PCIERCX_CFG031(pcie_port));
+ int lme = cfg452.s.lme;
+ int mlw = cfg031.s.mlw;
+
+ /* Link Width Mode (PCIERCn_CFG452[LME]) */
+ if (CAVIUM_IS_MODEL(CAVIUM_CN88XX))
+ {
+ lme = (pemx_cfg.cn88xx.lanes8) ? 0xf : 0x7;
+ mlw = (pemx_cfg.cn88xx.lanes8) ? 8 : 4;
+ }
+ /* CN83XX can support 8 lanes on QLM0+1 or QLM2+3. 4 lanes on DLM5+6 */
+ if (CAVIUM_IS_MODEL(CAVIUM_CN83XX))
+ {
+ switch (pcie_port)
+ {
+ case 0: /* PEM0 on QLM0-1 */
+ lme = (pemx_cfg.cn83xx.lanes8) ? 0xf : 0x7;
+ mlw = (pemx_cfg.cn83xx.lanes8) ? 8 : 4;
+ break;
+ case 1: /* PEM1 on QLM1 */
+ lme = 0x7;
+ mlw = 4;
+ break;
+ case 2: /* PEM2 on QLM2-3 or DLM4 */
+ {
+ BDK_CSR_INIT(pemx_qlm, node, BDK_PEMX_QLM(pcie_port));
+ if (pemx_qlm.s.pem_bdlm) /* PEM2 is on DLM4 */
+ {
+ lme = 0x3;
+ mlw = 2;
+ }
+ else /* PEM2 is on QLM2 */
+ {
+ lme = (pemx_cfg.cn83xx.lanes8) ? 0xf : 0x7;
+ mlw = (pemx_cfg.cn83xx.lanes8) ? 8 : 4;
+ }
+ break;
+ }
+ case 3: /* PEM3 on QLM3 or DLM5-6 */
+ {
+ BDK_CSR_INIT(pemx_qlm, node, BDK_PEMX_QLM(pcie_port));
+ if (pemx_qlm.s.pem_bdlm) /* PEM3 is on DLM5-6 */
+ {
+ lme = (pemx_cfg.cn83xx.lanes8) ? 0x7 : 0x3;
+ mlw = (pemx_cfg.cn83xx.lanes8) ? 4 : 2;
+ }
+ else /* PEM3 is on QLM3 */
+ {
+ lme = 0x7;
+ mlw = 4;
+ }
+ break;
+ }
+ }
+ }
+ /* CN80XX only supports 1 lane on PEM0 */
+ if (cavium_is_altpkg(CAVIUM_CN81XX) && (pcie_port == 0))
+ {
+ lme = 1;
+ mlw = 1;
+ }
+
+ /* Allow override of hardware max link width */
+ int max_width = bdk_config_get_int(BDK_CONFIG_PCIE_WIDTH, node, pcie_port);
+ switch (max_width)
+ {
+ case 1:
+ lme = 1;
+ mlw = 1;
+ break;
+ case 2:
+ lme = 3;
+ mlw = 2;
+ break;
+ case 4:
+ lme = 7;
+ mlw = 4;
+ break;
+ case 8:
+ lme = 0xf;
+ mlw = 8;
+ break;
+ case 16:
+ lme = 0x1f;
+ mlw = 16;
+ break;
+ default:
+ /* No change */
+ break;
+ }
+ BDK_CSR_MODIFY(c, node, BDK_PCIERCX_CFG452(pcie_port),
+ c.s.lme = lme);
+ BDK_CSR_MODIFY(c, node, BDK_PCIERCX_CFG031(pcie_port),
+ c.s.mlw = mlw);
+
+ /* Errata PEM-25990 - Disable ASLPMS */
+ BDK_CSR_MODIFY(c, node, BDK_PCIERCX_CFG031(pcie_port),
+ c.s.aslpms = 0);
+
+ /* Errata PEM-26189 - PEM EQ Preset Removal */
+ /* CFG554.PRV default changed from 16'h7ff to 16'h593. Should be
+ safe to apply to CN88XX, CN81XX, and CN83XX */
+ BDK_CSR_MODIFY(c, node, BDK_PCIERCX_CFG554(pcie_port),
+ c.s.prv = bdk_config_get_int(BDK_CONFIG_PCIE_PRESET_REQUEST_VECTOR, node, pcie_port));
+
+ /* Errata PEM-26189 - Disable the 2ms timer on all chips */
+ BDK_CSR_MODIFY(c, node, BDK_PCIERCX_CFG554(pcie_port),
+ c.s.p23td = 1);
+
+ /* Errata PEM-21178 - Change the CFG[089-092] LxUTP and LxDTP defaults.
+ Should be safe to apply to CN88XX, CN81XX, and CN83XX */
+ BDK_CSR_MODIFY(c, node, BDK_PCIERCX_CFG089(pcie_port),
+ c.s.l0dtp = 0x7;
+ c.s.l0utp = 0x7;
+ c.cn83xx.l1dtp = 0x7;
+ c.s.l1utp = 0x7);
+ BDK_CSR_MODIFY(c, node, BDK_PCIERCX_CFG090(pcie_port),
+ c.s.l2dtp = 0x7;
+ c.s.l2utp = 0x7;
+ c.s.l3dtp = 0x7;
+ c.s.l3utp = 0x7);
+ BDK_CSR_MODIFY(c, node, BDK_PCIERCX_CFG091(pcie_port),
+ c.s.l4dtp = 0x7;
+ c.s.l4utp = 0x7;
+ c.s.l5dtp = 0x7;
+ c.s.l5utp = 0x7);
+ BDK_CSR_MODIFY(c, node, BDK_PCIERCX_CFG092(pcie_port),
+ c.s.l6dtp = 0x7;
+ c.s.l6utp = 0x7;
+ c.s.l7dtp = 0x7;
+ c.s.l7utp = 0x7);
+
+ /* (ECAM-27114) PCIERC has incorrect device code */
+ BDK_CSR_MODIFY(c, node, BDK_PCIERCX_CFG002(pcie_port),
+ c.s.sc = 0x4;
+ c.s.bcc = 0x6);
+
+ /* Errata PCIE-29440 - Atomic Egress ATOM_OP/ATOM_OP_EP not implemented
+ correctly */
+ BDK_CSR_MODIFY(c, node, BDK_PCIERCX_CFG038(pcie_port),
+ c.s.atom_op =0x1;
+ c.s.atom_op_eb=0);
+
+ /* Errata PCIE-29566 PEM Link Hangs after going into L1 */
+ BDK_CSR_MODIFY(c, node, BDK_PCIERCX_CFG548(pcie_port),
+ c.s.grizdnc = 0x0);
+}
+
+/**
+ * Get the PCIe LTSSM state for the given port
+ *
+ * @param node Node to query
+ * @param pcie_port PEM to query
+ *
+ * @return LTSSM state
+ */
+static int __bdk_pcie_rc_get_ltssm_state(bdk_node_t node, int pcie_port)
+{
+ /* LTSSM state is in debug select 0 */
+ BDK_CSR_WRITE(node, BDK_DTX_PEMX_SELX(pcie_port, 0), 0);
+ BDK_CSR_WRITE(node, BDK_DTX_PEMX_ENAX(pcie_port, 0), 0xfffffffffull);
+ /* Read the value */
+ uint64_t debug = BDK_CSR_READ(node, BDK_DTX_PEMX_DATX(pcie_port, 0));
+ /* Disable the PEM from driving OCLA signals */
+ BDK_CSR_WRITE(node, BDK_DTX_PEMX_ENAX(pcie_port, 0), 0);
+ if (CAVIUM_IS_MODEL(CAVIUM_CN83XX))
+ return bdk_extract(debug, 0, 6); /* DBGSEL = 0x0, bits[5:0] */
+ else
+ return bdk_extract(debug, 3, 6); /* DBGSEL = 0x0, bits[8:3] */
+}
+
+/**
+ * Get the PCIe LTSSM state for the given port
+ *
+ * @param node Node to query
+ * @param pcie_port PEM to query
+ *
+ * @return LTSSM state
+ */
+static const char *ltssm_string(int ltssm)
+{
+ switch (ltssm)
+ {
+ case 0x00: return "DETECT_QUIET";
+ case 0x01: return "DETECT_ACT";
+ case 0x02: return "POLL_ACTIVE";
+ case 0x03: return "POLL_COMPLIANCE";
+ case 0x04: return "POLL_CONFIG";
+ case 0x05: return "PRE_DETECT_QUIET";
+ case 0x06: return "DETECT_WAIT";
+ case 0x07: return "CFG_LINKWD_START";
+ case 0x08: return "CFG_LINKWD_ACEPT";
+ case 0x09: return "CFG_LANENUM_WAIT";
+ case 0x0A: return "CFG_LANENUM_ACEPT";
+ case 0x0B: return "CFG_COMPLETE";
+ case 0x0C: return "CFG_IDLE";
+ case 0x0D: return "RCVRY_LOCK";
+ case 0x0E: return "RCVRY_SPEED";
+ case 0x0F: return "RCVRY_RCVRCFG";
+ case 0x10: return "RCVRY_IDLE";
+ case 0x11: return "L0";
+ case 0x12: return "L0S";
+ case 0x13: return "L123_SEND_EIDLE";
+ case 0x14: return "L1_IDLE";
+ case 0x15: return "L2_IDLE";
+ case 0x16: return "L2_WAKE";
+ case 0x17: return "DISABLED_ENTRY";
+ case 0x18: return "DISABLED_IDLE";
+ case 0x19: return "DISABLED";
+ case 0x1A: return "LPBK_ENTRY";
+ case 0x1B: return "LPBK_ACTIVE";
+ case 0x1C: return "LPBK_EXIT";
+ case 0x1D: return "LPBK_EXIT_TIMEOUT";
+ case 0x1E: return "HOT_RESET_ENTRY";
+ case 0x1F: return "HOT_RESET";
+ case 0x20: return "RCVRY_EQ0";
+ case 0x21: return "RCVRY_EQ1";
+ case 0x22: return "RCVRY_EQ2";
+ case 0x23: return "RCVRY_EQ3";
+ default: return "Unknown";
+ }
+}
+
+/**
+ * During PCIe link initialization we need to make config request to the attached
+ * device to verify its speed and width. These config access happen very early
+ * after the device is taken out of reset, so may fail for some amount of time.
+ * This function automatically retries these config accesses. The normal builtin
+ * hardware retry isn't enough for this very early access.
+ *
+ * @param node Note to read from
+ * @param pcie_port PCIe port to read from
+ * @param bus PCIe bus number
+ * @param dev PCIe device
+ * @param func PCIe function on the device
+ * @param reg Register to read
+ *
+ * @return Config register value, or all ones on failure
+ */
+static uint32_t cfg_read32_retry(bdk_node_t node, int pcie_port, int bus, int dev, int func, int reg)
+{
+ /* Read the PCI config register until we get a valid value. Some cards
+ require time after link up to return data. Wait at most 3 seconds */
+ uint64_t timeout = bdk_clock_get_count(BDK_CLOCK_TIME) + bdk_clock_get_rate(bdk_numa_local(), BDK_CLOCK_TIME) * 3;
+ uint32_t val;
+ do
+ {
+ /* Read PCI capability pointer */
+ val = bdk_pcie_config_read32(node, pcie_port, bus, dev, func, reg);
+ /* Check the read succeeded */
+ if (val != 0xffffffff)
+ return val;
+ /* Failed, wait a little and try again */
+ bdk_wait_usec(10000);
+ } while (bdk_clock_get_count(BDK_CLOCK_TIME) < timeout);
+
+ BDK_TRACE(PCIE, "N%d.PCIe%d: Config read failed, can't communicate with device\n",
+ node, pcie_port);
+ return 0xffffffff;
+}
+
+/**
+ * Initialize a host mode PCIe link. This function assumes the PEM has already
+ * been taken out of reset and configure. It brings up the link and checks that
+ * the negotiated speed and width is correct for the configured PEM and the
+ * device plugged into it. Note that the return code will signal a retry needed
+ * for some link failures. The caller is responsible for PEM reset and retry.
+ *
+ * @param node Node the PEM is on
+ * @param pcie_port PCIe port to initialize link on
+ *
+ * @return Zero on success
+ * Negative on failures where retries are not needed
+ * Positive if a retry is needed to fix a failure
+ */
+static int __bdk_pcie_rc_initialize_link(bdk_node_t node, int pcie_port)
+{
+ #define LTSSM_HISTORY_SIZE 64 /* Number of LTSSM transitions to record, must be a power of 2 */
+ uint8_t ltssm_history[LTSSM_HISTORY_SIZE];
+ int ltssm_history_loc;
+ bool do_retry_speed = false;
+
+ BDK_TRACE(PCIE, "N%d.PCIe%d: Checking the PEM is out of reset\n", node, pcie_port);
+ if (BDK_CSR_WAIT_FOR_FIELD(node, BDK_PEMX_ON(pcie_port), pemoor, ==, 1, 100000))
+ {
+ printf("N%d.PCIe%d: PEM in reset, skipping.\n", node, pcie_port);
+ return -1;
+ }
+
+ /* Determine the maximum link speed and width */
+ BDK_CSR_INIT(pciercx_cfg031, node, BDK_PCIERCX_CFG031(pcie_port));
+ int max_gen = pciercx_cfg031.s.mls; /* Max speed of PEM from config (1-3) */
+ int max_width = pciercx_cfg031.s.mlw; /* Max lane width of PEM (1-8) */
+ BDK_TRACE(PCIE, "N%d.PCIe%d: Link supports up to %d lanes, speed gen%d\n",
+ node, pcie_port, max_width, max_gen);
+
+ /* Record starting LTSSM state for debug */
+ memset(ltssm_history, -1, sizeof(ltssm_history));
+ ltssm_history[0] = __bdk_pcie_rc_get_ltssm_state(node, pcie_port);
+ ltssm_history_loc = 0;
+
+ /* Bring up the link */
+ BDK_TRACE(PCIE, "N%d.PCIe%d: Enabling the link\n", node, pcie_port);
+ BDK_CSR_MODIFY(c, node, BDK_PEMX_CTL_STATUS(pcie_port), c.cn83xx.lnk_enb = 1);
+
+ if (bdk_config_get_int(BDK_CONFIG_PCIE_SKIP_LINK_TRAIN, node, pcie_port)) {
+ BDK_TRACE(PCIE, "N%d.PCIe%d: Skipping link configuration\n", node, pcie_port);
+ return 0;
+ }
+
+retry_speed:
+ /* Clear RC Correctable Error Status Register */
+ BDK_CSR_WRITE(node, BDK_PCIERCX_CFG068(pcie_port), -1);
+
+ /* Wait for the link to come up and link training to be complete */
+ BDK_TRACE(PCIE, "N%d.PCIe%d: Waiting for link\n", node, pcie_port);
+
+ uint64_t clock_rate = bdk_clock_get_rate(bdk_numa_local(), BDK_CLOCK_TIME);
+ uint64_t hold_time = clock_rate / 5; /* 200ms */
+ uint64_t bounce_allow_time = clock_rate / 100; /* 10ms */
+ uint64_t timeout = bdk_clock_get_count(BDK_CLOCK_TIME) + clock_rate; /* Timeout = 1s */
+ uint64_t good_time = 0; /* Records when the link first went good */
+ BDK_CSR_DEFINE(pciercx_cfg032, BDK_PCIERCX_CFG032(pcie_port));
+ bool link_up;
+ bool is_loop_done;
+ do
+ {
+ /* Read link state */
+ pciercx_cfg032.u = BDK_CSR_READ(node, BDK_PCIERCX_CFG032(pcie_port));
+
+ /* Record LTSSM state for debug */
+ int ltssm_state = __bdk_pcie_rc_get_ltssm_state(node, pcie_port);
+ if (ltssm_history[ltssm_history_loc] != ltssm_state)
+ {
+ ltssm_history_loc = (ltssm_history_loc + 1) & (LTSSM_HISTORY_SIZE - 1);
+ ltssm_history[ltssm_history_loc] = ltssm_state;
+ }
+
+ /* Check if the link is up */
+ uint64_t current_time = bdk_clock_get_count(BDK_CLOCK_TIME);
+ link_up = (pciercx_cfg032.s.dlla && !pciercx_cfg032.s.lt);
+ if (link_up)
+ {
+ /* Is this the first link up? */
+ if (!good_time)
+ {
+ /* Mark the time when the link transitioned to good */
+ good_time = current_time;
+ }
+ else
+ {
+ /* Check for a link error */
+ BDK_CSR_INIT(cfg068, node, BDK_PCIERCX_CFG068(pcie_port));
+ if (cfg068.s.res)
+ {
+ /* Ignore errors before we've been stable for bounce_allow_time */
+ if (good_time + bounce_allow_time <= current_time)
+ {
+ BDK_TRACE(PCIE, "N%d.PCIe%d: Link errors after link up\n", node, pcie_port);
+ return 1; /* Link error, signal a retry */
+ }
+ else
+ {
+ /* Clear RC Correctable Error Status Register */
+ BDK_CSR_WRITE(node, BDK_PCIERCX_CFG068(pcie_port), -1);
+ BDK_TRACE(PCIE, "N%d.PCIe%d: Ignored error during settling time\n", node, pcie_port);
+ }
+ }
+ }
+ }
+ else if (good_time)
+ {
+ if (good_time + bounce_allow_time <= current_time)
+ {
+ /* We allow bounces for bounce_allow_time after the link is good.
+ Once this time passes any bounce requires a retry */
+ BDK_TRACE(PCIE, "N%d.PCIe%d: Link bounce detected\n", node, pcie_port);
+ return 1; /* Link bounce, signal a retry */
+ }
+ else
+ {
+ BDK_TRACE(PCIE, "N%d.PCIe%d: Ignored bounce during settling time\n", node, pcie_port);
+ }
+ }
+
+ /* Determine if we've hit the timeout */
+ is_loop_done = (current_time >= timeout);
+ /* Determine if we've had a good link for the required hold time */
+ is_loop_done |= link_up && (good_time + hold_time <= current_time);
+ } while (!is_loop_done);
+
+ /* Trace the LTSSM state */
+ BDK_TRACE(PCIE, "N%d.PCIe%d: LTSSM History\n", node, pcie_port);
+ for (int i = 0; i < LTSSM_HISTORY_SIZE; i++)
+ {
+ ltssm_history_loc = (ltssm_history_loc + 1) & (LTSSM_HISTORY_SIZE - 1);
+ if (ltssm_history[ltssm_history_loc] != 0xff)
+ BDK_TRACE(PCIE, "N%d.PCIe%d: %s\n",
+ node, pcie_port, ltssm_string(ltssm_history[ltssm_history_loc]));
+ }
+
+ if (!link_up)
+ {
+ BDK_TRACE(PCIE, "N%d.PCIe%d: Link down, Data link layer %s(DLLA=%d), Link training %s(LT=%d), LTSSM %s\n",
+ node, pcie_port,
+ pciercx_cfg032.s.dlla ? "active" : "down", pciercx_cfg032.s.dlla,
+ pciercx_cfg032.s.lt ? "active" : "complete", pciercx_cfg032.s.lt,
+ ltssm_string(__bdk_pcie_rc_get_ltssm_state(node, pcie_port)));
+ return 1; /* Link down, signal a retry */
+ }
+
+ /* Report the negotiated link speed and width */
+ int neg_gen = pciercx_cfg032.s.ls; /* Current speed of PEM (1-3) */
+ int neg_width = pciercx_cfg032.s.nlw; /* Current lane width of PEM (1-8) */
+ BDK_TRACE(PCIE, "N%d.PCIe%d: Link negotiated %d lanes, speed gen%d\n",
+ node, pcie_port, neg_width, neg_gen);
+
+ /* Determine PCIe bus number the directly attached device uses */
+ BDK_CSR_INIT(pciercx_cfg006, node, BDK_PCIERCX_CFG006(pcie_port));
+ int bus = pciercx_cfg006.s.sbnum;
+
+ int dev_gen = 1; /* Device max speed (1-3) */
+ int dev_width = 1; /* Device max lane width (1-16) */
+ BDK_TRACE(PCIE, "N%d.PCIe%d: Reading device max speed and width\n",
+ node, pcie_port);
+
+ /* Read PCI capability pointer */
+ uint32_t cap = cfg_read32_retry(node, pcie_port, bus, 0, 0, 0x34);
+
+ /* Check if we were able to read capabilities pointer */
+ if (cap == 0xffffffff)
+ return 1; /* Signal retry needed */
+
+ /* Read device max speed and width */
+ int cap_next = cap & 0xff;
+ while (cap_next)
+ {
+ cap = cfg_read32_retry(node, pcie_port, bus, 0, 0, cap_next);
+ if (cap == 0xffffffff)
+ return 1; /* Signal retry needed */
+
+ /* Is this a PCIe capability (0x10)? */
+ if ((cap & 0xff) == 0x10)
+ {
+ BDK_TRACE(PCIE, "N%d.PCIe%d: Found PCIe capability at offset 0x%x\n",
+ node, pcie_port, cap_next);
+ /* Offset 0xc contains the max link info */
+ cap = cfg_read32_retry(node, pcie_port, bus, 0, 0, cap_next + 0xc);
+ if (cap == 0xffffffff)
+ return 1; /* Signal retry needed */
+ dev_gen = cap & 0xf; /* Max speed of PEM from config (1-3) */
+ dev_width = (cap >> 4) & 0x3f; /* Max lane width of PEM (1-16) */
+ BDK_TRACE(PCIE, "N%d.PCIe%d: Device supports %d lanes, speed gen%d\n",
+ node, pcie_port, dev_width, dev_gen);
+ break;
+ }
+ /* Move to next capability */
+ cap_next = (cap >> 8) & 0xff;
+ }
+
+ /* Desired link speed and width is either limited by the device or our PEM
+ configuration. Choose the most restrictive limit */
+ int desired_gen = (dev_gen < max_gen) ? dev_gen : max_gen;
+ int desired_width = (dev_width < max_width) ? dev_width : max_width;
+
+ /* We need a change if we don't match the desired speed or width. Note that
+ we allow better than expected in case the device lied about its
+ capabilities */
+ bool need_speed_change = (neg_gen < desired_gen);
+ bool need_lane_change = (neg_width < desired_width);
+
+ if (need_lane_change)
+ {
+ /* We didn't get the maximum number of lanes */
+ BDK_TRACE(PCIE, "N%d.PCIe%d: Link width (%d) less that supported (%d)\n",
+ node, pcie_port, neg_width, desired_width);
+ return 2; /* Link wrong width, signal a retry */
+ }
+ else if (need_speed_change)
+ {
+ if (do_retry_speed)
+ {
+ BDK_TRACE(PCIE, "N%d.PCIe%d: Link speed (gen%d) less that supported (gen%d)\n",
+ node, pcie_port, neg_gen, desired_gen);
+ return 1; /* Link at width, but speed low. Request a retry */
+ }
+ else
+ {
+ /* We didn't get the maximum speed. Request a speed change */
+ BDK_TRACE(PCIE, "N%d.PCIe%d: Link speed (gen%d) less that supported (gen%d), requesting a speed change\n",
+ node, pcie_port, neg_gen, desired_gen);
+ BDK_CSR_MODIFY(c, node, BDK_PCIERCX_CFG515(pcie_port),
+ c.s.dsc = 1);
+ bdk_wait_usec(100000);
+ do_retry_speed = true;
+ goto retry_speed;
+ }
+ }
+ else
+ {
+ BDK_TRACE(PCIE, "N%d.PCIe%d: Link at best speed and width\n", node, pcie_port);
+ /* For gen3 links check if we are getting errors over the link */
+ if (neg_gen == 3)
+ {
+ /* Read RC Correctable Error Status Register */
+ BDK_CSR_INIT(cfg068, node, BDK_PCIERCX_CFG068(pcie_port));
+ if (cfg068.s.res)
+ {
+ BDK_TRACE(PCIE, "N%d.PCIe%d: Link reporting error status\n", node, pcie_port);
+ return 1; /* Getting receiver errors, request a retry */
+ }
+ }
+ return 0; /* Link at correct speed and width */
+ }
+}
+
+/**
+ * Setup the SLI memory mapped regions to allow access to PCIe by the cores
+ * using addresses returned by bdk_pcie_get_base_address().
+ *
+ * @param node Node to configure
+ * @param pcie_port PCIe port to configure
+ */
+static void __bdk_pcie_sli_initialize(bdk_node_t node, int pcie_port)
+{
+ int sli;
+ int sli_group;
+ __bdk_pcie_get_sli(node, pcie_port, &sli, &sli_group);
+
+ /* Setup store merge timer */
+ BDK_CSR_MODIFY(c, node, BDK_SLIX_S2M_CTL(sli),
+ c.s.max_word = 0; /* Allow 16 words to combine */
+ c.s.timer = 50); /* Wait up to 50 cycles for more data */
+
+ /* There are 256 regions per SLI. We need four regions per PCIe port to
+ support config, IO, normal, and prefetchable regions. The 256 regions
+ are shared across PCIe, so we need three groups of these (one group
+ for each PCIe). The setup is:
+ SLI bit[7:6]: PCIe port, relative to SLI (max of 4)
+ SLI bit[5:4]: Region. See bdk_pcie_mem_t enumeration
+ SLI bit[3:0]: Address extension from 32 bits to 36 bits
+ */
+ for (bdk_pcie_mem_t mem_region = BDK_PCIE_MEM_CONFIG; mem_region <= BDK_PCIE_MEM_IO; mem_region++)
+ {
+ /* Use top two bits for PCIe port, next two bits for memory region */
+ int sli_region = sli_group << 6;
+ /* Use next two bits for mem region type */
+ sli_region |= mem_region << 4;
+ /* Figure out the hardware setting for each region */
+ int ctype = 3;
+ int nmerge = 1;
+ int ordering = 0;
+ switch (mem_region)
+ {
+ case BDK_PCIE_MEM_CONFIG: /* Config space */
+ ctype = 1; /* Config space */
+ nmerge = 1; /* No merging allowed */
+ ordering = 0; /* NO "relaxed ordering" or "no snoop" */
+ break;
+ case BDK_PCIE_MEM_NORMAL: /* Memory, not prefetchable */
+ ctype = 0; /* Memory space */
+ nmerge = 1; /* No merging allowed */
+ ordering = 0; /* NO "relaxed ordering" or "no snoop" */
+ break;
+ case BDK_PCIE_MEM_PREFETCH: /* Memory, prefetchable */
+ ctype = 0; /* Memory space */
+ nmerge = 0; /* Merging allowed */
+ ordering = 1; /* Yes "relaxed ordering" and "no snoop" */
+ break;
+ case BDK_PCIE_MEM_IO: /* IO */
+ ctype = 2; /* I/O space */
+ nmerge = 1; /* No merging allowed */
+ ordering = 0; /* NO "relaxed ordering" or "no snoop" */
+ break;
+ }
+ /* Use the lower order bits to work as an address extension, allowing
+ each PCIe port to map a total of 36 bits (32bit each region, 16
+ regions) */
+ int epf = sli_group;
+ if (CAVIUM_IS_MODEL(CAVIUM_CN83XX) || CAVIUM_IS_MODEL(CAVIUM_CN81XX)) {
+ BDK_CSR_INIT(lmac_const0,node,BDK_SLIX_LMAC_CONST0X(sli,pcie_port));
+ epf = lmac_const0.s.epf;
+ }
+ for (int r = sli_region; r < sli_region + 16; r++)
+ {
+ uint64_t address = 0;
+ /* Address only applies to memory space */
+ if (mem_region == BDK_PCIE_MEM_NORMAL)
+ {
+ /* Normal starts at bus address 0 */
+ address = r - sli_region;
+ } else if (mem_region == BDK_PCIE_MEM_PREFETCH)
+ {
+ /* Normal starts at bus address 0x10.0000.0000 */
+ address = r - sli_region + 16;
+ }
+ BDK_CSR_MODIFY(c, node, BDK_SLIX_S2M_REGX_ACC(sli, r),
+ c.s.ctype = ctype;
+ c.s.zero = 0;
+ c.cn83xx.epf = epf; /* Superimposed onto c.cn81xx.mac. EPF value works for both */
+ c.s.nmerge = nmerge;
+ c.s.wtype = ordering;
+ c.s.rtype = ordering;
+ c.s.ba = address);
+ }
+ }
+
+ /* Setup MAC control */
+ BDK_CSR_MODIFY(c, node, BDK_SLIX_M2S_MACX_CTL(sli, sli_group),
+ c.s.waitl_com = 1; /* Improves ordering in Ali flash testing */
+ c.s.ctlp_ro = 1;
+ c.s.ptlp_ro = 1;
+ c.s.wind_d = 1;
+ c.s.bar0_d = 1;
+ c.s.wait_com = (bdk_config_get_int(BDK_CONFIG_PCIE_ORDERING) == 1));
+}
+
+
+/**
+ * Perform a complete PCIe RC reset. This is documented in the HRM as issuing a
+ * fundamental reset
+ *
+ * @param node Node to reset
+ * @param pcie_port PCIe port to reset
+ *
+ * @return Zero on success, negative on failure
+ */
+static int __bdk_pcie_rc_reset(bdk_node_t node, int pcie_port)
+{
+ /* Find which QLM/DLM is associated with this PCIe port */
+ int qlm = bdk_qlm_get_qlm_num(node, BDK_IF_PCIE, pcie_port, 0);
+ if (qlm < 0)
+ return -1;
+
+ /* Check if this PCIe port combines two QLM/DLM */
+ BDK_CSR_INIT(pemx_cfg, node, BDK_PEMX_CFG(pcie_port));
+ int is_dual = CAVIUM_IS_MODEL(CAVIUM_CN81XX) ? pemx_cfg.cn81xx.lanes4 : pemx_cfg.cn83xx.lanes8;
+
+ BDK_TRACE(PCIE, "N%d.PCIe%d: Performing PCIe fundamental reset\n", node, pcie_port);
+
+ /* Host software may want to issue a fundamental reset to the PCIe bus.
+ Software should perform the following steps:
+ 1. Write PEM(0..1)_ON[PEMON] = 0. */
+ BDK_CSR_MODIFY(c, node, BDK_PEMX_ON(pcie_port),
+ c.s.pemon = 0);
+ /* 2. Write RST_SOFT_PRST(0..3)[SOFT_PRST] = 1.
+ - This reassertion of [SOFT_PRST] causes the chip to drive PERSTn_L
+ low (if RST_CTL(0..3)[RST_DRV] = 1). */
+ BDK_CSR_MODIFY(c, node, BDK_RST_SOFT_PRSTX(pcie_port),
+ c.s.soft_prst = 1);
+ /* 3. Read RST_SOFT_PRST(0..3). This ensures the PCIe bus is now in reset.
+ - Note that PCIERCn_CFGn registers cannot be accessed when
+ RST_SOFT_PRST(0..3)[SOFT_PRST] = 1. */
+ BDK_CSR_READ(node, BDK_RST_SOFT_PRSTX(pcie_port));
+ /* 4. Write GSER(0..8)_PHY_CTL[PHY_RESET] = 1.
+ - This puts the PHY in reset. */
+ BDK_CSR_MODIFY(c, node, BDK_GSERX_PHY_CTL(qlm),
+ c.s.phy_reset = 1);
+ if (is_dual)
+ BDK_CSR_MODIFY(c, node, BDK_GSERX_PHY_CTL(qlm + 1),
+ c.s.phy_reset = 1);
+ /* Wait 10 us before proceeding to step 5. */
+ bdk_wait_usec(10);
+ /* 5. Write GSERx_PHY_CTL[PHY_RESET] = 0 */
+ BDK_CSR_MODIFY(c, node, BDK_GSERX_PHY_CTL(qlm),
+ c.s.phy_reset = 0);
+ if (is_dual)
+ BDK_CSR_MODIFY(c, node, BDK_GSERX_PHY_CTL(qlm + 1),
+ c.s.phy_reset = 0);
+
+ /* Turn on PEM clocks */
+ if (CAVIUM_IS_MODEL(CAVIUM_CN83XX))
+ BDK_CSR_MODIFY(c, node, BDK_PEMX_CLK_EN(pcie_port),
+ c.cn83xx.pceclk_gate = 0;
+ c.cn83xx.csclk_gate = 0);
+
+ /* 6. Wait 2 ms or more before taking the PCIe port out of reset. */
+ bdk_wait_usec(2000);
+
+ /* To take PCIe port out of reset, perform the following steps: */
+ /* 1. Write PEM(0..1)_ON[PEMON] = 1. */
+ BDK_CSR_MODIFY(c, node, BDK_PEMX_ON(pcie_port),
+ c.s.pemon = 1);
+ /* 2. Write RST_SOFT_PRST(0..3)[SOFT_PRST] = 0. */
+ /* 3. After RST_CTL(0..3)[RST_DONE], perform any configuration as the
+ PCIe MAC has been reset. Set the PEM(0..1)_CTL_STATUS[LNK_ENB] = 1. */
+ /* These steps are executed when we bring the link up. See
+ bdk_pcie_rc_initialize() */
+ return 0;
+}
+
+/**
+ * Before PCIe link can be brought up a number of steps must be performed to
+ * reset the PEM, take the PEM out of reset, initialize the PEM, initialize
+ * RC config space, and initialize SLI. These steps must be performed every
+ * time the PEM is reset, which may be repeated if the PCIe link doesn't come
+ * up at the desired speed and width.
+ *
+ * @param node Node to initialize
+ * @param pcie_port PCIe port to initialize
+ *
+ * @return Zero on success, negative on failure
+ */
+static int __bdk_pcie_rc_pre_link_init(bdk_node_t node, int pcie_port)
+{
+ /* Make sure the PEM and GSER do a full reset before starting PCIe */
+ if (__bdk_pcie_rc_reset(node, pcie_port))
+ {
+ bdk_error("N%d.PCIe%d: Reset failed.\n", node, pcie_port);
+ return -1;
+ }
+
+ /* Bring the PCIe out of reset */
+ BDK_TRACE(PCIE, "N%d.PCIe%d: Taking port out of reset\n", node, pcie_port);
+ BDK_CSR_WRITE(node, BDK_RST_SOFT_PRSTX(pcie_port), 0);
+
+ /* Check and make sure PCIe came out of reset. If it doesn't the board
+ probably hasn't wired the clocks up and the interface should be
+ skipped */
+ BDK_TRACE(PCIE, "N%d.PCIe%d: Waiting for reset to complete\n", node, pcie_port);
+ if (BDK_CSR_WAIT_FOR_FIELD(node, BDK_RST_CTLX(pcie_port), rst_done, ==, 1, 10000))
+ {
+ printf("N%d.PCIe%d: Stuck in reset, skipping.\n", node, pcie_port);
+ return -1;
+ }
+
+ /* Check BIST status */
+ BDK_TRACE(PCIE, "N%d.PCIe%d: Checking BIST\n", node, pcie_port);
+ BDK_CSR_INIT(pemx_bist_status, node, BDK_PEMX_BIST_STATUS(pcie_port));
+ if (pemx_bist_status.u)
+ bdk_warn("N%d.PCIe%d: BIST FAILED (0x%016llx)\n", node, pcie_port, pemx_bist_status.u);
+
+ /* Initialize the config space CSRs */
+ BDK_TRACE(PCIE, "N%d.PCIe%d: Setting up internal config space\n", node, pcie_port);
+ __bdk_pcie_rc_initialize_config_space(node, pcie_port);
+
+ /* Enable gen2 speed selection */
+ BDK_TRACE(PCIE, "N%d.PCIe%d: Enabling dynamic speed changes\n", node, pcie_port);
+ BDK_CSR_MODIFY(c, node, BDK_PCIERCX_CFG515(pcie_port),
+ c.s.dsc = 1);
+
+ /* Setup the SLI windows to allow access to this PCIe from the core */
+ BDK_TRACE(PCIE, "N%d.PCIe%d: Initializing SLI\n", node, pcie_port);
+ __bdk_pcie_sli_initialize(node, pcie_port);
+ return 0;
+}
+
+/**
+ * Initialize a PCIe port for use in host(RC) mode. It doesn't
+ * enumerate the bus.
+ *
+ * @param pcie_port PCIe port to initialize
+ *
+ * @return Zero on success
+ */
+int bdk_pcie_rc_initialize(bdk_node_t node, int pcie_port)
+{
+ const int MAX_RETRIES = 2; /* Total of 3 attempts: First + 2 retries */
+ int retry_count = 0;
+ int result= -1,i;
+ bdk_pemx_bar1_indexx_t bar1_idx;
+
+ /* Make sure we aren't trying to setup a target mode interface in host
+ mode. Sadly this bit is RAZ for CN88XX and CN81XX because the hardware
+ team removed it. So much for backward compatibility */
+ BDK_CSR_INIT(pemx_cfg, node, BDK_PEMX_CFG(pcie_port));
+ int host_mode = CAVIUM_IS_MODEL(CAVIUM_CN83XX) ? pemx_cfg.cn83xx.hostmd : 1;
+ if (!host_mode)
+ {
+ printf("N%d.PCIe%d: Port in endpoint mode.\n", node, pcie_port);
+ return -1;
+ }
+
+ while (retry_count <= MAX_RETRIES)
+ {
+ if (retry_count)
+ BDK_TRACE(PCIE, "N%d.PCIe%d: Starting link retry %d\n", node, pcie_port, retry_count);
+ /* Perform init that must be done after PEM reset, but before link */
+ if (__bdk_pcie_rc_pre_link_init(node, pcie_port))
+ return -1;
+
+ if (retry_count == MAX_RETRIES)
+ {
+ BDK_CSR_INIT(pciercx_cfg031, node, BDK_PCIERCX_CFG031(pcie_port));
+ /* Drop speed to gen2 if link bouncing */
+ /* Result =-1 PEM in reset */
+ /* Result = 0: link speed and width ok no retry needed */
+ /* Result = 1: Link errors or speed change needed */
+ /* Result = 2: lane width error */
+ if ((pciercx_cfg031.s.mls == 3) && (result != 2))
+ {
+ BDK_TRACE(PCIE, "N%d.PCIe%d: Dropping speed to gen2\n", node, pcie_port);
+ pciercx_cfg031.s.mls = 2;
+ BDK_CSR_WRITE(node, BDK_PCIERCX_CFG031(pcie_port), pciercx_cfg031.u);
+ /* Set the target link speed */
+ BDK_CSR_MODIFY(c, node, BDK_PCIERCX_CFG040(pcie_port),
+ c.s.tls = 2);
+ }
+ }
+ /* Bring the link up */
+ result = __bdk_pcie_rc_initialize_link(node, pcie_port);
+ if (result == 0)
+ {
+ BDK_TRACE(PCIE, "N%d.PCIe%d: Link does not need a retry\n", node, pcie_port);
+ break;
+ }
+ else if (result > 0)
+ {
+ if (retry_count >= MAX_RETRIES)
+ {
+ BDK_TRACE(PCIE, "N%d.PCIe%d: Link requested a retry, but hit the max retries\n", node, pcie_port);
+ /* If the link is down, report failure */
+ BDK_CSR_INIT(pciercx_cfg032, node, BDK_PCIERCX_CFG032(pcie_port));
+ bool link_up = (pciercx_cfg032.s.dlla && !pciercx_cfg032.s.lt);
+ if (!link_up)
+ result = -1;
+ }
+ else
+ BDK_TRACE(PCIE, "N%d.PCIe%d: Link requested a retry\n", node, pcie_port);
+ }
+ if (result < 0)
+ {
+ int ltssm_state = __bdk_pcie_rc_get_ltssm_state(node, pcie_port);
+ printf("N%d.PCIe%d: Link timeout, probably the slot is empty (LTSSM %s)\n",
+ node, pcie_port, ltssm_string(ltssm_state));
+ return -1;
+ }
+ retry_count++;
+ }
+
+ /* Errata PCIE-28816: Link retrain initiated at GEN1 can cause PCIE
+ link to hang. For Gen1 links we must disable equalization */
+ BDK_CSR_INIT(pciercx_cfg032, node, BDK_PCIERCX_CFG032(pcie_port));
+ if (pciercx_cfg032.s.ls == 1)
+ {
+ BDK_TRACE(PCIE, "N%d.PCIe%d: Disabling equalization for Gen1 link\n", node, pcie_port);
+ BDK_CSR_MODIFY(c, node, BDK_PCIERCX_CFG548(pcie_port),
+ c.s.ed = 1);
+ }
+
+ BDK_TRACE(PCIE, "N%d.PCIe%d: Setting up internal BARs\n", node, pcie_port);
+ /* Disable BAR0 */
+ BDK_CSR_WRITE(node, BDK_PEMX_P2N_BAR0_START(pcie_port), -1);
+ /* BAR1 Starting at address 0 */
+ BDK_CSR_WRITE(node, BDK_PEMX_P2N_BAR1_START(pcie_port), 0);
+ /* Set BAR2 to cover all memory starting at address 0 */
+ BDK_CSR_WRITE(node, BDK_PEMX_P2N_BAR2_START(pcie_port), 0);
+ /* Setup BAR attributes */
+ BDK_CSR_MODIFY(c, node, BDK_PEMX_BAR_CTL(pcie_port),
+ c.cn83xx.bar1_siz = 1; /* 64MB BAR1 */
+ c.s.bar2_enb = 1; /* BAR2 is enabled */
+ c.s.bar2_cax = 0); /* Cache in L2 */
+
+ /* Allow devices that truncate the bus address to 32-bits to reach the GITS_TRANSLATER */
+ bar1_idx.u = 0;
+ bar1_idx.s.addr_idx = bdk_numa_get_address(node, BDK_GITS_TRANSLATER) >> 22;
+ bar1_idx.s.addr_v = 1;
+
+ BDK_CSR_WRITE(node, BDK_PEMX_BAR1_INDEXX(pcie_port, 0), bar1_idx.u);
+
+ /* The rest of the windows map linearly to match the BAR2 translation. */
+ for (i = 1; i < 16; i++)
+ {
+ bar1_idx.s.addr_idx = i;
+ BDK_CSR_WRITE(node, BDK_PEMX_BAR1_INDEXX(pcie_port, i), bar1_idx.u);
+ }
+
+ /* Display the link status */
+ printf("N%d.PCIe%d: Link active, %d lanes, speed gen%d\n",
+ node, pcie_port, pciercx_cfg032.s.nlw, pciercx_cfg032.s.ls);
+
+ return 0;
+
+}
+
+/**
+ * Return PCIe state
+ *
+ * @param pcie_port PCIe port to query
+ *
+ * @return True if port is up and running
+ */
+int bdk_pcie_is_running(bdk_node_t node, int pcie_port)
+{
+ BDK_CSR_INIT(pemx_on, node, BDK_PEMX_ON(pcie_port));
+ BDK_CSR_INIT(rst_soft_prstx, node, BDK_RST_SOFT_PRSTX(pcie_port));
+ BDK_CSR_INIT(pciercx_cfg032, node, BDK_PCIERCX_CFG032(pcie_port));
+
+ if (!pemx_on.s.pemon || rst_soft_prstx.s.soft_prst)
+ return 0;
+
+ return bdk_config_get_int(BDK_CONFIG_PCIE_SKIP_LINK_TRAIN, node, pcie_port) ||
+ (pciercx_cfg032.s.dlla && !pciercx_cfg032.s.lt);
+}
+
+/**
+ * Shutdown a PCIe port and put it in reset
+ *
+ * @param pcie_port PCIe port to shutdown
+ *
+ * @return Zero on success
+ */
+int bdk_pcie_rc_shutdown(bdk_node_t node, int pcie_port)
+{
+ /* Check that the controller is out of reset */
+ BDK_CSR_INIT(rst_ctlx, node, BDK_RST_CTLX(pcie_port));
+ if (!rst_ctlx.s.rst_done)
+ goto skip_idle_wait;
+
+ /* Check if link is up */
+ BDK_CSR_INIT(pciercx_cfg032, node, BDK_PCIERCX_CFG032(pcie_port));
+ if ((pciercx_cfg032.s.dlla == 0) || (pciercx_cfg032.s.lt == 1))
+ goto skip_idle_wait;
+#if 0 // FIXME
+ /* Wait for all pending operations to complete */
+ if (BDK_CSR_WAIT_FOR_FIELD(node, BDK_PEMX_CPL_LUT_VALID(pcie_port), tag, ==, 0, 2000))
+ printf("N%d.PCIe%d: Shutdown timeout\n", node, pcie_port);
+#endif
+skip_idle_wait:
+ /* Bring down the link */
+ BDK_CSR_MODIFY(c, node, BDK_PEMX_CTL_STATUS(pcie_port), c.cn83xx.lnk_enb = 0);
+ /* Force reset */
+ __bdk_pcie_rc_reset(node, pcie_port);
+ return 0;
+}
+
+/**
+ * @INTERNAL
+ * Build a PCIe config space request address for a device
+ *
+ * @param pcie_port PCIe port to access
+ * @param bus Sub bus
+ * @param dev Device ID
+ * @param fn Device sub function
+ * @param reg Register to access
+ *
+ * @return 64bit IO address
+ */
+uint64_t pcie_build_config_addr(bdk_node_t node, int pcie_port, int bus, int dev, int fn, int reg)
+{
+ int num_pems = bdk_pcie_get_num_ports(node);
+ if (pcie_port < num_pems)
+ {
+ /* Errata (SLI-22555) ECAM to off-chip PCI misroutes address. Use
+ the SLI regions instead of ECAMs for config space access */
+ uint64_t address = bdk_pcie_get_base_address(node, pcie_port, BDK_PCIE_MEM_CONFIG);
+ /* Display the link status */
+ address += (uint64_t)bus << 24; /* Bus is bits 31:24 */
+ address += dev << 19; /* device+func is bits 23:16 */
+ address += fn << 16;
+ address += reg; /* Offset is bits 11:0 */
+ return address;
+ }
+ else if (pcie_port >= 100)
+ {
+ bdk_device_t device;
+ memset(&device, 0, sizeof(device));
+ device.node = node;
+ device.ecam = pcie_port - 100;
+ device.bus = bus;
+ device.dev = dev;
+ device.func = fn;
+ return __bdk_ecam_build_address(&device, reg);
+ }
+ return 0;
+}
diff --git a/src/vendorcode/cavium/bdk/libbdk-hal/bdk-pcie.c b/src/vendorcode/cavium/bdk/libbdk-hal/bdk-pcie.c
new file mode 100644
index 0000000000..769550d6b2
--- /dev/null
+++ b/src/vendorcode/cavium/bdk/libbdk-hal/bdk-pcie.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-hal/bdk-pcie.h"
+#include "libbdk-hal/bdk-utils.h"
+#include "libbdk-hal/if/bdk-if.h"
+
+/* This code is an optional part of the BDK. It is only linked in
+ if BDK_REQUIRE() needs it */
+BDK_REQUIRE_DEFINE(PCIE);
+
+/**
+ * Read 8bits from a Device's config space
+ *
+ * @param pcie_port PCIe port the device is on
+ * @param bus Sub bus
+ * @param dev Device ID
+ * @param fn Device sub function
+ * @param reg Register to access
+ *
+ * @return Result of the read
+ */
+uint8_t bdk_pcie_config_read8(bdk_node_t node, int pcie_port, int bus, int dev, int fn, int reg)
+{
+ uint64_t address = pcie_build_config_addr(node, pcie_port, bus, dev, fn, reg);
+ BDK_TRACE(PCIE_CONFIG, "N%d.PCIe%d: Config Read8(bus=%d, dev=%d, fn=%d, reg=0x%x, internal=0x%llx)\n",
+ node, pcie_port, bus, dev, fn, reg, address);
+ uint8_t result;
+ if (address)
+ result = bdk_read64_uint8(address);
+ else
+ result = 0xff;
+ BDK_TRACE(PCIE_CONFIG, "N%d.PCIe%d: Result=0x%02x\n", node, pcie_port, result);
+ return result;
+}
+
+
+/**
+ * Read 16bits from a Device's config space
+ *
+ * @param pcie_port PCIe port the device is on
+ * @param bus Sub bus
+ * @param dev Device ID
+ * @param fn Device sub function
+ * @param reg Register to access
+ *
+ * @return Result of the read
+ */
+uint16_t bdk_pcie_config_read16(bdk_node_t node, int pcie_port, int bus, int dev, int fn, int reg)
+{
+ uint64_t address = pcie_build_config_addr(node, pcie_port, bus, dev, fn, reg);
+ BDK_TRACE(PCIE_CONFIG, "N%d.PCIe%d: Config Read16(bus=%d, dev=%d, fn=%d, reg=0x%x, internal=0x%llx)\n",
+ node, pcie_port, bus, dev, fn, reg, address);
+ uint16_t result;
+ if (address)
+ result = bdk_le16_to_cpu(bdk_read64_uint16(address));
+ else
+ result = 0xffff;
+ BDK_TRACE(PCIE_CONFIG, "N%d.PCIe%d: Result=0x%04x\n", node, pcie_port, result);
+ return result;
+}
+
+
+/**
+ * Read 32bits from a Device's config space
+ *
+ * @param pcie_port PCIe port the device is on
+ * @param bus Sub bus
+ * @param dev Device ID
+ * @param fn Device sub function
+ * @param reg Register to access
+ *
+ * @return Result of the read
+ */
+uint32_t bdk_pcie_config_read32(bdk_node_t node, int pcie_port, int bus, int dev, int fn, int reg)
+{
+ uint64_t address = pcie_build_config_addr(node, pcie_port, bus, dev, fn, reg);
+ BDK_TRACE(PCIE_CONFIG, "N%d.PCIe%d: Config Read32(bus=%d, dev=%d, fn=%d, reg=0x%x, internal=0x%llx)\n",
+ node, pcie_port, bus, dev, fn, reg, address);
+
+ uint32_t result;
+ if (address)
+ result = bdk_le32_to_cpu(bdk_read64_uint32(address));
+ else
+ result = 0xffffffff;
+ BDK_TRACE(PCIE_CONFIG, "N%d.PCIe%d: Result=0x%08x\n", node, pcie_port, result);
+
+ /* Errata ECAM-22630: CN88XX pass 1.x, except pass 1.0, will return zero
+ for non-existent devices instead of ones. We look for this special case
+ for 32bit reads for reg=0 so we can scan device properly */
+ if (CAVIUM_IS_MODEL(CAVIUM_CN88XX_PASS1_X) && (reg == 0) && (result == 0))
+ result = 0xffffffff;
+
+ return result;
+}
+
+
+/**
+ * Write 8bits to a Device's config space
+ *
+ * @param pcie_port PCIe port the device is on
+ * @param bus Sub bus
+ * @param dev Device ID
+ * @param fn Device sub function
+ * @param reg Register to access
+ * @param val Value to write
+ */
+void bdk_pcie_config_write8(bdk_node_t node, int pcie_port, int bus, int dev, int fn, int reg, uint8_t val)
+{
+ uint64_t address = pcie_build_config_addr(node, pcie_port, bus, dev, fn, reg);
+ BDK_TRACE(PCIE_CONFIG, "N%d.PCIe%d: Config Write8(bus=%d, dev=%d, fn=%d, reg=0x%x, val=0x%02x, internal=0x%llx)\n",
+ node, pcie_port, bus, dev, fn, reg, val, address);
+ if (address)
+ bdk_write64_uint8(address, val);
+}
+
+
+/**
+ * Write 16bits to a Device's config space
+ *
+ * @param pcie_port PCIe port the device is on
+ * @param bus Sub bus
+ * @param dev Device ID
+ * @param fn Device sub function
+ * @param reg Register to access
+ * @param val Value to write
+ */
+void bdk_pcie_config_write16(bdk_node_t node, int pcie_port, int bus, int dev, int fn, int reg, uint16_t val)
+{
+ uint64_t address = pcie_build_config_addr(node, pcie_port, bus, dev, fn, reg);
+ BDK_TRACE(PCIE_CONFIG, "N%d.PCIe%d: Config Write16(bus=%d, dev=%d, fn=%d, reg=0x%x, val=0x%04x, internal=0x%llx)\n",
+ node, pcie_port, bus, dev, fn, reg, val, address);
+ if (address)
+ bdk_write64_uint16(address, bdk_cpu_to_le16(val));
+}
+
+
+/**
+ * Write 32bits to a Device's config space
+ *
+ * @param pcie_port PCIe port the device is on
+ * @param bus Sub bus
+ * @param dev Device ID
+ * @param fn Device sub function
+ * @param reg Register to access
+ * @param val Value to write
+ */
+void bdk_pcie_config_write32(bdk_node_t node, int pcie_port, int bus, int dev, int fn, int reg, uint32_t val)
+{
+ uint64_t address = pcie_build_config_addr(node, pcie_port, bus, dev, fn, reg);
+ BDK_TRACE(PCIE_CONFIG, "N%d.PCIe%d: Config Write32(bus=%d, dev=%d, fn=%d, reg=0x%x, val=0x%08x, internal=0x%llx)\n",
+ node, pcie_port, bus, dev, fn, reg, val, address);
+ if (address)
+ bdk_write64_uint32(address, bdk_cpu_to_le32(val));
+}
+
+/**
+ * Read 64bits from PCIe using a memory transaction
+ *
+ * @param node Node to read from
+ * @param pcie_port PCIe port to read
+ * @param address PCIe address to read
+ *
+ * @return Result of the read
+ */
+uint64_t bdk_pcie_mem_read64(bdk_node_t node, int pcie_port, uint64_t address)
+{
+ uint64_t base_address = bdk_pcie_get_base_address(node, pcie_port, BDK_PCIE_MEM_NORMAL);
+ return bdk_read64_uint64(base_address + address);
+}
+
+/**
+ * Write 64bits to PCIe memory
+ *
+ * @param node Node to write to
+ * @param pcie_port PCIe port to use
+ * @param address Address to write
+ * @param data Data to write
+ */
+void bdk_pcie_mem_write64(bdk_node_t node, int pcie_port, uint64_t address, uint64_t data)
+{
+ uint64_t base_address = bdk_pcie_get_base_address(node, pcie_port, BDK_PCIE_MEM_NORMAL);
+ bdk_write64_uint64(base_address + address, data);
+}
+
diff --git a/src/vendorcode/cavium/bdk/libbdk-hal/bdk-qlm.c b/src/vendorcode/cavium/bdk/libbdk-hal/bdk-qlm.c
new file mode 100644
index 0000000000..f7d631fb5b
--- /dev/null
+++ b/src/vendorcode/cavium/bdk/libbdk-hal/bdk-qlm.c
@@ -0,0 +1,423 @@
+/***********************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 <string.h>
+#include "libbdk-arch/bdk-csrs-gser.h"
+#include "libbdk-arch/bdk-csrs-gsern.h"
+#include "libbdk-hal/if/bdk-if.h"
+#include "libbdk-hal/bdk-qlm.h"
+#include "libbdk-hal/qlm/bdk-qlm-common.h"
+
+/* This code is an optional part of the BDK. It is only linked in
+ if BDK_REQUIRE() needs it */
+BDK_REQUIRE_DEFINE(QLM);
+
+/**
+ * Convert a mode into a configuration variable string value
+ *
+ * @param mode Mode to convert
+ *
+ * @return configuration value string
+ */
+const char *bdk_qlm_mode_to_cfg_str(bdk_qlm_modes_t mode)
+{
+#define MODE_CASE(m) case m: return #m+13
+ switch (mode)
+ {
+ MODE_CASE(BDK_QLM_MODE_DISABLED);
+ MODE_CASE(BDK_QLM_MODE_PCIE_1X1);
+ MODE_CASE(BDK_QLM_MODE_PCIE_2X1);
+ MODE_CASE(BDK_QLM_MODE_PCIE_1X2);
+ MODE_CASE(BDK_QLM_MODE_PCIE_1X4);
+ MODE_CASE(BDK_QLM_MODE_PCIE_1X8);
+ MODE_CASE(BDK_QLM_MODE_PCIE_1X16);
+
+ MODE_CASE(BDK_QLM_MODE_SATA_4X1);
+ MODE_CASE(BDK_QLM_MODE_SATA_2X1);
+
+ MODE_CASE(BDK_QLM_MODE_ILK);
+ MODE_CASE(BDK_QLM_MODE_SGMII_4X1);
+ MODE_CASE(BDK_QLM_MODE_SGMII_2X1);
+ MODE_CASE(BDK_QLM_MODE_SGMII_1X1);
+ MODE_CASE(BDK_QLM_MODE_XAUI_1X4);
+ MODE_CASE(BDK_QLM_MODE_RXAUI_2X2);
+ MODE_CASE(BDK_QLM_MODE_RXAUI_1X2);
+ MODE_CASE(BDK_QLM_MODE_OCI);
+ MODE_CASE(BDK_QLM_MODE_XFI_4X1);
+ MODE_CASE(BDK_QLM_MODE_XFI_2X1);
+ MODE_CASE(BDK_QLM_MODE_XFI_1X1);
+ MODE_CASE(BDK_QLM_MODE_XLAUI_1X4);
+ MODE_CASE(BDK_QLM_MODE_10G_KR_4X1);
+ MODE_CASE(BDK_QLM_MODE_10G_KR_2X1);
+ MODE_CASE(BDK_QLM_MODE_10G_KR_1X1);
+ MODE_CASE(BDK_QLM_MODE_40G_KR4_1X4);
+ MODE_CASE(BDK_QLM_MODE_QSGMII_4X1);
+ MODE_CASE(BDK_QLM_MODE_25G_4X1);
+ MODE_CASE(BDK_QLM_MODE_25G_2X1);
+ MODE_CASE(BDK_QLM_MODE_50G_2X2);
+ MODE_CASE(BDK_QLM_MODE_50G_1X2);
+ MODE_CASE(BDK_QLM_MODE_100G_1X4);
+ MODE_CASE(BDK_QLM_MODE_25G_KR_4X1);
+ MODE_CASE(BDK_QLM_MODE_25G_KR_2X1);
+ MODE_CASE(BDK_QLM_MODE_50G_KR_2X2);
+ MODE_CASE(BDK_QLM_MODE_50G_KR_1X2);
+ MODE_CASE(BDK_QLM_MODE_100G_KR4_1X4);
+ MODE_CASE(BDK_QLM_MODE_USXGMII_4X1);
+ MODE_CASE(BDK_QLM_MODE_USXGMII_2X1);
+
+ case BDK_QLM_MODE_LAST: break; /* fall through error */
+ }
+ return "INVALID_QLM_MODE_VALUE";
+}
+
+/**
+ * Convert a configuration variable value string into a mode
+ *
+ * @param val Configuration variable value
+ *
+ * @return mode
+ */
+bdk_qlm_modes_t bdk_qlm_cfg_string_to_mode(const char *val)
+{
+ bdk_qlm_modes_t mode;
+
+ for (mode = 0; mode < BDK_QLM_MODE_LAST; mode++)
+ {
+ if (0 == strcmp(val, bdk_qlm_mode_to_cfg_str(mode)))
+ {
+ return mode;
+ }
+ }
+ return -1;
+}
+
+/**
+ * Convert a mode into a human understandable string
+ *
+ * @param mode Mode to convert
+ *
+ * @return Easy to read string
+ */
+const char *bdk_qlm_mode_tostring(bdk_qlm_modes_t mode)
+{
+ const char *result = "Unknown, update bdk_qlm_mode_tostring()";
+ switch (mode)
+ {
+ case BDK_QLM_MODE_DISABLED:
+ result = "Disabled";
+ break;
+ case BDK_QLM_MODE_PCIE_1X1:
+ result = "1 PCIe, 1 lane";
+ break;
+ case BDK_QLM_MODE_PCIE_2X1:
+ result = "2 PCIe, 1 lane each";
+ break;
+ case BDK_QLM_MODE_PCIE_1X2:
+ result = "1 PCIe, 2 lanes";
+ break;
+ case BDK_QLM_MODE_PCIE_1X4:
+ result = "1 PCIe, 4 lanes";
+ break;
+ case BDK_QLM_MODE_PCIE_1X8:
+ result = "1 PCIe, 8 lanes";
+ break;
+ case BDK_QLM_MODE_PCIE_1X16:
+ result = "1 PCIe, 16 lanes";
+ break;
+
+ case BDK_QLM_MODE_SATA_4X1:
+ result = "4 SATA, one lane each";
+ break;
+ case BDK_QLM_MODE_SATA_2X1:
+ result = "2 SATA, one lane each";
+ break;
+
+ case BDK_QLM_MODE_ILK:
+ result = "Interlaken";
+ break;
+ case BDK_QLM_MODE_SGMII_4X1:
+ result = "4 SGMII, 1 lane each";
+ break;
+ case BDK_QLM_MODE_SGMII_2X1:
+ result = "2 SGMII, 1 lane each";
+ break;
+ case BDK_QLM_MODE_SGMII_1X1:
+ result = "1 SGMII, 1 lane";
+ break;
+ case BDK_QLM_MODE_XAUI_1X4:
+ result = "1 XAUI, 4 lanes";
+ break;
+ case BDK_QLM_MODE_RXAUI_2X2:
+ result = "2 RXAUI, 2 lanes each";
+ break;
+ case BDK_QLM_MODE_RXAUI_1X2:
+ result = "1 RXAUI, 2 lanes each";
+ break;
+ case BDK_QLM_MODE_OCI:
+ result = "Cavium Coherent Processor Interconnect";
+ break;
+ case BDK_QLM_MODE_XFI_4X1:
+ result = "4 XFI, 1 lane each";
+ break;
+ case BDK_QLM_MODE_XFI_2X1:
+ result = "2 XFI, 1 lane each";
+ break;
+ case BDK_QLM_MODE_XFI_1X1:
+ result = "1 XFI, 1 lane";
+ break;
+ case BDK_QLM_MODE_XLAUI_1X4:
+ result = "1 XLAUI, 4 lanes";
+ break;
+ case BDK_QLM_MODE_10G_KR_4X1:
+ result = "4 10GBASE-KR, 1 lane each";
+ break;
+ case BDK_QLM_MODE_10G_KR_2X1:
+ result = "2 10GBASE-KR, 1 lane each";
+ break;
+ case BDK_QLM_MODE_10G_KR_1X1:
+ result = "1 10GBASE-KR, 1 lane";
+ break;
+ case BDK_QLM_MODE_40G_KR4_1X4:
+ result = "1 40GBASE-KR4, 4 lanes";
+ break;
+ case BDK_QLM_MODE_QSGMII_4X1:
+ result = "4 QSGMII, 1 lane";
+ break;
+ case BDK_QLM_MODE_25G_4X1:
+ result = "4 25G, 1 lane each";
+ break;
+ case BDK_QLM_MODE_25G_2X1:
+ result = "2 25G, 1 lane each";
+ break;
+ case BDK_QLM_MODE_50G_2X2:
+ result = "2 50G, 2 lanes each";
+ break;
+ case BDK_QLM_MODE_50G_1X2:
+ result = "1 50G, 2 lanes";
+ break;
+ case BDK_QLM_MODE_100G_1X4:
+ result = "1 100G, 4 lanes";
+ break;
+ case BDK_QLM_MODE_25G_KR_4X1:
+ result = "4 25G, 1 lane each";
+ break;
+ case BDK_QLM_MODE_25G_KR_2X1:
+ result = "2 25G, 1 lane each";
+ break;
+ case BDK_QLM_MODE_50G_KR_2X2:
+ result = "2 50G, 2 lanes each";
+ break;
+ case BDK_QLM_MODE_50G_KR_1X2:
+ result = "1 50G, 2 lanes";
+ break;
+ case BDK_QLM_MODE_100G_KR4_1X4:
+ result = "1 100G, 4 lanes";
+ break;
+ case BDK_QLM_MODE_USXGMII_4X1:
+ result = "4 USXGMII, 1 lane each";
+ break;
+ case BDK_QLM_MODE_USXGMII_2X1:
+ result = "2 USXGMII, 1 lane each";
+ break;
+
+ case BDK_QLM_MODE_LAST:
+ break; /* fallthrough error */
+ }
+ return result;
+}
+
+int bdk_qlm_measure_clock(bdk_node_t node, int qlm)
+{
+ int ref_clock = __bdk_qlm_measure_refclock(node, qlm);
+ BDK_TRACE(QLM, "N%d.QLM%d: Ref clock %d Hz\n", node, qlm, ref_clock);
+
+ return ref_clock;
+}
+
+/**
+ * Set the QLM's clock source.
+ *
+ * @param node Node to use in a Numa setup
+ * @param qlm QLM to configure
+ * @param clk Clock source for QLM
+ *
+ * @return Zero on success, negative on failure
+ */
+int bdk_qlm_set_clock(bdk_node_t node, int qlm, bdk_qlm_clock_t clk)
+{
+ if (CAVIUM_IS_MODEL(CAVIUM_CN8XXX))
+ {
+ int sel;
+ int com1;
+ switch (clk)
+ {
+ case BDK_QLM_CLK_COMMON_0:
+ sel = 1;
+ com1 = 0;
+ break;
+ case BDK_QLM_CLK_COMMON_1:
+ sel = 1;
+ com1 = 1;
+ break;
+ case BDK_QLM_CLK_EXTERNAL:
+ sel = 0;
+ com1 = 0;
+ break;
+ default:
+ bdk_warn("Unrecognized clock mode %d for QLM%d on node %d.\n",
+ clk, qlm, node);
+ return -1;
+ }
+
+ BDK_CSR_MODIFY(c, node, BDK_GSERX_REFCLK_SEL(qlm),
+ c.s.com_clk_sel = sel;
+ c.s.use_com1 = com1);
+ }
+ else
+ {
+ int cclksel;
+ switch (clk)
+ {
+ case BDK_QLM_CLK_COMMON_0:
+ cclksel = 0;
+ break;
+ case BDK_QLM_CLK_COMMON_1:
+ cclksel = 1;
+ break;
+ case BDK_QLM_CLK_COMMON_2:
+ cclksel = 2;
+ break;
+ case BDK_QLM_CLK_EXTERNAL:
+ cclksel = 3;
+ break;
+ default:
+ bdk_warn("Unrecognized clock mode %d for QLM%d on node %d.\n",
+ clk, qlm, node);
+ return -1;
+ }
+ BDK_CSR_MODIFY(c, node, BDK_GSERNX_COMMON_REFCLK_BCFG(qlm),
+ c.s.pwdn = (clk == BDK_QLM_CLK_EXTERNAL) ? 0 : 1;
+ c.s.cclksel = cclksel);
+ }
+ return 0;
+}
+
+/**
+ * Display an eye diagram for the given QLM lane. The eye data can be in "eye", or
+ * captured during the call if "eye" is NULL.
+ *
+ * @param node Node to use in numa setup
+ * @param qlm QLM to use
+ * @param qlm_lane Which lane
+ * @param format Display format. 0 = raw, 1 = Color ASCII
+ * @param eye Eye data to display, or NULL if the data should be captured.
+ *
+ * @return Zero on success, negative on failure
+ */
+int bdk_qlm_eye_display(bdk_node_t node, int qlm, int qlm_lane, int format, const bdk_qlm_eye_t *eye)
+{
+ int result;
+ int need_free = 0;
+ if (eye == NULL)
+ {
+ bdk_qlm_eye_t *eye_data = malloc(sizeof(bdk_qlm_eye_t));
+ if (eye_data == NULL)
+ {
+ bdk_error("Failed to allocate space for eye\n");
+ return -1;
+ }
+ if (bdk_qlm_eye_capture(node, qlm, qlm_lane, eye_data))
+ return -1;
+ eye = eye_data;
+ }
+
+ /* Calculate the max eye width */
+ int eye_area = 0;
+ int eye_width = 0;
+ for (int y = 0; y < eye->height; y++)
+ {
+ int width = 0;
+ for (int x = 0; x < eye->width; x++)
+ {
+ if (eye->data[y][x] == 0)
+ {
+ width++;
+ eye_area++;
+ }
+ }
+ if (width > eye_width)
+ eye_width = width;
+ }
+
+ /* Calculate the max eye height */
+ int eye_height = 0;
+ for (int x = 0; x < eye->width; x++)
+ {
+ int height = 0;
+ for (int y = 0; y < eye->height; y++)
+ {
+ if (eye->data[y][x] == 0)
+ {
+ height++;
+ eye_area++;
+ }
+ }
+ if (height > eye_height)
+ eye_height = height;
+ }
+
+ printf("\nEye Diagram for Node %d, QLM %d, Lane %d\n", node, qlm, qlm_lane);
+
+ if (format == 0) /* Raw */
+ {
+ for (int y = 0; y < eye->height; y++)
+ {
+ for (int x = 0; x < eye->width; x++)
+ printf("%u\t", eye->data[y][x]);
+ printf("\n");
+ }
+ result = 0;
+ }
+ else
+ result = -1;
+
+ if (need_free)
+ free((void*)eye);
+ return result;
+}
diff --git a/src/vendorcode/cavium/bdk/libbdk-hal/bdk-sata.c b/src/vendorcode/cavium/bdk/libbdk-hal/bdk-sata.c
new file mode 100644
index 0000000000..82e2d3da36
--- /dev/null
+++ b/src/vendorcode/cavium/bdk/libbdk-hal/bdk-sata.c
@@ -0,0 +1,1117 @@
+/***********************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 <malloc.h>
+#include "libbdk-arch/bdk-csrs-sata.h"
+
+/* This code is an optional part of the BDK. It is only linked in
+ if BDK_REQUIRE() needs it */
+BDK_REQUIRE_DEFINE(SATA);
+
+/* Most all information used to create this code was gotten from this wiki
+ page: http://wiki.osdev.org/AHCI */
+
+/**
+ * Following code defines different kinds of FIS specified in Serial
+ * ATA Revision 3.0.
+ */
+typedef enum
+{
+ FIS_TYPE_REG_H2D = 0x27, /**< Register FIS - host to device */
+ FIS_TYPE_REG_D2H = 0x34, /**< Register FIS - device to host */
+ FIS_TYPE_DMA_ACT = 0x39, /**< DMA activate FIS - device to host */
+ FIS_TYPE_DMA_SETUP = 0x41, /**< DMA setup FIS - bidirectional */
+ FIS_TYPE_DATA = 0x46, /**< Data FIS - bidirectional */
+ FIS_TYPE_BIST = 0x58, /**< BIST activate FIS - bidirectional */
+ FIS_TYPE_PIO_SETUP = 0x5F, /**< PIO setup FIS - device to host */
+ FIS_TYPE_DEV_BITS = 0xA1, /**< Set device bits FIS - device to host */
+} fis_type_t;
+
+/**
+ * A host to device register FIS is used by the host to send
+ * command or control to a device. As illustrated in the
+ * following data structure, it contains the IDE registers such
+ * as command, LBA, device, feature, count and control. An ATA
+ * command is constructed in this structure and issued to the
+ * device. All reserved fields in an FIS should be cleared to
+ * zero.
+ */
+typedef struct
+{
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+ // DWORD 0
+ uint8_t fis_type; /**< FIS_TYPE_REG_H2D */
+ uint8_t pmport:4; /**< Port multiplier */
+ uint8_t rsv0:3; /**< Reserved */
+ uint8_t c:1; /**< 1: Command, 0: Control */
+ uint8_t command; /**< Command register */
+ uint8_t featurel; /**< Feature register, 7:0 */
+ // DWORD 1
+ uint8_t lba0; /**< LBA low register, 7:0 */
+ uint8_t lba1; /**< LBA mid register, 15:8 */
+ uint8_t lba2; /**< LBA high register, 23:16 */
+ uint8_t device; /**< Device register */
+ // DWORD 2
+ uint8_t lba3; /**< LBA register, 31:24 */
+ uint8_t lba4; /**< LBA register, 39:32 */
+ uint8_t lba5; /**< LBA register, 47:40 */
+ uint8_t featureh; /**< Feature register, 15:8 */
+ // DWORD 3
+ uint16_t count; /**< Count register */
+ uint8_t icc; /**< Isochronous command completion */
+ uint8_t control; /**< Control register */
+ // DWORD 4
+ uint8_t rsv1[4]; /**< Reserved */
+#else
+ // DWORD 0
+ uint8_t fis_type; /**< FIS_TYPE_REG_H2D */
+ uint8_t c:1; /**< 1: Command, 0: Control */
+ uint8_t rsv0:3; /**< Reserved */
+ uint8_t pmport:4; /**< Port multiplier */
+ uint8_t command; /**< Command register */
+ uint8_t featurel; /**< Feature register, 7:0 */
+ // DWORD 1
+ uint8_t lba0; /**< LBA low register, 7:0 */
+ uint8_t lba1; /**< LBA mid register, 15:8 */
+ uint8_t lba2; /**< LBA high register, 23:16 */
+ uint8_t device; /**< Device register */
+ // DWORD 2
+ uint8_t lba3; /**< LBA register, 31:24 */
+ uint8_t lba4; /**< LBA register, 39:32 */
+ uint8_t lba5; /**< LBA register, 47:40 */
+ uint8_t featureh; /**< Feature register, 15:8 */
+ // DWORD 3
+ uint16_t count; /**< Count register */
+ uint8_t icc; /**< Isochronous command completion */
+ uint8_t control; /**< Control register */
+ // DWORD 4
+ uint8_t rsv1[4]; /**< Reserved */
+#endif
+} fis_reg_h2d_t;
+
+/**
+ * A device to host register FIS is used by the device to notify
+ * the host that some ATA register has changed. It contains the
+ * updated task files such as status, error and other registers.
+ */
+typedef struct
+{
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+ // DWORD 0
+ uint8_t fis_type; /**< FIS_TYPE_REG_D2H */
+ uint8_t pmport:4; /**< Port multiplier */
+ uint8_t rsv0:2; /**< Reserved */
+ uint8_t i:1; /**< Interrupt bit */
+ uint8_t rsv1:1; /**< Reserved */
+ uint8_t status; /**< Status register */
+ uint8_t error; /**< Error register */
+ // DWORD 1
+ uint8_t lba0; /**< LBA low register, 7:0 */
+ uint8_t lba1; /**< LBA mid register, 15:8 */
+ uint8_t lba2; /**< LBA high register, 23:16 */
+ uint8_t device; /**< Device register */
+ // DWORD 2
+ uint8_t lba3; /**< LBA register, 31:24 */
+ uint8_t lba4; /**< LBA register, 39:32 */
+ uint8_t lba5; /**< LBA register, 47:40 */
+ uint8_t rsv2; /**< Reserved */
+ // DWORD 3
+ uint8_t countl; /**< Count register, 7:0 */
+ uint8_t counth; /**< Count register, 15:8 */
+ uint8_t rsv3[2]; /**< Reserved */
+ // DWORD 4
+ uint8_t rsv4[4]; /**< Reserved */
+#else
+ // DWORD 0
+ uint8_t fis_type; /**< FIS_TYPE_REG_D2H */
+ uint8_t rsv1:1; /**< Reserved */
+ uint8_t i:1; /**< Interrupt bit */
+ uint8_t rsv0:2; /**< Reserved */
+ uint8_t pmport:4; /**< Port multiplier */
+ uint8_t status; /**< Status register */
+ uint8_t error; /**< Error register */
+ // DWORD 1
+ uint8_t lba0; /**< LBA low register, 7:0 */
+ uint8_t lba1; /**< LBA mid register, 15:8 */
+ uint8_t lba2; /**< LBA high register, 23:16 */
+ uint8_t device; /**< Device register */
+ // DWORD 2
+ uint8_t lba3; /**< LBA register, 31:24 */
+ uint8_t lba4; /**< LBA register, 39:32 */
+ uint8_t lba5; /**< LBA register, 47:40 */
+ uint8_t rsv2; /**< Reserved */
+ // DWORD 3
+ uint8_t countl; /**< Count register, 7:0 */
+ uint8_t counth; /**< Count register, 15:8 */
+ uint8_t rsv3[2]; /**< Reserved */
+ // DWORD 4
+ uint8_t rsv4[4]; /**< Reserved */
+#endif
+} fis_reg_d2h_t;
+
+/**
+ * This FIS is used by the host or device to send data payload.
+ * The data size can be varied.
+ */
+typedef struct
+{
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+ // DWORD 0
+ uint8_t fis_type; /**< FIS_TYPE_DATA */
+ uint8_t pmport:4; /**< Port multiplier */
+ uint8_t rsv0:4; /**< Reserved */
+ uint8_t rsv1[2]; /**< Reserved */
+ // DWORD 1 ~ N
+ uint32_t data[1]; /**< Payload */
+#else
+ // DWORD 0
+ uint8_t fis_type; /**< FIS_TYPE_DATA */
+ uint8_t rsv0:4; /**< Reserved */
+ uint8_t pmport:4; /**< Port multiplier */
+ uint8_t rsv1[2]; /**< Reserved */
+ // DWORD 1 ~ N
+ uint32_t data[1]; /**< Payload */
+#endif
+} fis_data_t;
+
+/**
+ * This FIS is used by the device to tell the host that it's
+ * about to send or ready to receive a PIO data payload.
+ */
+typedef struct
+{
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+ // DWORD 0
+ uint8_t fis_type; /**< FIS_TYPE_PIO_SETUP */
+ uint8_t pmport:4; /**< Port multiplier */
+ uint8_t rsv0:1; /**< Reserved */
+ uint8_t d:1; /**< Data transfer direction, 1 - device to host */
+ uint8_t i:1; /**< Interrupt bit */
+ uint8_t rsv1:1;
+ uint8_t status; /**< Status register */
+ uint8_t error; /**< Error register */
+ // DWORD 1
+ uint8_t lba0; /**< LBA low register, 7:0 */
+ uint8_t lba1; /**< LBA mid register, 15:8 */
+ uint8_t lba2; /**< LBA high register, 23:16 */
+ uint8_t device; /**< Device register */
+ // DWORD 2
+ uint8_t lba3; /**< LBA register, 31:24 */
+ uint8_t lba4; /**< LBA register, 39:32 */
+ uint8_t lba5; /**< LBA register, 47:40 */
+ uint8_t rsv2; /**< Reserved */
+ // DWORD 3
+ uint8_t countl; /**< Count register, 7:0 */
+ uint8_t counth; /**< Count register, 15:8 */
+ uint8_t rsv3; /**< Reserved */
+ uint8_t e_status; /**< New value of status register */
+ // DWORD 4
+ uint16_t tc; /**< Transfer count */
+ uint8_t rsv4[2]; /**< Reserved */
+#else
+ // DWORD 0
+ uint8_t fis_type; /**< FIS_TYPE_PIO_SETUP */
+ uint8_t rsv1:1;
+ uint8_t i:1; /**< Interrupt bit */
+ uint8_t d:1; /**< Data transfer direction, 1 - device to host */
+ uint8_t rsv0:1; /**< Reserved */
+ uint8_t pmport:4; /**< Port multiplier */
+ uint8_t status; /**< Status register */
+ uint8_t error; /**< Error register */
+ // DWORD 1
+ uint8_t lba0; /**< LBA low register, 7:0 */
+ uint8_t lba1; /**< LBA mid register, 15:8 */
+ uint8_t lba2; /**< LBA high register, 23:16 */
+ uint8_t device; /**< Device register */
+ // DWORD 2
+ uint8_t lba3; /**< LBA register, 31:24 */
+ uint8_t lba4; /**< LBA register, 39:32 */
+ uint8_t lba5; /**< LBA register, 47:40 */
+ uint8_t rsv2; /**< Reserved */
+ // DWORD 3
+ uint8_t countl; /**< Count register, 7:0 */
+ uint8_t counth; /**< Count register, 15:8 */
+ uint8_t rsv3; /**< Reserved */
+ uint8_t e_status; /**< New value of status register */
+ // DWORD 4
+ uint16_t tc; /**< Transfer count */
+ uint8_t rsv4[2]; /**< Reserved */
+#endif
+} fis_pio_setup_t;
+
+/**
+ * DMA Setup ? Device to Host
+ */
+typedef struct __attribute__ ((__packed__))
+{
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+ // DWORD 0
+ uint8_t fis_type; /**< FIS_TYPE_DMA_SETUP */
+ uint8_t pmport:4; /**< Port multiplier */
+ uint8_t rsv0:1; /**< Reserved */
+ uint8_t d:1; /**< Data transfer direction, 1 - device to host */
+ uint8_t i:1; /**< Interrupt bit */
+ uint8_t a:1; /**< Auto-activate. Specifies if DMA Activate FIS is needed */
+ uint8_t rsved[2]; /**< Reserved */
+ //DWORD 1&2
+ uint64_t DMAbufferID; /**< DMA Buffer Identifier. Used to Identify DMA buffer in host memory. SATA Spec says host specific and not in Spec. Trying AHCI spec might work. */
+ //DWORD 3
+ uint32_t rsvd; /**< More reserved */
+ //DWORD 4
+ uint32_t DMAbufOffset; /**< Byte offset into buffer. First 2 bits must be 0 */
+ //DWORD 5
+ uint32_t TransferCount; /**< Number of bytes to transfer. Bit 0 must be 0 */
+ //DWORD 6
+ uint32_t resvd; /**< Reserved */
+#else
+ // DWORD 0
+ uint8_t fis_type; /**< FIS_TYPE_DMA_SETUP */
+ uint8_t a:1; /**< Auto-activate. Specifies if DMA Activate FIS is needed */
+ uint8_t i:1; /**< Interrupt bit */
+ uint8_t d:1; /**< Data transfer direction, 1 - device to host */
+ uint8_t rsv0:1; /**< Reserved */
+ uint8_t pmport:4; /**< Port multiplier */
+ uint8_t rsved[2]; /**< Reserved */
+ //DWORD 1&2
+ uint64_t DMAbufferID; /**< DMA Buffer Identifier. Used to Identify DMA buffer in host memory. SATA Spec says host specific and not in Spec. Trying AHCI spec might work. */
+ //DWORD 3
+ uint32_t rsvd; /**< More reserved */
+ //DWORD 4
+ uint32_t DMAbufOffset; /**< Byte offset into buffer. First 2 bits must be 0 */
+ //DWORD 5
+ uint32_t TransferCount; /**< Number of bytes to transfer. Bit 0 must be 0 */
+ //DWORD 6
+ uint32_t resvd; /**< Reserved */
+#endif
+} fis_dma_setup_t;
+
+typedef struct __attribute__ ((__packed__))
+{
+ uint8_t fis_type; /**< FIS_TYPE_BIST */
+ uint8_t pmport:4; /**< Port multiplier */
+ uint8_t rsv0:4; /**< Reserved */
+ uint8_t v:1; /**< Vendor Specific */
+ uint8_t r:1; /**< Reserved */
+ uint8_t p:1; /**< Primitive bit */
+ uint8_t f:1; /**< Far end analog loopback */
+ uint8_t l:1; /**< Far end retimed loopback */
+ uint8_t s:1; /**< Scrambling bypass */
+ uint8_t a:1; /**< Align bypass */
+ uint8_t t:1; /**< Far end transmit only */
+ uint8_t rsv1; /**< Reserved */
+ uint32_t data1; /**< Only valid when "t" is set */
+ uint32_t data2; /**< Only valid when "t" is set */
+} fis_bist_t;
+
+/**
+ * Received FIS Structure - AHCI rev 1.3 page 35
+ */
+typedef struct
+{
+ // 0x00
+ fis_dma_setup_t dsfis; /**< DMA Setup FIS */
+ uint8_t pad0[4]; /* Filler 0x1c - 0x1f */
+ // 0x20
+ fis_pio_setup_t psfis; /**< PIO Setup FIS */
+ uint8_t pad1[12]; /* Filler 0x34 - 0x3f */
+ // 0x40
+ fis_reg_d2h_t rfis; /**< Device to Host (D2H) Register FIS */
+ uint8_t pad2[4]; /* Filler 0x54 - 0x57 */
+ // 0x58
+ uint8_t sdbfis[8]; /**< Set Device Bit FIS */
+ // 0x60
+ uint8_t ufis[64]; /**< Unknown FIS (up to 64 bytes) */
+ // 0xA0
+ uint8_t rsv[0x100-0xA0]; /* Reserved */
+} hba_fis_t;
+
+/**
+ * Command header - AHCI rev 1.3 page 36
+ */
+typedef struct
+{
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+ // DW0
+ uint8_t cfl:5; /**< Command FIS length in DWORDS, 2 ~ 16 */
+ uint8_t a:1; /**< ATAPI */
+ uint8_t w:1; /**< Write, 1: H2D, 0: D2H */
+ uint8_t p:1; /**< Prefetchable */
+ uint8_t r:1; /**< Reset */
+ uint8_t b:1; /**< BIST */
+ uint8_t c:1; /**< Clear busy upon R_OK */
+ uint8_t rsv0:1; /**< Reserved */
+ uint8_t pmp:4; /**< Port multiplier port */
+ uint16_t prdtl; /**< Physical region descriptor table length in entries */
+ // DW1
+ uint32_t prdbc; /**< Physical region descriptor byte count transferred */
+ // DW2, 3
+ uint64_t ctba; /**< Command table descriptor base address. Must be 128 byte aligned */
+ // DW4 - 7
+ uint32_t rsv1[4]; /**< Reserved */
+#else
+ // DW0
+ uint8_t p:1; /**< Prefetchable */
+ uint8_t w:1; /**< Write, 1: H2D, 0: D2H */
+ uint8_t a:1; /**< ATAPI */
+ uint8_t cfl:5; /**< Command FIS length in DWORDS, 2 ~ 16 */
+ uint8_t pmp:4; /**< Port multiplier port */
+ uint8_t c:1; /**< Clear busy upon R_OK */
+ uint8_t b:1; /**< BIST */
+ uint8_t r:1; /**< Reset */
+ uint8_t rsv0:1; /**< Reserved */
+ uint16_t prdtl; /**< Physical region descriptor table length in entries */
+ // DW1
+ uint32_t prdbc; /**< Physical region descriptor byte count transferred */
+ // DW2, 3
+ uint64_t ctba; /**< Command table descriptor base address */
+ // DW4 - 7
+ uint32_t rsv1[4]; /**< Reserved */
+#endif
+} hba_cmd_header_t;
+
+/**
+ * Physical Region Descriptor Table Entry - AHCI rev 1.3 page 39
+ */
+typedef struct
+{
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+ uint64_t dba; /**< Data base address. Must be 2 byte aligned */
+ uint32_t rsv0; /**< Reserved */
+ uint32_t dbc:22; /**< Byte count - 1, 4M max. Must be even number of bytes to transfer */
+ uint32_t rsv1:9; /**< Reserved */
+ uint32_t i:1; /**< Interrupt on completion */
+#else
+ uint64_t dba; /**< Data base address */
+ uint32_t rsv0; /**< Reserved */
+ uint32_t dbc;
+#endif
+} hba_prdt_entry_t;
+
+/**
+ * Command Table - AHCI rev 1.3 page 39
+ */
+typedef struct
+{
+ uint8_t cfis[64]; /**< Command FIS */
+ uint8_t acmd[16]; /**< ATAPI command, 12 or 16 bytes */
+ uint8_t rsv[48]; /**< Reserved */
+ hba_prdt_entry_t prdt_entry[1]; /**< Physical region descriptor table entries, 0 ~ 65535 */
+} hba_cmd_tbl_t;
+
+/**
+ * Return the number of SATA controllers on the chip
+ *
+ * @param node Node to query
+ *
+ * @return Number of controllers, could be zero.
+ */
+int bdk_sata_get_controllers(bdk_node_t node)
+{
+ if (CAVIUM_IS_MODEL(CAVIUM_CN88XX))
+ return 16; /* 16 controllers on QLMs 2,3, 6-7 */
+ else if (CAVIUM_IS_MODEL(CAVIUM_CN83XX))
+ return 6; /* 6 controllers on DLMs 4-6 */
+ else if (CAVIUM_IS_MODEL(CAVIUM_CN81XX))
+ return 2; /* 2 controllers on DLM 2 */
+ else if (CAVIUM_IS_MODEL(CAVIUM_CN93XX))
+ return 4; /* 4 controllers on DLM 4-5 */
+ else
+ return 0;
+}
+
+static int __bdk_sata_is_initialized(bdk_node_t node, int controller)
+{
+ /* Make sure port is clocked before proceeding */
+ BDK_CSR_INIT(uctl_ctl, node, BDK_SATAX_UCTL_CTL(controller));
+ if (!uctl_ctl.s.a_clk_en || uctl_ctl.s.a_clkdiv_rst)
+ return 0;
+
+ /* See if the controller is started */
+ BDK_CSR_INIT(cmd, node, BDK_SATAX_UAHC_P0_CMD(controller));
+ return cmd.s.st;
+}
+
+/**
+ * Initialize a SATA controller and begin device detection
+ *
+ * @param node Node to initialize
+ * @param controller Which controller to initialize
+ *
+ * @return Zero on success, negative on failure
+ */
+int bdk_sata_initialize(bdk_node_t node, int controller)
+{
+ _Static_assert(sizeof(fis_reg_h2d_t) == 5 * 4, "Size of fis_reg_h2d_t wrong");
+ _Static_assert(sizeof(fis_reg_d2h_t)== 5 * 4, "Size of fis_reg_d2h_t wrong");
+ _Static_assert(sizeof(fis_data_t) == 2 * 4, "Size of fis_data_t wrong");
+ _Static_assert(sizeof(fis_pio_setup_t) == 5 * 4, "Size of fis_pio_setup_t wrong");
+ _Static_assert(sizeof(fis_dma_setup_t) == 7 * 4, "Size of fis_dma_setup_t wrong");
+ _Static_assert(sizeof(fis_bist_t) == 3 * 4, "Size of fis_bist_t wrong");
+ _Static_assert(sizeof(hba_fis_t) == 256, "Size of hba_fis_t wrong");
+ _Static_assert(sizeof(hba_cmd_header_t) == 8 * 4, "Size of hba_cmd_header_t wrong");
+ _Static_assert(sizeof(hba_prdt_entry_t) == 4 * 4, "Size of hba_prdt_entry_t wrong");
+ _Static_assert(sizeof(hba_cmd_tbl_t)== 128 + sizeof(hba_prdt_entry_t), "Size of hba_cmd_tbl_t wrong");
+
+ /* Make sure port is clocked before proceeding */
+ BDK_CSR_INIT(uctl_ctl, node, BDK_SATAX_UCTL_CTL(controller));
+ if (!uctl_ctl.s.a_clk_en || uctl_ctl.s.a_clkdiv_rst)
+ {
+ bdk_error("N%d.SATA%d: Not in SATA mode\n", node, controller);
+ return -1;
+ }
+
+ /* The following SATA setup is from the AHCI 1.3 spec, section
+ 10.1.1, Firmware Specific Initialization. */
+ /* Early firmware setup was done in __bdk_qlm_set_sata(), we're not
+ starting the staggered spin-up process */
+
+ /* 1. Indicate that system software is AHCI aware by setting GHC.AE to '1'. */
+ BDK_CSR_MODIFY(c, node, BDK_SATAX_UAHC_GBL_GHC(controller),
+ c.s.ae = 1); /* AHCI enable */
+
+ /* 2. Ensure that PxCMD.ST = '0', PxCMD.CR = '0', PxCMD.FRE = '0',
+ PxCMD.FR = '0', and PxSCTL.DET = '0'. */
+ BDK_CSR_INIT(p0_cmd, node, BDK_SATAX_UAHC_P0_CMD(controller));
+ if (p0_cmd.s.st)
+ bdk_error("N%d.SATA%d: PxCMD[ST] is illegally set during init\n", node, controller);
+ if (p0_cmd.s.cr)
+ bdk_error("N%d.SATA%d: PxCMD[CR] is illegally set during init\n", node, controller);
+ if (p0_cmd.s.fre)
+ bdk_error("N%d.SATA%d: PxCMD[FRE] is illegally set during init\n", node, controller);
+ if (p0_cmd.s.fr)
+ bdk_error("N%d.SATA%d: PxCMD[FR] is illegally set during init\n", node, controller);
+ BDK_CSR_INIT(p0_sctl, node, BDK_SATAX_UAHC_P0_SCTL(controller));
+ if (p0_sctl.s.det)
+ bdk_error("N%d.SATA%d: PxSCTL[DET] is illegally set during init\n", node, controller);
+
+ /* 3. Allocate memory for the command list and the FIS receive area. Set
+ PxCLB and PxCLBU to the physical address of the allocated command list.
+ Set PxFB and PxFBU to the physical address of the allocated FIS receive
+ area. Then set PxCMD.FRE to '1'. */
+ /* Allocate area for commands */
+ uint64_t clb_pa = BDK_CSR_READ(node, BDK_SATAX_UAHC_P0_CLB(controller));
+ if (clb_pa == 0)
+ {
+ void *clb = memalign(1024, sizeof(hba_cmd_header_t) * 32);
+ if (clb == NULL)
+ {
+ bdk_error("N%d.SATA%d: Failed to allocate command list\n", node, controller);
+ return -1;
+ }
+ memset(clb, 0, sizeof(hba_cmd_header_t) * 32);
+ BDK_CSR_WRITE(node, BDK_SATAX_UAHC_P0_CLB(controller),
+ bdk_ptr_to_phys(clb));
+ }
+ /* Allocate area for FIS DMAs */
+ uint64_t fb_pa = BDK_CSR_READ(node, BDK_SATAX_UAHC_P0_FB(controller));
+ if (fb_pa == 0)
+ {
+ hba_fis_t *fb = memalign(256, sizeof(hba_fis_t));
+ if (fb == NULL)
+ {
+ bdk_error("N%d.SATA%d: Failed to allocate FIS\n", node, controller);
+ return -1;
+ }
+ memset(fb, 0, sizeof(hba_fis_t));
+ BDK_CSR_WRITE(node, BDK_SATAX_UAHC_P0_FB(controller),
+ bdk_ptr_to_phys(fb));
+ }
+
+ BDK_CSR_MODIFY(c, node, BDK_SATAX_UAHC_P0_CMD(controller),
+ c.s.fre = 1); /* FIS-receive enable */
+
+ /* 4. Initiate a spin up of the SATA drive attached to the port; i.e. set
+ PxCMD.SUD to '1'.*/
+ BDK_CSR_MODIFY(c, node, BDK_SATAX_UAHC_P0_CMD(controller),
+ c.s.pod = 1; /* Power on the device, only has affect if SATAX_UAHC_P0_CMD[CPD]=1 */
+ c.s.sud = 1); /* Spin-up device */
+
+ /* 5. Wait for a positive indication that a device is attached to the port
+ (the maximum amount of time to wait for presence indication is specified
+ in the Serial ATA Revision 2.6 specification). This is done by polling
+ PxSSTS.DET. If PxSSTS.DET returns a value of 1h or 3h when read, then
+ system software shall continue to the next step, otherwise if the
+ polling process times out system software moves to the next implemented
+ port and returns to step 1. */
+ /* Waiting for device detection, up to 500ms. PxCMD[DET] must be 1 or 3 */
+ uint64_t timeout = bdk_clock_get_count(BDK_CLOCK_TIME) + bdk_clock_get_rate(bdk_numa_local(), BDK_CLOCK_TIME) / 2;
+ BDK_CSR_INIT(p0_ssts, node, BDK_SATAX_UAHC_P0_SSTS(controller));
+ while ((p0_ssts.s.det != 1) && (p0_ssts.s.det != 3) &&
+ (bdk_clock_get_count(BDK_CLOCK_TIME) <= timeout))
+ {
+ p0_ssts.u = BDK_CSR_READ(node, BDK_SATAX_UAHC_P0_SSTS(controller));
+ bdk_thread_yield();
+ }
+ if ((p0_ssts.s.det != 1) && (p0_ssts.s.det != 3))
+ {
+ bdk_error("N%d.SATA%d: PxSCTL[DET]=%d failed to detect a device\n", node, controller, p0_ssts.s.det);
+ goto fail;
+ }
+
+ /* 6. Clear the PxSERR register, by writing '1s' to each implemented bit
+ location. */
+ BDK_CSR_WRITE(node, BDK_SATAX_UAHC_P0_SERR(controller), -1);
+
+ /* 7. Wait for indication that SATA drive is ready. This is determined via
+ an examination of PxTFD.STS. If PxTFD.STS.BSY, PxTFD.STS.DRQ, and
+ PxTFD.STS.ERR are all '0', prior to the maximum allowed time as
+ specified in the ATA/ATAPI-7 specification, the device is ready. */
+ /* Wait for the device to be ready. BSY(7), DRQ(3), and ERR(0) must be clear */
+ if (BDK_CSR_WAIT_FOR_FIELD(node, BDK_SATAX_UAHC_P0_TFD(controller), sts & 0x89, ==, 0, 5000000))
+ {
+ BDK_CSR_INIT(p0_tfd, node, BDK_SATAX_UAHC_P0_TFD(controller));
+ bdk_error("N%d.SATA%d: PxTFD[STS]=0x%x, Drive not ready\n", node, controller, p0_tfd.s.sts);
+ goto fail;
+ }
+
+ /* Enable AHCI command queuing */
+ BDK_CSR_MODIFY(c, node, BDK_SATAX_UAHC_GBL_CCC_CTL(controller),
+ c.s.tv = 0;
+ c.s.en = 1);
+ BDK_CSR_MODIFY(c, node, BDK_SATAX_UAHC_GBL_CCC_PORTS(controller),
+ c.s.prt = 1);
+
+ /* Enable the FIS and clear any pending errors */
+ BDK_CSR_MODIFY(c, node, BDK_SATAX_UAHC_P0_FBS(controller),
+ c.s.dec = 1;
+ c.s.en = 1);
+
+ /* Disable all interrupts */
+ BDK_CSR_WRITE(node, BDK_SATAX_UAHC_P0_IE(controller), 0);
+
+ /* Clear all status bits */
+ BDK_CSR_WRITE(node, BDK_SATAX_UAHC_P0_IS(controller), -1);
+
+ /* Start the port controller */
+ BDK_CSR_MODIFY(c, node, BDK_SATAX_UAHC_P0_CMD(controller),
+ c.s.st = 1); /* Start the controller */
+ return 0;
+
+fail:
+ bdk_sata_shutdown(node, controller);
+ return -1;
+}
+
+/**
+ * Shutdown a SATA controller
+ *
+ * @param node Node to access
+ * @param controller Controller to shutdown
+ *
+ * @return Zero on success, negative on failure
+ */
+int bdk_sata_shutdown(bdk_node_t node, int controller)
+{
+ /* Remember the current speed limit and power management */
+ BDK_CSR_INIT(p0_sctl, node, BDK_SATAX_UAHC_P0_SCTL(controller));
+ /* Perform a HBA reset */
+ BDK_CSR_MODIFY(c, node, BDK_SATAX_UAHC_GBL_GHC(controller),
+ c.s.hr = 1);
+ /* Wait for the reset to complete */
+ if (BDK_CSR_WAIT_FOR_FIELD(node, BDK_SATAX_UAHC_GBL_GHC(controller), hr, ==, 0, 100000))
+ {
+ bdk_error("N%d.SATA%d: Timeout waiting for HBA reset to complete\n", node, controller);
+ return -1;
+ }
+ /* Restore the speed limit and power management */
+ BDK_CSR_MODIFY(c, node, BDK_SATAX_UAHC_P0_SCTL(controller),
+ c.s.ipm = p0_sctl.s.ipm;
+ c.s.spd = p0_sctl.s.spd);
+ return 0;
+}
+
+/**
+ * Return the number of SATA ports connected to this AHCI controller
+ *
+ * @param node Node to query
+ * @param controller SATA controller
+ *
+ * @return Number of ports. Zero if the controller doesn't connect to a QLM.
+ */
+int bdk_sata_get_ports(bdk_node_t node, int controller)
+{
+ BDK_CSR_INIT(ctl, node, BDK_SATAX_UAHC_GBL_CCC_CTL(controller));
+ return (ctl.s.en) ? 1 : 0;
+}
+
+/**
+ * Convert an IDE string into a C string with a NULL terminator
+ *
+ * @param buffer Buffer for new string. Must be one longer than length
+ * @param original IDE string of identify command
+ * @param length Length of the string in bytes
+ */
+static void get_ide_string(char *buffer, void *original, int length)
+{
+ /* Copy the IDE string 2 bytes at a time, swapping as we go */
+ uint16_t *newp = (uint16_t *)buffer;
+ uint16_t *oldp = (uint16_t *)original;
+ for (int i = 0; i < length / 2; i++)
+ newp[i] = bdk_swap16(oldp[i]);
+
+ /* Force a NULL terminator */
+ buffer[length] = 0;
+
+ /* Remove all trailing spaces */
+ while (buffer[length-1] == ' ')
+ {
+ buffer[length - 1] = 0;
+ length--;
+ }
+}
+
+static int issue_command(bdk_node_t node, int controller, int command, int is_write, uint64_t lba, void *buffer, int size)
+{
+ /* Pick a command slot to use */
+ int slot = 0;
+ hba_cmd_header_t *cmd_header = bdk_phys_to_ptr(BDK_CSR_READ(node, BDK_SATAX_UAHC_P0_CLB(controller)));
+ cmd_header += slot;
+
+ /* Build a command table with the command to execute */
+ hba_cmd_tbl_t cmd_table BDK_CACHE_LINE_ALIGNED;
+ memset(&cmd_table, 0, sizeof(hba_cmd_tbl_t));
+ /* Where the data is */
+ cmd_table.prdt_entry[0].dba = bdk_cpu_to_le64(bdk_ptr_to_phys(buffer));
+ cmd_table.prdt_entry[0].dbc = bdk_cpu_to_le32(size - 1);
+
+ /* The actual command */
+ fis_reg_h2d_t *cmd_fis = (fis_reg_h2d_t *)cmd_table.cfis;
+ cmd_fis->fis_type = FIS_TYPE_REG_H2D;
+ cmd_fis->command = command;
+ cmd_fis->device = 1 << 6; /* LBA mode */
+ cmd_fis->c = 1; /* Write command register */
+ cmd_fis->lba0 = (lba >> 0) & 0xff;
+ cmd_fis->lba1 = (lba >> 8) & 0xff;
+ cmd_fis->lba2 = (lba >> 16) & 0xff;
+ cmd_fis->lba3 = (lba >> 24) & 0xff;
+ cmd_fis->lba4 = (lba >> 32) & 0xff;
+ cmd_fis->lba5 = (lba >> 40) & 0xff;
+ cmd_fis->count = bdk_cpu_to_le16(size / 512);
+
+ /* Setup the command header */
+ cmd_header->cfl = sizeof(fis_reg_h2d_t) / 4;
+ cmd_header->w = is_write;
+ cmd_header->prdtl = bdk_cpu_to_le16(1);
+ cmd_header->ctba = bdk_cpu_to_le64(bdk_ptr_to_phys(&cmd_table));
+
+ BDK_WMB;
+
+ /* Check that the slot is idle */
+ BDK_CSR_INIT(ci, node, BDK_SATAX_UAHC_P0_CI(controller));
+ if (ci.u & (1<<slot))
+ {
+ bdk_error("N%d.SATA%d: Command slot busy before submit\n", node, controller);
+ return -1;
+ }
+
+ /* Clear all status bits */
+ BDK_CSR_WRITE(node, BDK_SATAX_UAHC_P0_IS(controller), -1);
+ BDK_CSR_READ(node, BDK_SATAX_UAHC_P0_IS(controller));
+
+ /* Issue command */
+ BDK_CSR_WRITE(node, BDK_SATAX_UAHC_P0_CI(controller), 1 << slot);
+
+ /* Wait for command accept */
+ const int TIMEOUT = 5000000; /* 5 seconds */
+ if (BDK_CSR_WAIT_FOR_FIELD(node,BDK_SATAX_UAHC_P0_CI(controller), ci & (1<<slot), ==, 0, TIMEOUT))
+ {
+ bdk_error("N%d.SATA%d: Command timeout\n", node, controller);
+ bdk_sata_shutdown(node, controller);
+ return -1;
+ }
+
+ /* Wait for completion */
+ if (BDK_CSR_WAIT_FOR_FIELD(node,BDK_SATAX_UAHC_P0_IS(controller), dhrs | c.s.pss | c.s.dss, !=, 0, TIMEOUT))
+ {
+ bdk_error("N%d.SATA%d: Command Response timeout\n", node, controller);
+ bdk_sata_shutdown(node, controller);
+ return -1;
+ }
+
+ /* Read status */
+ BDK_CSR_INIT(p_is, node, BDK_SATAX_UAHC_P0_IS(controller));
+ if (p_is.s.tfes)
+ {
+ bdk_error("N%d.SATA%d: Task-file error\n", node, controller);
+ bdk_sata_shutdown(node, controller);
+ return -1;
+ }
+ return 0;
+}
+
+/**
+ * Identify the SATA device connected to a controller
+ *
+ * @param node Node to query
+ * @param controller Controller to query
+ * @param port Which SATA port on the controller, zero based
+ *
+ * @return Size of the disk in bytes
+ */
+uint64_t bdk_sata_identify(bdk_node_t node, int controller, int port)
+{
+ if (!__bdk_sata_is_initialized(node, controller))
+ {
+ if (bdk_sata_initialize(node, controller))
+ return 0;
+ }
+
+ const int TIMEOUT = 1000000; /* 1 seconds */
+ if (BDK_CSR_WAIT_FOR_FIELD(node, BDK_SATAX_UAHC_P0_SSTS(controller), ipm, !=, 0, TIMEOUT))
+ {
+ bdk_error("N%d.SATA%d: Device not present or communication not established\n", node, controller);
+ return 0;
+ }
+
+ /* Read the Serial ATA Status */
+ BDK_CSR_INIT(ssts, node, BDK_SATAX_UAHC_P0_SSTS(controller));
+
+ /* Check the link power state */
+ switch (ssts.s.ipm)
+ {
+ case 0: /* Device not present or communication not established */
+ BDK_TRACE(SATA, "N%d.SATA%d: Device not present or communication not established\n", node, controller);
+ return 0;
+ case 1: /* Interface in active state */
+ BDK_TRACE(SATA, "N%d.SATA%d: Interface in active state\n", node, controller);
+ break;
+ case 2: /* Interface in Partial power management state */
+ BDK_TRACE(SATA, "N%d.SATA%d: Interface in Partial power management state\n", node, controller);
+ return 0;
+ case 6: /* Interface in Slumber power management state */
+ BDK_TRACE(SATA, "N%d.SATA%d: Interface in Slumber power management state\n", node, controller);
+ return 0;
+ case 8: /* Interface in DevSleep power management state */
+ BDK_TRACE(SATA, "N%d.SATA%d: Interface in DevSleep power management state\n", node, controller);
+ return 0;
+ default:
+ BDK_TRACE(SATA, "N%d.SATA%d: Interface in unknown power state %d\n", node, controller, ssts.s.ipm);
+ return 0;
+ }
+
+ /* Check the link speed */
+ switch (ssts.s.spd)
+ {
+ case 0: /* Device not present or communication not established */
+ BDK_TRACE(SATA, "N%d.SATA%d: Device not present or communication not established\n", node, controller);
+ return 0;
+ case 1:
+ case 2:
+ case 3:
+ BDK_TRACE(SATA, "N%d.SATA%d: Speed Gen%d\n", node, controller, ssts.s.spd);
+ break;
+ default:
+ BDK_TRACE(SATA, "N%d.SATA%d: Interface in unknown speed %d\n", node, controller, ssts.s.spd);
+ return 0;
+ }
+
+ /* Check the device detection */
+ switch (ssts.s.det)
+ {
+ case 0: /* No device detected and Phy communication not established */
+ BDK_TRACE(SATA, "N%d.SATA%d: No device detected and Phy communication not established\n", node, controller);
+ return 0;
+ case 1: /* Device presence detected but Phy communication not established */
+ BDK_TRACE(SATA, "N%d.SATA%d: Device presence detected but Phy communication not established\n", node, controller);
+ return 0;
+ case 3: /* Device presence detected and Phy communication established */
+ BDK_TRACE(SATA, "N%d.SATA%d: Device presence detected and Phy communication established\n", node, controller);
+ break;
+ case 4: /* Phy in offline mode as a result of the interface being disabled or running in a BIST loopback mode */
+ BDK_TRACE(SATA, "N%d.SATA%d: Phy in offline mode\n", node, controller);
+ return 0;
+ default:
+ BDK_TRACE(SATA, "N%d.SATA%d: Device presence in unknown state %d\n", node, controller, ssts.s.det);
+ return 0;
+ }
+
+ /* Read the port signature to identify the device type */
+ BDK_CSR_INIT(sig, node, BDK_SATAX_UAHC_P0_SIG(controller));
+ switch (sig.s.sig)
+ {
+ case 0x00000101: /* SATA_SIG_ATA 0x00000101, SATA drive */
+ BDK_TRACE(SATA, "N%d.SATA%d: SATA drive\n", node, controller);
+ break;
+ case 0xEB140101: /* SATA_SIG_ATAPI 0xEB140101, SATAPI drive */
+ BDK_TRACE(SATA, "N%d.SATA%d: ATAPI drive, not supported by the BDK\n", node, controller);
+ return 0;
+ case 0xC33C0101: /* SATA_SIG_SEMB 0xC33C0101, Enclosure management bridge */
+ BDK_TRACE(SATA, "N%d.SATA%d: Enclosure management bridge, not supported by the BDK\n", node, controller);
+ return 0;
+ case 0x96690101: /* SATA_SIG_PM 0x96690101, Port multiplier */
+ BDK_TRACE(SATA, "N%d.SATA%d: Port multiplier, not supported by the BDK\n", node, controller);
+ return 0;
+ default: /* Just assume it is a drive */
+ BDK_TRACE(SATA, "N%d.SATA%d: Unknown signature 0x%08x, assuming a SATA drive\n", node, controller, sig.u);
+ break;
+ }
+
+ /* Send identify to the device */
+ const int ATA_CMD_IDENTIFY = 0xec;
+ char buffer[512];
+ if (issue_command(node, controller, ATA_CMD_IDENTIFY, 0, 0, buffer, sizeof(buffer)))
+ return 0;
+
+ /* Extract the data out of the IDENTIFY response */
+ uint16_t *ptr = (uint16_t *)buffer;
+ uint64_t sectors = bdk_le16_to_cpu(ptr[57]);
+ sectors += (uint32_t)bdk_le16_to_cpu(ptr[58]) << 16;
+ char serial[20 + 1];
+ get_ide_string(serial, ptr + 10, 20);
+ char firmware[8 + 1];
+ get_ide_string(firmware, ptr + 23, 8);
+ char model[40 + 1];
+ get_ide_string(model, ptr + 27, 40);
+
+ printf("N%d.SATA%d: Model=\"%s\", Firmware=\"%s\", Serial=\"%s\", Sectors=%lu, Link=Gen%d\n",
+ node, controller, model, firmware, serial, sectors, ssts.s.spd);
+
+ /* Return size in bytes */
+ return sectors * 512;
+}
+
+/**
+ * Read data from a SATA device
+ *
+ * @param node Node the controller is on
+ * @param controller Which controller
+ * @param port Which port on the controller, zero based
+ * @param lba 48 bit Block address to read
+ * @param sectors Number of 512 bytes sectors to read
+ * @param buffer Buffer to receive the data. Must be at least 512 * sectors in size
+ *
+ * @return Zero on success, negative on failure
+ */
+int bdk_sata_read(bdk_node_t node, int controller, int port, uint64_t lba, int sectors, void *buffer)
+{
+ if (!__bdk_sata_is_initialized(node, controller))
+ {
+ if (bdk_sata_initialize(node, controller))
+ return -1;
+ }
+
+ const int ATA_READ_DMA = 0xc8;
+ if (issue_command(node, controller, ATA_READ_DMA, 0, lba, buffer, sectors * 512))
+ return -1;
+ return 0;
+}
+
+/**
+ * Write data to a SATA device
+ *
+ * @param node Node the controller is on
+ * @param controller Which controller
+ * @param port Which port on the controller, zero based
+ * @param lba 48 bit Block address to write
+ * @param sectors Number of 512 bytes sectors to write
+ * @param buffer Data buffer to write. Must be at least 512 * sectors in size
+ *
+ * @return Zero on success, negative on failure
+ */
+int bdk_sata_write(bdk_node_t node, int controller, int port, uint64_t lba, int sectors, const void *buffer)
+{
+ if (!__bdk_sata_is_initialized(node, controller))
+ {
+ if (bdk_sata_initialize(node, controller))
+ return -1;
+ }
+
+ const int ATA_WRITE_DMA = 0xca;
+ if (issue_command(node, controller, ATA_WRITE_DMA, 1, lba, (void*)buffer, sectors * 512))
+ return -1;
+ return 0;
+}
+
+/**
+ * Enter one of the SATA pattern generation / loop testing modes
+ *
+ * @param node Node to access
+ * @param controller SATA controller to access
+ * @param port Which port on the controller
+ * @param mode Test mode to enter
+ *
+ * @return Zero on success, negative on failure
+ */
+int bdk_sata_bist_fis(bdk_node_t node, int controller, int port, bdk_sata_bist_fis_t mode)
+{
+ if (!__bdk_sata_is_initialized(node, controller))
+ {
+ if (bdk_sata_initialize(node, controller))
+ return -1;
+ }
+
+ /* Select the port we're doing BIST loopback on */
+ BDK_CSR_MODIFY(c, node, BDK_SATAX_UAHC_GBL_TESTR(controller),
+ c.s.psel = port);
+
+ /* Select the pattern */
+ int pattern;
+ switch (mode)
+ {
+ case BDK_SATA_BIST_SW_TX_ONLY_SSOP:
+ case BDK_SATA_BIST_SW_TX_ONLY_HTDP:
+ case BDK_SATA_BIST_SW_TX_ONLY_LTDP:
+ case BDK_SATA_BIST_SW_TX_ONLY_LFSCP:
+ case BDK_SATA_BIST_SW_TX_ONLY_COMP:
+ case BDK_SATA_BIST_SW_TX_ONLY_LBP:
+ case BDK_SATA_BIST_SW_TX_ONLY_MFTP:
+ case BDK_SATA_BIST_SW_TX_ONLY_HFTP:
+ case BDK_SATA_BIST_SW_TX_ONLY_LFTP:
+ pattern = mode - BDK_SATA_BIST_SW_TX_ONLY_SSOP;
+ break;
+ default:
+ pattern = 1; /* HTDP */
+ break;
+ }
+ BDK_CSR_MODIFY(c, node, BDK_SATAX_UAHC_GBL_BISTCR(controller),
+ c.s.pattern = pattern);
+
+ /*
+ Note from the Synopsys SATA bist training video on pattern generation
+ without using BIST FIS.
+
+ 1) Far-end Re-timed Loopback Responder Mode (Software Initiated)
+
+ In this mode the host controller receives the pattern and transmits
+ it back out. The setup of the mode is done by software, so no BIST FIS
+ frames are needed. After software sets it up, any pattern generator
+ should be able to send a pattern and get it back.
+
+ Setup:
+ 1) Write SATAX_UAHC_GBL_BISTCR.ferlib = 1
+ 2) Connect pattern generator
+ 3) Pattern generator must send ALIGNs for PHY sync up
+ 4) Pattern should be looped back out
+
+ 2) Far-end Transmit Only Responder Mode (Software Initiated)
+
+ In this mode the host controller sends a transmit pattern and ignores
+ all input. This is useful for checking the TX eye diagram without an
+ external pattern generator.
+
+ Setup:
+ 1) Write SATAX_UAHC_GBL_BISTCR.pattern to select the pattern.
+ 2) Write SATAX_UAHC_GBL_BISTCR.txo = 1.
+ 3) Host starts sending the requested BIST pattern.
+
+ BIST FIS Modes:
+ 1) Far-end Analog Loopback (F=1)
+ Far end loops the received pattern back to transmit without retiming
+ the symbols. This is optional in the SATA 3.0 spec.
+ 2) Far-end Retimed Loopback (L=1)
+ Far end loops the received pattern back to transmit after retiming
+ the symbols. This is mandatory in the SATA 3.0 spec.
+ 3) Far-end Transmit Only (T=1, with other bits)
+ Far end transits a pattern and ignores its input. This is optional
+ in the SATA 3.0 spec.
+ */
+ if (mode == BDK_SATA_BIST_SW_RETIMED)
+ {
+ /* No FIS, just enter local retimed loopback */
+ BDK_CSR_MODIFY(c, node, BDK_SATAX_UAHC_GBL_BISTCR(controller),
+ c.s.ferlib = 1);
+ BDK_TRACE(SATA, "N%d.SATA%d: Started Retimed loopback\n", node, controller);
+ return 0;
+ }
+ else if ((mode >= BDK_SATA_BIST_SW_TX_ONLY_SSOP) && (mode <= BDK_SATA_BIST_SW_TX_ONLY_LFTP))
+ {
+ /* No FIS, just enter local transit only */
+ BDK_CSR_MODIFY(c, node, BDK_SATAX_UAHC_GBL_BISTCR(controller),
+ c.s.txo = 1);
+ BDK_TRACE(SATA, "N%d.SATA%d: Started tranmsit only\n", node, controller);
+ return 0;
+ }
+
+ /* Issue a BIST FIS command */
+
+ /* Pick a command slot to use */
+ int slot = 0;
+ hba_cmd_header_t *cmd_header = bdk_phys_to_ptr(BDK_CSR_READ(node, BDK_SATAX_UAHC_P0_CLB(controller)));
+ cmd_header += slot;
+
+ /* Build a command table with the command to execute */
+ hba_cmd_tbl_t cmd_table BDK_CACHE_LINE_ALIGNED;
+ memset(&cmd_table, 0, sizeof(hba_cmd_tbl_t));
+
+ /* The actual BIST FIS command */
+ fis_bist_t *bist_fis = (fis_bist_t *)cmd_table.cfis;
+ bist_fis->fis_type = FIS_TYPE_BIST;
+ switch (mode)
+ {
+ case BDK_SATA_BIST_FIS_RETIMED: /* Send FIS to tell device to enter Retimed loopback */
+ bist_fis->l = 1;
+ break;
+ case BDK_SATA_BIST_FIS_ANALOG: /* Send FIS to tell device to enter Analog loopback */
+ bist_fis->f = 1;
+ break;
+ case BDK_SATA_BIST_FIS_TX_ONLY: /* Send FIS to tell device to transit only */
+ bist_fis->t = 1;
+ break;
+ default:
+ bdk_error("Invalid SATA BIST FIS mode %d\n", mode);
+ return -1;
+ }
+
+ /* Setup the command header */
+ memset(cmd_header, 0, sizeof(hba_cmd_header_t));
+ cmd_header->cfl = sizeof(fis_bist_t) / 4;
+ cmd_header->b = 1;
+ cmd_header->ctba = bdk_ptr_to_phys(&cmd_table);
+
+ BDK_WMB;
+
+ /* Check that the slot is idle */
+ BDK_CSR_INIT(ci, node, BDK_SATAX_UAHC_P0_CI(controller));
+ if (ci.u & (1<<slot))
+ {
+ bdk_error("N%d.SATA%d: Command slot busy before submit\n", node, controller);
+ return -1;
+ }
+
+ /* Clear all status bits */
+ BDK_CSR_WRITE(node, BDK_SATAX_UAHC_P0_IS(controller), -1);
+ BDK_CSR_READ(node, BDK_SATAX_UAHC_P0_IS(controller));
+
+ /* Issue command */
+ BDK_CSR_WRITE(node, BDK_SATAX_UAHC_P0_CI(controller), 1 << slot);
+ BDK_TRACE(SATA, "N%d.SATA%d: Sent BIST FIS\n", node, controller);
+
+ return 0;
+}
+
diff --git a/src/vendorcode/cavium/bdk/libbdk-hal/bdk-twsi.c b/src/vendorcode/cavium/bdk/libbdk-hal/bdk-twsi.c
deleted file mode 100644
index 4fbb78a876..0000000000
--- a/src/vendorcode/cavium/bdk/libbdk-hal/bdk-twsi.c
+++ /dev/null
@@ -1,318 +0,0 @@
-/***********************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;
-}
diff --git a/src/vendorcode/cavium/bdk/libbdk-hal/bdk-usb.c b/src/vendorcode/cavium/bdk/libbdk-hal/bdk-usb.c
new file mode 100644
index 0000000000..eb2a85fa0d
--- /dev/null
+++ b/src/vendorcode/cavium/bdk/libbdk-hal/bdk-usb.c
@@ -0,0 +1,683 @@
+/***********************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>
+#include <libbdk-arch/bdk-csrs-usbdrd.h>
+#include <libbdk-arch/bdk-csrs-usbh.h>
+#include <libbdk-hal/bdk-usb.h>
+#include <libbdk-hal/bdk-config.h>
+
+/* This code is an optional part of the BDK. It is only linked in
+ if BDK_REQUIRE() needs it */
+BDK_REQUIRE_DEFINE(USB);
+
+/**
+ * Write to DWC3 indirect debug control register
+ *
+ * @param node Node to write to
+ * @param usb_port USB port to write to
+ * @param val 32bit value to write
+ */
+static void write_cr_dbg_cfg(bdk_node_t node, int usb_port, uint64_t val)
+{
+ if (!CAVIUM_IS_MODEL(CAVIUM_CN88XX))
+ BDK_CSR_WRITE(node, BDK_USBDRDX_UCTL_PORTX_CR_DBG_CFG(usb_port, 0), val);
+ else
+ BDK_CSR_WRITE(node, BDK_USBHX_UCTL_PORTX_CR_DBG_CFG(usb_port, 0), val);
+}
+
+/**
+ * Poll the DWC3 internal status until the ACK bit matches a desired value. Return
+ * the final status.
+ *
+ * @param node Node to query
+ * @param usb_port USB port to query
+ * @param desired_ack
+ * Desired ACK bit state
+ *
+ * @return Final status with ACK at correct state
+ */
+static bdk_usbdrdx_uctl_portx_cr_dbg_status_t get_cr_dbg_status(bdk_node_t node, int usb_port, int desired_ack)
+{
+ const int TIMEOUT = 1000000; /* 1 sec */
+ bdk_usbdrdx_uctl_portx_cr_dbg_status_t status;
+ if (!CAVIUM_IS_MODEL(CAVIUM_CN88XX))
+ {
+ if (BDK_CSR_WAIT_FOR_FIELD(node, BDK_USBDRDX_UCTL_PORTX_CR_DBG_STATUS(usb_port, 0), ack, ==, desired_ack, TIMEOUT))
+ {
+ BDK_TRACE(USB_XHCI, "N%d.USB%d: Timeout waiting for indirect ACK\n", node, usb_port);
+ status.u = -1;
+ }
+ else
+ status.u = BDK_CSR_READ(node, BDK_USBDRDX_UCTL_PORTX_CR_DBG_STATUS(usb_port, 0));
+ }
+ else
+ {
+ if (BDK_CSR_WAIT_FOR_FIELD(node, BDK_USBHX_UCTL_PORTX_CR_DBG_STATUS(usb_port, 0), ack, ==, desired_ack, TIMEOUT))
+ {
+ BDK_TRACE(USB_XHCI, "N%d.USB%d: Timeout waiting for indirect ACK\n", node, usb_port);
+ status.u = -1;
+ }
+ else
+ status.u = BDK_CSR_READ(node, BDK_USBHX_UCTL_PORTX_CR_DBG_STATUS(usb_port, 0));
+ }
+ return status;
+}
+
+/**
+ * Perform an indirect read of an internal register inside the DWC3 usb block
+ *
+ * @param node Node to read
+ * @param usb_port USB port to read
+ * @param addr Indirect register address
+ *
+ * @return Value of the indirect register
+ */
+static uint32_t dwc3_uphy_indirect_read(bdk_node_t node, int usb_port, uint32_t addr)
+{
+ bdk_usbdrdx_uctl_portx_cr_dbg_cfg_t dbg_cfg;
+ bdk_usbdrdx_uctl_portx_cr_dbg_status_t status;
+
+ /* See the CSR description for USBHX_UCTL_PORTX_CR_DBG_CFG, which describes
+ the steps implemented by this function */
+
+ dbg_cfg.u = 0;
+ dbg_cfg.s.data_in = addr;
+ write_cr_dbg_cfg(node, usb_port, dbg_cfg.u);
+
+ dbg_cfg.s.cap_addr = 1;
+ write_cr_dbg_cfg(node, usb_port, dbg_cfg.u);
+
+ status = get_cr_dbg_status(node, usb_port, 1);
+ if (status.u == (uint64_t)-1)
+ return 0xffffffff;
+
+ write_cr_dbg_cfg(node, usb_port, 0);
+ get_cr_dbg_status(node, usb_port, 0);
+
+ dbg_cfg.u = 0;
+ dbg_cfg.s.read = 1;
+ write_cr_dbg_cfg(node, usb_port, dbg_cfg.u);
+
+ status = get_cr_dbg_status(node, usb_port, 1);
+
+ write_cr_dbg_cfg(node, usb_port, 0);
+ get_cr_dbg_status(node, usb_port, 0);
+
+ return status.s.data_out;
+}
+
+/**
+ * Perform an indirect write of an internal register inside the DWC3 usb block
+ *
+ * @param node Node to write
+ * @param usb_port USB port to write
+ * @param addr Indirect register address
+ * @param value Value for write
+ */
+static void dwc3_uphy_indirect_write(bdk_node_t node, int usb_port, uint32_t addr, uint16_t value)
+{
+ bdk_usbdrdx_uctl_portx_cr_dbg_cfg_t dbg_cfg;
+
+ /* See the CSR description for USBHX_UCTL_PORTX_CR_DBG_CFG, which describes
+ the steps implemented by this function */
+
+ dbg_cfg.u = 0;
+ dbg_cfg.s.data_in = addr;
+ write_cr_dbg_cfg(node, usb_port, dbg_cfg.u);
+
+ dbg_cfg.s.cap_addr = 1;
+ write_cr_dbg_cfg(node, usb_port, dbg_cfg.u);
+
+ get_cr_dbg_status(node, usb_port, 1);
+
+ write_cr_dbg_cfg(node, usb_port, 0);
+ get_cr_dbg_status(node, usb_port, 0);
+
+ dbg_cfg.u = 0;
+ dbg_cfg.s.data_in = value;
+ write_cr_dbg_cfg(node, usb_port, dbg_cfg.u);
+
+ dbg_cfg.s.cap_data = 1;
+ write_cr_dbg_cfg(node, usb_port, dbg_cfg.u);
+
+ get_cr_dbg_status(node, usb_port, 1);
+
+ write_cr_dbg_cfg(node, usb_port, 0);
+ get_cr_dbg_status(node, usb_port, 0);
+
+ dbg_cfg.u = 0;
+ dbg_cfg.s.write = 1;
+ write_cr_dbg_cfg(node, usb_port, dbg_cfg.u);
+
+ get_cr_dbg_status(node, usb_port, 1);
+
+ write_cr_dbg_cfg(node, usb_port, 0);
+ get_cr_dbg_status(node, usb_port, 0);
+}
+
+/**
+ * Errata USB-29206 - The USB HS PLL in all 28nm devices has a
+ * design issue that may cause the VCO to lock up on
+ * initialization. The Synopsys VCO is designed with an even
+ * number of stages and no kick-start circuit, which makes us
+ * believe that there is no question a latched up
+ * (non-oscillating) state is possible. The workaround is to
+ * check the PLL lock bit, which is just based on a counter and
+ * will not set if the VCO is not oscillating, and if it's not
+ * set do a power down/power up cycle on the PLL, which tests
+ * have proven is much more likely to guarantee the VCO will
+ * start oscillating. Part of the problem appears to be that
+ * the normal init sequence holds the VCO in reset during the
+ * power up sequence, whereas the plain power up/down sequence
+ * does not, so the voltage changing may be helping the circuit
+ * to oscillate.
+ *
+ * @param node Node to check
+ * @param usb_port USB port to check
+ *
+ * @return Zero on success, negative on failure
+ */
+static int dwc3_uphy_check_pll(bdk_node_t node, int usb_port)
+{
+ /* Internal indirect register that reports if the phy PLL has lock. This will
+ be 1 if lock, 0 if no lock */
+ const int DWC3_INT_IND_PLL_LOCK_REG = 0x200b;
+ /* Internal indirect UPHY register that controls the power to the UPHY PLL */
+ const int DWC3_INT_IND_UPHY_PLL_PU = 0x2012;
+ /* Write enable bit for DWC3_INT_IND_PLL_POWER_CTL */
+ const int DWC3_INT_IND_UPHY_PLL_PU_WE = 0x20;
+ /* Power enable bit for DWC3_INT_IND_PLL_POWER_CTL */
+ const int DWC3_INT_IND_UPHY_PLL_PU_POWER_EN = 0x02;
+
+ uint32_t pll_locked = dwc3_uphy_indirect_read(node, usb_port, DWC3_INT_IND_PLL_LOCK_REG);
+ int retry_count = 0;
+ while (!pll_locked)
+ {
+ if (retry_count >= 3)
+ {
+ bdk_error("N%d.USB%d: USB2 PLL failed to lock\n", node, usb_port);
+ return -1;
+ }
+
+ retry_count++;
+ BDK_TRACE(USB_XHCI, "N%d.USB%d: USB2 PLL didn't lock, retry %d\n", node, usb_port, retry_count);
+
+ /* Turn on write enable for PLL power control */
+ uint32_t pwr_val = dwc3_uphy_indirect_read(node, usb_port, DWC3_INT_IND_UPHY_PLL_PU);
+ pwr_val |= DWC3_INT_IND_UPHY_PLL_PU_WE;
+ dwc3_uphy_indirect_write(node, usb_port, DWC3_INT_IND_UPHY_PLL_PU, pwr_val);
+
+ /* Power down the PLL */
+ pwr_val &= ~DWC3_INT_IND_UPHY_PLL_PU_POWER_EN;
+ dwc3_uphy_indirect_write(node, usb_port, DWC3_INT_IND_UPHY_PLL_PU, pwr_val);
+ bdk_wait_usec(1000);
+
+ /* Power on the PLL */
+ pwr_val |= DWC3_INT_IND_UPHY_PLL_PU_POWER_EN;
+ dwc3_uphy_indirect_write(node, usb_port, DWC3_INT_IND_UPHY_PLL_PU, pwr_val);
+ bdk_wait_usec(1000);
+
+ /* Check for PLL Lock again */
+ pll_locked = dwc3_uphy_indirect_read(node, usb_port, DWC3_INT_IND_PLL_LOCK_REG);
+ }
+ return 0;
+}
+
+/**
+ * Initialize the clocks for USB such that it is ready for a generic XHCI driver
+ *
+ * @param node Node to init
+ * @param usb_port Port to intialize
+ * @param clock_type Type of clock connected to the usb port
+ *
+ * @return Zero on success, negative on failure
+ */
+
+int bdk_usb_initialize(bdk_node_t node, int usb_port, bdk_usb_clock_t clock_type)
+{
+ int is_usbdrd = !CAVIUM_IS_MODEL(CAVIUM_CN88XX);
+
+ /* Perform the following steps to initiate a cold reset. */
+
+ /* 1. Wait for all voltages to reach a stable state. Ensure the
+ reference clock is up and stable.
+ a. If 3.3V is up first, 0.85V must be soon after (within tens of ms). */
+
+ /* 2. Wait for IOI reset to deassert. */
+
+ /* 3. If Over Current indication and/or Port Power Control features
+ are desired, program the GPIO CSRs appropriately.
+ a. For Over Current Indication, select a GPIO for the input and
+ program GPIO_USBH_CTL[SEL].
+ b. For Port Power Control, set one of
+ GPIO_BIT_CFG(0..19)[OUTPUT_SEL] = USBH_VBUS_CTRL. */
+
+ /* 4. Assert all resets:
+ a. UPHY reset: USBDRD(0..1)_UCTL_CTL[UPHY_RST] = 1
+ b. UAHC reset: USBDRD(0..1)_UCTL_CTL[UAHC_RST] = 1
+ c. UCTL reset: USBDRD(0..1)_UCTL_CTL[UCTL_RST] = 1 */
+ if (is_usbdrd)
+ {
+ BDK_CSR_MODIFY(c, node, BDK_USBDRDX_UCTL_CTL(usb_port),
+ c.s.uphy_rst = 1;
+ c.s.uahc_rst = 1;
+ c.s.uctl_rst = 1);
+ }
+ else
+ {
+ BDK_CSR_MODIFY(c, node, BDK_USBHX_UCTL_CTL(usb_port),
+ c.s.uphy_rst = 1;
+ c.s.uahc_rst = 1;
+ c.s.uctl_rst = 1);
+ }
+
+ /* 5. Configure the controller clock:
+ a. Reset the clock dividers: USBDRD(0..1)_UCTL_CTL[H_CLKDIV_RST] = 1.
+ b. Select the controller clock frequency
+ USBDRD(0..1)_UCTL_CTL[H_CLKDIV] = desired value.
+ USBDRD(0..1)_UCTL_CTL[H_CLKDIV_EN] = 1 to enable the controller
+ clock.
+ Read USBDRD(0..1)_UCTL_CTL to ensure the values take effect.
+ c. Deassert the controller clock divider reset: USB-
+ DRD(0..1)_UCTL_CTL[H_CLKDIV_RST] = 0. */
+ uint64_t sclk_rate = bdk_clock_get_rate(node, BDK_CLOCK_SCLK);
+ uint64_t divider = (sclk_rate + 300000000-1) / 300000000;
+ /*
+ ** According to HRM Rules are:
+ ** - clock must be below 300MHz
+ ** USB3 full-rate requires 150 MHz or better
+ ** USB3 requires 125 MHz
+ ** USB2 full rate requires 90 MHz
+ ** USB2 requires 62.5 MHz
+ */
+ if (divider <= 1)
+ divider = 0;
+ else if (divider <= 2)
+ divider = 1;
+ else if (divider <= 4)
+ divider = 2;
+ else if (divider <= 6)
+ divider = 3;
+ else if (divider <= 8)
+ divider = 4;
+ else if (divider <= 16)
+ divider = 5;
+ else if (divider <= 24)
+ divider = 6;
+ else
+ divider = 7;
+ if (is_usbdrd)
+ {
+ BDK_CSR_MODIFY(c, node, BDK_USBDRDX_UCTL_CTL(usb_port),
+ c.s.h_clkdiv_rst = 1);
+ BDK_CSR_MODIFY(c, node, BDK_USBDRDX_UCTL_CTL(usb_port),
+ c.s.h_clkdiv_sel = divider;
+ c.s.h_clk_en = 1);
+ BDK_CSR_MODIFY(c, node, BDK_USBDRDX_UCTL_CTL(usb_port),
+ c.s.h_clkdiv_rst = 0);
+ }
+ else
+ {
+ BDK_CSR_MODIFY(c, node, BDK_USBHX_UCTL_CTL(usb_port),
+ c.s.h_clkdiv_rst = 1);
+ BDK_CSR_MODIFY(c, node, BDK_USBHX_UCTL_CTL(usb_port),
+ c.s.h_clkdiv_sel = divider;
+ c.s.h_clk_en = 1);
+ BDK_CSR_MODIFY(c, node, BDK_USBHX_UCTL_CTL(usb_port),
+ c.s.h_clkdiv_rst = 0);
+ }
+ {
+ static bool printit[2] = {true,true};
+ if (printit[usb_port]) {
+ uint64_t fr_div;
+ if (divider < 5) fr_div = divider * 2;
+ else fr_div = 8 * (divider - 3);
+ uint64_t freq = (typeof(freq)) (sclk_rate / fr_div);
+ const char *token;
+ if (freq < 62500000ULL) token = "???Low";
+ else if (freq < 90000000ULL) token = "USB2";
+ else if (freq < 125000000ULL) token = "USB2 Full";
+ else if (freq < 150000000ULL) token = "USB3";
+ else token = "USB3 Full";
+ BDK_TRACE(USB_XHCI, "Freq %lld - %s\n",
+ (unsigned long long)freq, token);
+ printit[usb_port] = false;
+ }
+ }
+
+ /* 6. Configure the strap signals in USBDRD(0..1)_UCTL_CTL.
+ a. Reference clock configuration (see Table 31.2): USB-
+ DRD(0..1)_UCTL_CTL[REF_CLK_FSEL, MPLL_MULTIPLIER,
+ REF_CLK_SEL, REF_CLK_DIV2].
+ b. Configure and enable spread-spectrum for SuperSpeed:
+ USBDRD(0..1)_UCTL_CTL[SSC_RANGE, SSC_EN, SSC_REF_CLK_SEL].
+ c. Enable USBDRD(0..1)_UCTL_CTL[REF_SSP_EN].
+ d. Configure PHY ports:
+ USBDRD(0..1)_UCTL_CTL[USB*_PORT_PERM_ATTACH, USB*_PORT_DISABLE]. */
+ if (is_usbdrd)
+ {
+ int ref_clk_src = 0;
+ int ref_clk_fsel = 0x27;
+ if (CAVIUM_IS_MODEL(CAVIUM_CN83XX)) {
+ if (BDK_USB_CLOCK_SS_PAD_HS_PAD != clock_type) {
+ bdk_error("Node %d usb_port %d: usb clock type %d is invalid\n", node, usb_port, clock_type);
+ return -1;
+ }
+ }
+ else if (CAVIUM_IS_MODEL(CAVIUM_CN81XX)) {
+ switch (clock_type)
+ {
+ default:
+ bdk_error("Node %d usb_port %d: usb clock type %d is invalid\n", node, usb_port, clock_type);
+ return -1;
+ case BDK_USB_CLOCK_SS_PAD_HS_PAD : ref_clk_src = 2; break;
+ case BDK_USB_CLOCK_SS_REF0_HS_REF0 : ref_clk_src = 0; break; /* Superspeed and high speed use DLM/QLM ref clock 0 */
+ case BDK_USB_CLOCK_SS_REF1_HS_REF1 : ref_clk_src = 1; break; /* Superspeed and high speed use DLM/QLM ref clock 1 */
+ case BDK_USB_CLOCK_SS_PAD_HS_PLL : ref_clk_src = 6; ref_clk_fsel = 0x7; break; /* Superspeed uses PAD clock, high speed uses PLL ref clock */
+ case BDK_USB_CLOCK_SS_REF0_HS_PLL : ref_clk_src = 4; ref_clk_fsel = 0x7; break; /* Superspeed uses DLM/QLM ref clock 0, high speed uses PLL ref clock */
+ case BDK_USB_CLOCK_SS_REF1_HS_PLL: ref_clk_src = 5; ref_clk_fsel =0x7; break; /* Superspeed uses DLM/QLM ref clock 1, high speed uses PLL ref clock */
+ }
+ }
+ BDK_CSR_MODIFY(c, node, BDK_USBDRDX_UCTL_CTL(usb_port),
+ c.s.ref_clk_fsel = ref_clk_fsel;
+ c.s.mpll_multiplier = 0x19;
+ c.s.ref_clk_sel = ref_clk_src;
+ c.s.ref_clk_div2 = 0);
+ BDK_CSR_MODIFY(c, node, BDK_USBDRDX_UCTL_CTL(usb_port),
+ c.s.ssc_en = 1;
+ c.s.ssc_ref_clk_sel = 0);
+ BDK_CSR_MODIFY(c, node, BDK_USBDRDX_UCTL_CTL(usb_port),
+ c.s.ref_ssp_en = 1);
+ }
+ else
+ {
+ if (BDK_USB_CLOCK_SS_PAD_HS_PAD != clock_type) {
+ bdk_error("Node %d usb_port %d: usb clock type %d is invalid\n", node, usb_port, clock_type);
+ return -1;
+ }
+ BDK_CSR_MODIFY(c, node, BDK_USBHX_UCTL_CTL(usb_port),
+ c.s.ref_clk_fsel = 0x27;
+ c.s.mpll_multiplier = 0;
+ c.s.ref_clk_sel = 0;
+ c.s.ref_clk_div2 = 0);
+ BDK_CSR_MODIFY(c, node, BDK_USBHX_UCTL_CTL(usb_port),
+ c.s.ssc_en = 1;
+ c.s.ssc_ref_clk_sel = 0);
+ BDK_CSR_MODIFY(c, node, BDK_USBHX_UCTL_CTL(usb_port),
+ c.s.ref_ssp_en = 1);
+ }
+ /* Hardware default is for ports to be enabled and not perm attach. Don't
+ change it */
+
+ /* 7. The PHY resets in lowest-power mode. Power up the per-port PHY
+ logic by enabling the following:
+ a. USBDRD(0..1)_UCTL_CTL [HS_POWER_EN] if high-speed/full-speed/low-
+ speed functionality needed.
+ b. USBDRD(0..1)_UCTL_CTL [SS_POWER_EN] if SuperSpeed functionality
+ needed. */
+ if (is_usbdrd)
+ {
+ BDK_CSR_MODIFY(c, node, BDK_USBDRDX_UCTL_CTL(usb_port),
+ c.s.hs_power_en = 1;
+ c.s.ss_power_en = 1);
+ }
+ else
+ {
+ BDK_CSR_MODIFY(c, node, BDK_USBHX_UCTL_CTL(usb_port),
+ c.s.hs_power_en = 1;
+ c.s.ss_power_en = 1);
+ }
+
+ /* 8. Wait 10 controller-clock cycles from step 5. for controller clock
+ to start and async FIFO to properly reset. */
+ bdk_wait_usec(1);
+
+ /* 9. Deassert UCTL and UAHC resets:
+ a. USBDRD(0..1)_UCTL_CTL[UCTL_RST] = 0
+ b. USBDRD(0..1)_UCTL_CTL[UAHC_RST] = 0
+ c. [optional] For port-power control:
+ - Set one of GPIO_BIT_CFG(0..47)[PIN_SEL] = USB0_VBUS_CTRLor USB1_VBUS_CTRL.
+ - Set USBDRD(0..1)_UCTL_HOST_CFG[PPC_EN] = 1 and USBDRD(0..1)_UCTL_HOST_CFG[PPC_ACTIVE_HIGH_EN] = 1.
+ - Wait for the external power management chip to power the VBUS.ional port-power control.
+ ]
+ d. You will have to wait 10 controller-clock cycles before accessing
+ any controller-clock-only registers. */
+ if (is_usbdrd)
+ {
+ BDK_CSR_MODIFY(c, node, BDK_USBDRDX_UCTL_CTL(usb_port),
+ c.s.uctl_rst = 0);
+ }
+ else
+ {
+ BDK_CSR_MODIFY(c, node, BDK_USBHX_UCTL_CTL(usb_port),
+ c.s.uctl_rst = 0);
+ }
+ bdk_wait_usec(1);
+
+ int usb_gpio = bdk_config_get_int(BDK_CONFIG_USB_PWR_GPIO, node, usb_port);
+ int usb_polarity = bdk_config_get_int(BDK_CONFIG_USB_PWR_GPIO_POLARITY, node, usb_port);
+ if (-1 != usb_gpio) {
+ int gsrc = BDK_GPIO_PIN_SEL_E_USBX_VBUS_CTRL_CN88XX(usb_port);
+ if (CAVIUM_IS_MODEL(CAVIUM_CN88XX)) {
+ gsrc = BDK_GPIO_PIN_SEL_E_USBX_VBUS_CTRL_CN88XX(usb_port);
+ }
+ else if (CAVIUM_IS_MODEL(CAVIUM_CN81XX)) {
+ gsrc = BDK_GPIO_PIN_SEL_E_USBX_VBUS_CTRL_CN81XX(usb_port);
+ }
+ else if (CAVIUM_IS_MODEL(CAVIUM_CN83XX)) {
+ gsrc = BDK_GPIO_PIN_SEL_E_USBX_VBUS_CTRL_CN83XX(usb_port);}
+ else {
+ bdk_error("USB_VBUS_CTRL GPIO: unknown chip model\n");
+ }
+
+ BDK_CSR_MODIFY(c,node,BDK_GPIO_BIT_CFGX(usb_gpio),
+ c.s.pin_sel = gsrc;
+ c.s.pin_xor = (usb_polarity) ? 0 : 1;
+ );
+
+ if (is_usbdrd)
+ {
+ BDK_CSR_MODIFY(c, node, BDK_USBDRDX_UCTL_HOST_CFG(usb_port),
+ c.s.ppc_en = 1;
+ c.s.ppc_active_high_en = 1);
+ }
+ else
+ {
+ BDK_CSR_MODIFY(c, node, BDK_USBHX_UCTL_HOST_CFG(usb_port),
+ c.s.ppc_en = 1;
+ c.s.ppc_active_high_en = 1);
+ }
+ bdk_wait_usec(100000);
+ }
+
+ if (is_usbdrd)
+ {
+ BDK_CSR_MODIFY(c, node, BDK_USBDRDX_UCTL_CTL(usb_port),
+ c.s.uahc_rst = 0);
+ }
+ else
+ {
+ BDK_CSR_MODIFY(c, node, BDK_USBHX_UCTL_CTL(usb_port),
+ c.s.uahc_rst = 0);
+ }
+
+ bdk_wait_usec(100000);
+ bdk_wait_usec(1);
+
+ /* 10. Enable conditional coprocessor clock of UCTL by writing USB-
+ DRD(0..1)_UCTL_CTL[CSCLK_EN] = 1. */
+ if (is_usbdrd)
+ {
+ if (CAVIUM_IS_MODEL(CAVIUM_CN8XXX))
+ {
+ /* CN9XXX make coprocessor clock automatic */
+ BDK_CSR_MODIFY(c, node, BDK_USBDRDX_UCTL_CTL(usb_port),
+ c.cn83xx.csclk_en = 1);
+ }
+ }
+ else
+ {
+ BDK_CSR_MODIFY(c, node, BDK_USBHX_UCTL_CTL(usb_port),
+ c.s.csclk_en = 1);
+ }
+
+ /* 11. Set USBDRD(0..1)_UCTL_CTL[DRD_MODE] to 1 for device mode, 0 for
+ host mode. */
+ if (is_usbdrd)
+ {
+ BDK_CSR_MODIFY(c, node, BDK_USBDRDX_UCTL_CTL(usb_port),
+ c.s.drd_mode = 0);
+ }
+
+ /* 12. Soft reset the UPHY and UAHC logic via the UAHC controls:
+ a. USBDRD(0..1)_UAHC_GUSB2PHYCFG(0)[PHYSOFTRST] = 1
+ b. USBDRD(0..1)_UAHC_GUSB3PIPECTL(0)[PHYSOFTRST] = 1
+ c. USBDRD(0..1)_UAHC_GCTL[CORESOFTRESET] = 1 */
+ if (is_usbdrd)
+ {
+ BDK_CSR_MODIFY(c, node, BDK_USBDRDX_UAHC_GUSB2PHYCFGX(usb_port, 0),
+ c.s.physoftrst = 1);
+ BDK_CSR_MODIFY(c, node, BDK_USBDRDX_UAHC_GUSB3PIPECTLX(usb_port, 0),
+ c.s.physoftrst = 1);
+ BDK_CSR_MODIFY(c, node, BDK_USBDRDX_UAHC_GCTL(usb_port),
+ c.s.coresoftreset = 1);
+ }
+ else
+ {
+ BDK_CSR_MODIFY(c, node, BDK_USBHX_UAHC_GUSB2PHYCFGX(usb_port, 0),
+ c.s.physoftrst = 1);
+ BDK_CSR_MODIFY(c, node, BDK_USBHX_UAHC_GUSB3PIPECTLX(usb_port, 0),
+ c.s.physoftrst = 1);
+ BDK_CSR_MODIFY(c, node, BDK_USBHX_UAHC_GCTL(usb_port),
+ c.s.coresoftreset = 1);
+ }
+
+ /* 13. Program USBDRD(0..1)_UAHC_GCTL[PRTCAPDIR] to 0x2 for device mode
+ or 0x1 for host mode. */
+ if (is_usbdrd)
+ {
+ BDK_CSR_MODIFY(c, node, BDK_USBDRDX_UAHC_GCTL(usb_port),
+ c.s.prtcapdir = 1);
+ }
+ else
+ {
+ BDK_CSR_MODIFY(c, node, BDK_USBHX_UAHC_GCTL(usb_port),
+ c.s.prtcapdir = 1);
+ }
+
+ /* 14. Wait 10us after step 13. for the PHY to complete its reset. */
+ bdk_wait_usec(10);
+
+ /* 15. Deassert UPHY reset: USBDRD(0..1)_UCTL_CTL[UPHY_RST] = 0. */
+ if (is_usbdrd)
+ {
+ BDK_CSR_MODIFY(c, node, BDK_USBDRDX_UCTL_CTL(usb_port),
+ c.s.uphy_rst = 0);
+ }
+ else
+ {
+ BDK_CSR_MODIFY(c, node, BDK_USBHX_UCTL_CTL(usb_port),
+ c.s.uphy_rst = 0);
+ }
+
+ /* 16. Wait for at least 45us after step 15. for UPHY to output
+ stable PHYCLOCK. */
+ bdk_wait_usec(45);
+
+ /* Workround Errata USB-29206 */
+ if (dwc3_uphy_check_pll(node, usb_port))
+ return -1;
+
+ /* 17. Initialize any other strap signals necessary and make sure they
+ propagate by reading back the last register written.
+ a. UCTL
+ USBDRD(0..1)_UCTL_PORT0_CFG_*[*_TUNE]
+ USBDRD(0..1)_UCTL_PORT0_CFG_*[PCS_*]
+ USBDRD(0..1)_UCTL_PORT0_CFG_*[LANE0_TX_TERM_OFFSET]
+ USBDRD(0..1)_UCTL_PORT0_CFG_*[TX_VBOOST_LVL]
+ USBDRD(0..1)_UCTL__PORT0_CFG_*[LOS_BIAS]
+ USBDRD(0..1)_UCTL_HOST_CFG
+ USBDRD(0..1)_UCTL_SHIM_CFG
+ b. UAHC: only the following UAHC registers are accessible during
+ CoreSoftReset.
+ USBDRD(0..1)_UAHC_GCTL
+ USBDRD(0..1)_UAHC_GUCTL
+ USBDRD(0..1)_UAHC_GSTS
+ USBDRD(0..1)_UAHC_GUID
+ USBDRD(0..1)_UAHC_GUSB2PHYCFG(0)
+ USBDRD(0..1)_UAHC_GUSB3PIPECTL(0) */
+
+ /* 18. Release soft reset the UPHY and UAHC logic via the UAHC controls:
+ a. USBDRD(0..1)_UAHC_GUSB2PHYCFG(0)[PHYSOFTRST] = 0
+ b. USBDRD(0..1)_UAHC_GUSB3PIPECTL(0)[PHYSOFTRST] = 0
+ c. USBDRD(0..1)_UAHC_GCTL[CORESOFTRESET] = 0 */
+ if (is_usbdrd)
+ {
+ BDK_CSR_MODIFY(c, node, BDK_USBDRDX_UAHC_GUSB2PHYCFGX(usb_port, 0),
+ c.s.physoftrst = 0);
+ BDK_CSR_MODIFY(c, node, BDK_USBDRDX_UAHC_GUSB3PIPECTLX(usb_port, 0),
+ c.s.physoftrst = 0);
+ BDK_CSR_MODIFY(c, node, BDK_USBDRDX_UAHC_GCTL(usb_port),
+ c.s.coresoftreset = 0);
+ }
+ else
+ {
+ BDK_CSR_MODIFY(c, node, BDK_USBHX_UAHC_GUSB2PHYCFGX(usb_port, 0),
+ c.s.physoftrst = 0);
+ BDK_CSR_MODIFY(c, node, BDK_USBHX_UAHC_GUSB3PIPECTLX(usb_port, 0),
+ c.s.physoftrst = 0);
+ BDK_CSR_MODIFY(c, node, BDK_USBHX_UAHC_GCTL(usb_port),
+ c.s.coresoftreset = 0);
+ }
+
+ /* 19. Configure the remaining UAHC_G* registers as needed, including
+ any that were not configured in step 17.-b. */
+
+ /* 20. Initialize the USB controller:
+ a. To initialize the UAHC as a USB host controller, the application
+ should perform the steps described in the xHCI specification
+ (UAHC_X* registers). The xHCI sequence starts with poll for a 0 in
+ USBDRD(0..1)_UAHC_USBSTS[CNR].
+ b. To initialize the UAHC as a device, the application should TBD. The
+ device initiation sequence starts with a device soft reset by
+ setting USBDRD(0..1)_UAHC_DCTL[CSFTRST] = 1 and wait for a read
+ operation to return 0. */
+ return 0;
+}
diff --git a/src/vendorcode/cavium/bdk/libbdk-hal/device/bdk-device.c b/src/vendorcode/cavium/bdk/libbdk-hal/device/bdk-device.c
new file mode 100644
index 0000000000..a8e65f061a
--- /dev/null
+++ b/src/vendorcode/cavium/bdk/libbdk-hal/device/bdk-device.c
@@ -0,0 +1,721 @@
+/***********************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 <string.h>
+#include "libbdk-arch/bdk-csrs-ap.h"
+#include "libbdk-arch/bdk-csrs-pccpf.h"
+#include "libbdk-hal/bdk-ecam.h"
+#include "libbdk-hal/device/bdk-device.h"
+#include "libbdk-hal/bdk-config.h"
+#include "libbdk-driver/bdk-driver.h"
+#include "libbdk-hal/bdk-utils.h"
+
+static struct bdk_driver_s *driver_list = NULL;
+
+#define DEVICE_GROW 64
+static bdk_device_t *device_list = NULL;
+static int device_list_count = 0;
+static int device_list_max = 0;
+
+/**
+ * Called to register a new driver with the bdk-device system. Drivers are probed
+ * and initialized as device are found for them. If devices have already been
+ * added before the driver was registered, the driver will be probed and
+ * initialized before this function returns.
+ *
+ * @param driver Driver functions
+ *
+ * @return Zero on success, negative on failure
+ */
+int bdk_device_add_driver(struct bdk_driver_s *driver)
+{
+ driver->next = driver_list;
+ driver_list = driver;
+ BDK_TRACE(DEVICE, "Added driver for %08x\n", driver->id);
+ return 0;
+}
+
+/**
+ * Lookup the correct driver for a device
+ *
+ * @param device Device to lookup
+ *
+ * @return Driver, or NULL on failure
+ */
+static const bdk_driver_t *lookup_driver(const bdk_device_t *device)
+{
+ const bdk_driver_t *drv = driver_list;
+ while (drv)
+ {
+ if (drv->id == device->id)
+ return drv;
+ drv = drv->next;
+ }
+ return NULL;
+}
+
+/**
+ * Populate the fields of a new device from the ECAM
+ *
+ * @param device Device to populate
+ */
+static void populate_device(bdk_device_t *device)
+{
+ /* The default name may be replaced by the driver with something easier to read */
+ snprintf(device->name, sizeof(device->name), "N%d.E%d:%d:%d.%d",
+ device->node, device->ecam, device->bus, device->dev, device->func);
+
+ BDK_TRACE(DEVICE_SCAN, "%s: Populating device\n", device->name);
+
+ /* Get the current chip ID and pass. We'll need this to fill in version
+ information for the device */
+ bdk_ap_midr_el1_t midr_el1;
+ BDK_MRS(MIDR_EL1, midr_el1.u);
+
+ /* PCCPF_XXX_VSEC_SCTL[RID] with the revision of the chip,
+ read from fuses */
+ BDK_CSR_DEFINE(sctl, BDK_PCCPF_XXX_VSEC_SCTL);
+ sctl.u = bdk_ecam_read32(device, BDK_PCCPF_XXX_VSEC_SCTL);
+ sctl.s.rid = midr_el1.s.revision | (midr_el1.s.variant<<3);
+ sctl.s.node = device->node; /* Program node bits */
+ sctl.s.ea = bdk_config_get_int(BDK_CONFIG_PCIE_EA);
+ if (CAVIUM_IS_MODEL(CAVIUM_CN88XX_PASS1_X))
+ sctl.s.ea = 0; /* EA is not supported on CN88XX pass 1.x */
+ else
+ sctl.s.ea = bdk_config_get_int(BDK_CONFIG_PCIE_EA);
+ bdk_ecam_write32(device, BDK_PCCPF_XXX_VSEC_SCTL, sctl.u);
+
+ /* Read the Device ID */
+ device->id = bdk_ecam_read32(device, BDK_PCCPF_XXX_ID);
+
+ /* Read the Device Type so we know how to handle BARs */
+ bdk_pccpf_xxx_clsize_t clsize;
+ clsize.u = bdk_ecam_read32(device, BDK_PCCPF_XXX_CLSIZE);
+ int isbridge = (clsize.s.hdrtype & 0x7f) == 1;
+
+ BDK_TRACE(DEVICE_SCAN, "%s: Device ID: 0x%08x%s\n", device->name, device->id,
+ (isbridge) ? " (Bridge)" : "");
+
+ /* Loop through all the BARs */
+ int max_bar = (isbridge) ? BDK_PCCPF_XXX_BAR0U : BDK_PCCPF_XXX_BAR4U;
+ int bar = BDK_PCCPF_XXX_BAR0L;
+ unsigned guess_instance = 0;
+ while (bar <= max_bar)
+ {
+ int bar_index = (bar - BDK_PCCPF_XXX_BAR0L) / 8;
+ /* Read the BAR address and config bits [3:0] */
+ uint64_t address = bdk_ecam_read32(device, bar);
+ int ismem = !(address & 1); /* Bit 0: 0 = mem, 1 = io */
+ int is64 = ismem && (address & 4); /* Bit 2: 0 = 32 bit, 1 = 64 bit if mem */
+ /* Bit 3: 1 = Is prefetchable. We on't care for now */
+
+ /* All internal BARs should be 64 bit. Skip if BAR isn't as that means
+ it is using Enhanced Allocation (EA) */
+ if (!is64)
+ {
+ BDK_TRACE(DEVICE_SCAN, "%s: BAR%d Disabled or EA bar skipped (0x%08llx)\n", device->name, bar_index, address);
+ bar += 8;
+ continue;
+ }
+
+ /* Get the upper part of 64bit BARs */
+ address |= (uint64_t)bdk_ecam_read32(device, bar + 4) << 32;
+
+ /* Write the bits to determine the size */
+ bdk_ecam_write32(device, bar, -1);
+ bdk_ecam_write32(device, bar + 4, -1);
+ uint64_t size_mask = (uint64_t)bdk_ecam_read32(device, bar + 4) << 32;
+ size_mask |= bdk_ecam_read32(device, bar);
+ /* Make sure the node bits are correct in the address */
+ address = (address & ~(3UL << 44)) | ((uint64_t)device->node << 44);
+ /* Restore address value */
+ bdk_ecam_write32(device, bar, address);
+ bdk_ecam_write32(device, bar + 4, address >> 32);
+
+ /* Convert the size into a power of 2 bits */
+ int size_bits = bdk_dpop(~size_mask | 0xf);
+ if (size_bits <= 4)
+ size_bits = 0;
+
+ /* Store the BAR info */
+ device->bar[bar_index].address = address & ~0xfull;
+ device->bar[bar_index].size2 = size_bits;
+ device->bar[bar_index].flags = address & 0xf;
+ BDK_TRACE(DEVICE_SCAN, "%s: BAR%d 0x%llx/%d flags=0x%x\n",
+ device->name, bar_index, device->bar[bar_index].address,
+ device->bar[bar_index].size2, device->bar[bar_index].flags);
+ /* Move to the next BAR */
+ bar += 8;
+ }
+
+ /* Walk the PCI capabilities looking for PCIe support and EA headers */
+ BDK_TRACE(DEVICE_SCAN, "%s: Walking PCI capabilites\n", device->name);
+ int has_pcie = 0;
+ bdk_pccpf_xxx_cap_ptr_t cap_ptr;
+ cap_ptr.u = bdk_ecam_read32(device, BDK_PCCPF_XXX_CAP_PTR);
+ int cap_loc = cap_ptr.s.cp;
+ while (cap_loc)
+ {
+ uint32_t cap = bdk_ecam_read32(device, cap_loc);
+ int cap_id = cap & 0xff;
+ int cap_next = (cap >> 8) & 0xff;
+
+ BDK_TRACE(DEVICE_SCAN, "%s: PCI Capability 0x%02x ID:0x%02x Next:0x%02x\n",
+ device->name, cap_loc, cap_id, cap_next);
+
+ if (cap_id == 0x10)
+ {
+ BDK_TRACE(DEVICE_SCAN, "%s: PCIe\n", device->name);
+ has_pcie = 1;
+ }
+ else if (cap_id == 0x01)
+ {
+ BDK_TRACE(DEVICE_SCAN, "%s: PCI Power Management Interface\n", device->name);
+ /* Do nothing for now */
+ }
+ else if (cap_id == 0x11)
+ {
+ bdk_pccpf_xxx_msix_cap_hdr_t msix_cap_hdr;
+ bdk_pccpf_xxx_msix_table_t msix_table;
+ bdk_pccpf_xxx_msix_pba_t msix_pba;
+ msix_cap_hdr.u = cap;
+ msix_table.u = bdk_ecam_read32(device, cap_loc + 4);
+ msix_pba.u = bdk_ecam_read32(device, cap_loc + 8);
+ BDK_TRACE(DEVICE_SCAN, "%s: MSI-X Entries:%d, Func Mask:%d, Enable:%d\n",
+ device->name, msix_cap_hdr.s.msixts + 1, msix_cap_hdr.s.funm, msix_cap_hdr.s.msixen);
+ BDK_TRACE(DEVICE_SCAN, "%s: Table BAR%d, Offset:0x%x\n",
+ device->name, msix_table.s.msixtbir, msix_table.s.msixtoffs * 8);
+ BDK_TRACE(DEVICE_SCAN, "%s: PBA BAR%d, Offset:0x%x\n",
+ device->name, msix_pba.s.msixpbir, msix_pba.s.msixpoffs * 8);
+ }
+ else if (cap_id == 0x05)
+ {
+ BDK_TRACE(DEVICE_SCAN, "%s: MSI\n", device->name);
+ /* Do nothing for now */
+ }
+ else if (cap_id == 0x14)
+ {
+ bdk_pccpf_xxx_ea_cap_hdr_t ea_cap_hdr;
+ ea_cap_hdr.u = cap;
+ cap_loc += 4;
+ BDK_TRACE(DEVICE_SCAN, "%s: Enhanced Allocation, %d entries\n",
+ device->name, ea_cap_hdr.s.num_entries);
+ if (isbridge)
+ {
+ cap = bdk_ecam_read32(device, cap_loc);
+ cap_loc += 4;
+ int fixed_secondary_bus = cap & 0xff;
+ int fixed_subordinate_bus = cap & 0xff;
+ BDK_TRACE(DEVICE_SCAN, "%s: Fixed Secondary Bus:0x%02x Fixed Subordinate Bus:0x%02x\n",
+ device->name, fixed_secondary_bus, fixed_subordinate_bus);
+ }
+ for (int entry = 0; entry < ea_cap_hdr.s.num_entries; entry++)
+ {
+ union bdk_pcc_ea_entry_s ea_entry;
+ memset(&ea_entry, 0, sizeof(ea_entry));
+ uint32_t *ptr = (uint32_t *)&ea_entry;
+ *ptr++ = bdk_ecam_read32(device, cap_loc);
+#if __BYTE_ORDER == __BIG_ENDIAN
+ /* For big endian we actually need the previous data
+ shifted 32 bits */
+ *ptr = ptr[-1];
+#endif
+ asm volatile ("" ::: "memory"); /* Needed by gcc 5.0 to detect aliases on ea_entry */
+ int entry_size = ea_entry.s.entry_size;
+ for (int i = 0; i < entry_size; i++)
+ {
+ *ptr++ = bdk_ecam_read32(device, cap_loc + 4*i + 4);
+ }
+#if __BYTE_ORDER == __BIG_ENDIAN
+ /* The upper and lower 32bits need to be swapped */
+ ea_entry.u[0] = (ea_entry.u[0] >> 32) | (ea_entry.u[0] << 32);
+ ea_entry.u[1] = (ea_entry.u[1] >> 32) | (ea_entry.u[1] << 32);
+ ea_entry.u[2] = (ea_entry.u[2] >> 32) | (ea_entry.u[2] << 32);
+#endif
+ asm volatile ("" ::: "memory"); /* Needed by gcc 5.0 to detect aliases on ea_entry */
+ BDK_TRACE(DEVICE_SCAN, "%s: Enable:%d Writeable:%d Secondary Prop:0x%02x Primary Prop:0x%02x BEI:%d Size:%d\n",
+ device->name, ea_entry.s.enable, ea_entry.s.w, ea_entry.s.sec_prop, ea_entry.s.pri_prop, ea_entry.s.bei, ea_entry.s.entry_size);
+ if (ea_entry.s.entry_size > 0)
+ {
+ BDK_TRACE(DEVICE_SCAN, "%s: Base:0x%08x 64bit:%d\n",
+ device->name, ea_entry.s.basel << 2, ea_entry.s.base64);
+ }
+ if (ea_entry.s.entry_size > 1)
+ {
+ BDK_TRACE(DEVICE_SCAN, "%s: MaxOffset:0x%08x 64bit:%d\n",
+ device->name, (ea_entry.s.offsetl << 2) | 3, ea_entry.s.offset64);
+ }
+ if (ea_entry.s.entry_size > 2)
+ {
+ BDK_TRACE(DEVICE_SCAN, "%s: BaseUpper:0x%08x\n",
+ device->name, ea_entry.s.baseh);
+ }
+ if (ea_entry.s.entry_size > 3)
+ {
+ BDK_TRACE(DEVICE_SCAN, "%s: MaxOffsetUpper:0x%08x\n",
+ device->name, ea_entry.s.offseth);
+ }
+ if (ea_entry.s.enable)
+ {
+ uint64_t base = (uint64_t)ea_entry.s.baseh << 32;
+ base |= (uint64_t)ea_entry.s.basel << 2;
+ /* Make sure the node bits are correct in the address */
+ base = (base & ~(3UL << 44)) | ((uint64_t)device->node << 44);
+ uint64_t offset = (uint64_t)ea_entry.s.offseth << 32;
+ offset |= ((uint64_t)ea_entry.s.offsetl << 2) | 3;
+ switch (ea_entry.s.bei)
+ {
+ case 0: /* BAR 0 */
+ case 2: /* BAR 1 */
+ case 4: /* BAR 2 */
+ {
+ int bar_index = ea_entry.s.bei/2;
+ device->bar[bar_index].address = base;
+ device->bar[bar_index].size2 = bdk_dpop(offset);
+ device->bar[bar_index].flags = ea_entry.s.base64 << 2;
+ BDK_TRACE(DEVICE_SCAN, "%s: Updated BAR%d 0x%llx/%d flags=0x%x\n",
+ device->name, bar_index, device->bar[bar_index].address,
+ device->bar[bar_index].size2, device->bar[bar_index].flags);
+ if (0 == ea_entry.s.bei) {
+ /* PEMs eg PCIEEP and PCIERC do not have instance id
+ ** We can calculate it for PCIERC based on BAR0 allocation.
+ ** PCIEEP will be dropped by probe
+ */
+ guess_instance = (device->bar[bar_index].address >> 24) & 7;
+ }
+ break;
+ }
+ case 9: /* SR-IOV BAR 0 */
+ case 11: /* SR-IOV BAR 1 */
+ case 13: /* SR-IOV BAR 2 */
+ // FIXME
+ break;
+ }
+ }
+ cap_loc += ea_entry.s.entry_size * 4 + 4;
+ }
+ }
+ else
+ {
+ /* Unknown PCI capability */
+ bdk_warn("%s: ECAM device unknown PCI capability 0x%x\n", device->name, cap_id);
+ }
+ cap_loc = cap_next;
+ }
+
+ /* Walk the PCIe capabilities looking for instance header */
+ if (has_pcie)
+ {
+ BDK_TRACE(DEVICE_SCAN, "%s: Walking PCIe capabilites\n", device->name);
+ cap_loc = 0x100;
+ while (cap_loc)
+ {
+ uint32_t cap = bdk_ecam_read32(device, cap_loc);
+ int cap_id = cap & 0xffff;
+ int cap_ver = (cap >> 16) & 0xf;
+ int cap_next = cap >> 20;
+ BDK_TRACE(DEVICE_SCAN, "%s: PCIe Capability 0x%03x ID:0x%04x Version:0x%x Next:0x%03x\n",
+ device->name, cap_loc, cap_id, cap_ver, cap_next);
+ if (cap_id == 0xe)
+ {
+ /* ARI. Do nothing for now */
+ BDK_TRACE(DEVICE_SCAN, "%s: ARI\n", device->name);
+ }
+ else if (cap_id == 0xb)
+ {
+ /* Vendor specific*/
+ int vsec_id = bdk_ecam_read32(device, cap_loc + 4);
+ int vsec_id_id = vsec_id & 0xffff;
+ int vsec_id_rev = (vsec_id >> 16) & 0xf;
+ int vsec_id_len = vsec_id >> 20;
+ BDK_TRACE(DEVICE_SCAN, "%s: Vendor ID: 0x%04x Rev: 0x%x Size 0x%03x\n",
+ device->name, vsec_id_id, vsec_id_rev, vsec_id_len);
+ switch (vsec_id_id)
+ {
+ case 0x0001: /* RAS Data Path */
+ BDK_TRACE(DEVICE_SCAN, "%s: Vendor RAS Data Path\n", device->name);
+ break;
+
+ case 0x0002: /* RAS DES */
+ BDK_TRACE(DEVICE_SCAN, "%s: Vendor RAS DES\n", device->name);
+ break;
+
+ case 0x00a0: /* Cavium common */
+ case 0x00a1: /* Cavium CN88XX */
+ case 0x00a2: /* Cavium CN81XX */
+ case 0x00a3: /* Cavium CN83XX */
+ if ((vsec_id_rev == 1) || (vsec_id_rev == 2))
+ {
+ int vsec_ctl = bdk_ecam_read32(device, cap_loc + 8);
+ int vsec_ctl_inst_num = vsec_ctl & 0xff;
+ int vsec_ctl_subnum = (vsec_ctl >> 8) & 0xff;
+ BDK_TRACE(DEVICE_SCAN, "%s: Cavium Instance: 0x%02x Static Bus: 0x%02x\n",
+ device->name, vsec_ctl_inst_num, vsec_ctl_subnum);
+ int vsec_sctl = bdk_ecam_read32(device, cap_loc + 12);
+ int vsec_sctl_rid = (vsec_sctl >> 16) & 0xff;
+ if (vsec_id_rev == 2)
+ {
+ int vsec_sctl_pi = (vsec_sctl >> 24) & 0xff; /* Only in Rev 2 */
+ BDK_TRACE(DEVICE_SCAN, "%s: Revision ID: 0x%02x Programming Interface: 0x%02x\n",
+ device->name, vsec_sctl_rid, vsec_sctl_pi);
+ }
+ else
+ {
+ BDK_TRACE(DEVICE_SCAN, "%s: Revision ID: 0x%02x\n",
+ device->name, vsec_sctl_rid);
+ }
+ /* Record the device instance */
+ device->instance = vsec_ctl_inst_num;
+ }
+ else
+ {
+ bdk_warn("%s: ECAM device Unknown Cavium extension revision\n", device->name);
+ }
+ break;
+
+ default: /* Unknown Vendor extension */
+ bdk_warn("%s: ECAM device unknown vendor extension ID 0x%x\n", device->name, vsec_id_id);
+ break;
+ }
+ }
+ else if (cap_id == 0x10)
+ {
+ /* Single Root I/O Virtualization (SR-IOV) */
+ BDK_TRACE(DEVICE_SCAN, "%s: SR-IOV\n", device->name);
+ /* Loop through all the SR-IOV BARs */
+ bar = cap_loc + 0x24;
+ while (bar <= (cap_loc + 0x3c))
+ {
+ int bar_index = (bar - 0x24 - cap_loc) / 8;
+ /* Read the BAR address and config bits [3:0] */
+ uint64_t address = bdk_ecam_read32(device, bar);
+ int ismem = !(address & 1); /* Bit 0: 0 = mem, 1 = io */
+ int is64 = ismem && (address & 4); /* Bit 2: 0 = 32 bit, 1 = 64 bit if mem */
+ /* Bit 3: 1 = Is prefetchable. We don't care for now */
+
+ /* All internal BARs should be 64 bit. Skip if BAR isn't as that means
+ it is using Enhanced Allocation (EA) */
+ if (!is64)
+ {
+ BDK_TRACE(DEVICE_SCAN, "%s: SR-IOV BAR%d Disabled or EA bar skipped (0x%08llx)\n", device->name, bar_index, address);
+ bar += 8;
+ continue;
+ }
+
+ /* Get the upper part of 64bit BARs */
+ address |= (uint64_t)bdk_ecam_read32(device, bar + 4) << 32;
+
+ /* Write the bits to determine the size */
+ bdk_ecam_write32(device, bar, -1);
+ bdk_ecam_write32(device, bar + 4, -1);
+ uint64_t size_mask = (uint64_t)bdk_ecam_read32(device, bar + 4) << 32;
+ size_mask |= bdk_ecam_read32(device, bar);
+ /* Make sure the node bits are correct in the address */
+ address = (address & ~(3UL << 44)) | ((uint64_t)device->node << 44);
+ /* Restore address value */
+ bdk_ecam_write32(device, bar, address);
+ bdk_ecam_write32(device, bar + 4, address >> 32);
+
+ /* Convert the size into a power of 2 bits */
+ int size_bits = bdk_dpop(size_mask | 0xf);
+ if (size_bits <= 4)
+ size_bits = 0;
+
+ BDK_TRACE(DEVICE_SCAN, "%s: SR-IOV BAR%d 0x%llx/%d flags=0x%llx\n",
+ device->name, bar_index, address & ~0xfull,
+ size_bits, address & 0xf);
+ /* Move to the next BAR */
+ bar += 8;
+ }
+ }
+ else if (cap_id == 0x01)
+ {
+ /* Advanced Error Reporting Capability */
+ BDK_TRACE(DEVICE_SCAN, "%s: Advanced Error Reporting\n", device->name);
+ }
+ else if (cap_id == 0x19)
+ {
+ /* Secondary PCI Express Extended Capability */
+ BDK_TRACE(DEVICE_SCAN, "%s: Secondary PCI Express Extended\n", device->name);
+ }
+ else if (cap_id == 0x15)
+ {
+ /* PCI Express Resizable BAR (RBAR) Capability */
+ BDK_TRACE(DEVICE_SCAN, "%s: PCI Express Resizable BAR (RBAR)\n", device->name);
+ }
+ else if (cap_id == 0x0d)
+ {
+ /* Extended access control := ACS Extended Capability */
+ BDK_TRACE(DEVICE_SCAN, "%s: ACS\n", device->name);
+ }
+ else
+ {
+ /* Unknown PCIe capability */
+ bdk_warn("%s: ECAM device unknown PCIe capability 0x%x\n", device->name, cap_id);
+ }
+ cap_loc = cap_next;
+ }
+ }
+ else
+ {
+ bdk_error("%s: ECAM device didn't have a PCIe capability\n", device->name);
+ }
+ if (BDK_NO_DEVICE_INSTANCE == device->instance) {
+ device->instance = guess_instance;
+ }
+ BDK_TRACE(DEVICE_SCAN, "%s: Device populated\n", device->name);
+}
+
+/**
+ * Called by the ECAM code whan a new device is detected in the system
+ *
+ * @param node Node the ECAM is on
+ * @param ecam ECAM the device is on
+ * @param bus Bus number for the device
+ * @param dev Device number
+ * @param func Function number
+ *
+ * @return Zero on success, negative on failure
+ */
+int bdk_device_add(bdk_node_t node, int ecam, int bus, int dev, int func)
+{
+ if (device_list_count == device_list_max)
+ {
+ int grow = device_list_max + DEVICE_GROW;
+ bdk_device_t *tmp = malloc(grow * sizeof(bdk_device_t));
+ if (!tmp)
+ memcpy(tmp, device_list, device_list_max * sizeof(bdk_device_t));
+ free(device_list);
+ if (tmp == NULL)
+ {
+ bdk_error("bdk-device: Failed to allocate space for device\n");
+ return -1;
+ }
+ device_list = tmp;
+ device_list_max = grow;
+ }
+
+ bdk_device_t *device = &device_list[device_list_count++];
+ memset(device, 0, sizeof(*device));
+
+ device->state = BDK_DEVICE_STATE_NOT_PROBED;
+ device->node = node;
+ device->ecam = ecam;
+ device->bus = bus;
+ device->dev = dev;
+ device->func = func;
+ device->instance = BDK_NO_DEVICE_INSTANCE;
+ populate_device(device);
+
+ const bdk_driver_t *drv = lookup_driver(device);
+ if (drv)
+ BDK_TRACE(DEVICE, "%s: Added device\n", device->name);
+ else
+ BDK_TRACE(DEVICE, "%s: Added device without driver (0x%08x)\n", device->name, device->id);
+ return 0;
+}
+
+/**
+ * Rename a device. Called by driver to give devices friendly names
+ *
+ * @param device Device to rename
+ * @param format Printf style format string
+ */
+void bdk_device_rename(bdk_device_t *device, const char *format, ...)
+{
+ char tmp[sizeof(device->name)];
+ va_list args;
+ va_start(args, format);
+ vsnprintf(tmp, sizeof(tmp), format, args);
+ va_end(args);
+ tmp[sizeof(tmp) - 1] = 0;
+ BDK_TRACE(DEVICE, "%s: Renamed to %s\n", device->name, tmp);
+ strcpy(device->name, tmp);
+}
+
+/**
+ * Called by the ECAM code once all devices have been added
+ *
+ * @return Zero on success, negative on failure
+ */
+int bdk_device_init(void)
+{
+ /* Probe all devices first */
+ for (int i = 0; i < device_list_count; i++)
+ {
+ bdk_device_t *dev = &device_list[i];
+ const bdk_driver_t *drv = lookup_driver(dev);
+ if (drv == NULL)
+ continue;
+ if (dev->state == BDK_DEVICE_STATE_NOT_PROBED)
+ {
+ BDK_TRACE(DEVICE, "%s: Probing\n", dev->name);
+ if (drv->probe(dev))
+ {
+ BDK_TRACE(DEVICE, "%s: Probe failed\n", dev->name);
+ dev->state = BDK_DEVICE_STATE_PROBE_FAIL;
+ }
+ else
+ {
+ BDK_TRACE(DEVICE, "%s: Probe complete\n", dev->name);
+ dev->state = BDK_DEVICE_STATE_PROBED;
+ }
+ }
+ }
+
+ /* Do init() after all the probes. See comments in top of bdk-device.h */
+ for (int i = 0; i < device_list_count; i++)
+ {
+ bdk_device_t *dev = &device_list[i];
+ const bdk_driver_t *drv = lookup_driver(dev);
+ if (drv == NULL)
+ continue;
+ if (dev->state == BDK_DEVICE_STATE_PROBED)
+ {
+ BDK_TRACE(DEVICE, "%s: Initializing\n", dev->name);
+ if (drv->init(dev))
+ {
+ BDK_TRACE(DEVICE, "%s: Init failed\n", dev->name);
+ dev->state = BDK_DEVICE_STATE_INIT_FAIL;
+ }
+ else
+ {
+ BDK_TRACE(DEVICE, "%s: Init complete\n", dev->name);
+ dev->state = BDK_DEVICE_STATE_READY;
+ }
+ }
+ }
+ return 0;
+}
+
+/**
+ * Lookup a device by ECAM ID and internal instance number. This can be used by
+ * one device to find a handle to an associated device. For example, PKI would
+ * use this function to get a handle to the FPA.
+ *
+ * @param node Node to lookup for
+ * @param id ECAM ID
+ * @param instance Cavium internal instance number
+ *
+ * @return Device pointer, or NULL if the device isn't found
+ */
+const bdk_device_t *bdk_device_lookup(bdk_node_t node, uint32_t id, int instance)
+{
+ for (int i = 0; i < device_list_count; i++)
+ {
+ bdk_device_t *dev = &device_list[i];
+ if ((dev->node == node) && (dev->id == id) && (dev->instance == instance))
+ return dev;
+ }
+ BDK_TRACE(DEVICE, "No device found for node %d, ID %08x, instance %d\n", node, id, instance);
+ return NULL;
+}
+
+/**
+ * Read from a device BAR
+ *
+ * @param device Device to read from
+ * @param bar Which BAR to read from (0-3)
+ * @param size Size of the read
+ * @param offset Offset into the BAR
+ *
+ * @return Value read
+ */
+uint64_t bdk_bar_read(const bdk_device_t *device, int bar, int size, uint64_t offset)
+{
+ uint64_t address = offset & bdk_build_mask(device->bar[bar/2].size2);
+ address += device->bar[bar/2].address;
+ if (offset+size > (1ULL << device->bar[bar/2].size2)) {
+ /* The CSR address passed in offset doesn't contain the node number. Copy it
+ from the BAR address */
+ offset |= address & (0x3ull << 44);
+ if (address != offset)
+ bdk_fatal("BAR read address 0x%llx doesn't match CSR address 0x%llx\n", address, offset);
+ }
+ switch (size)
+ {
+ case 1:
+ return bdk_read64_uint8(address);
+ case 2:
+ return bdk_le16_to_cpu(bdk_read64_uint16(address));
+ case 4:
+ return bdk_le32_to_cpu(bdk_read64_uint32(address));
+ case 8:
+ return bdk_le64_to_cpu(bdk_read64_uint64(address));
+ }
+ bdk_fatal("%s: Unexpected read size %d\n", device->name, size);
+}
+
+/**
+ * Write to a device BAR
+ *
+ * @param device Device to write to
+ * @param bar Which BAR to read from (0-3)
+ * @param size Size of the write
+ * @param offset Offset into the BAR
+ * @param value Value to write
+ */
+void bdk_bar_write(const bdk_device_t *device, int bar, int size, uint64_t offset, uint64_t value)
+{
+ uint64_t address = offset & bdk_build_mask(device->bar[bar/2].size2);
+ address += device->bar[bar/2].address;
+ if (offset+size > (1ULL << device->bar[bar/2].size2)) {
+ /* The CSR address passed in offset doesn't contain the node number. Copy it
+ from the BAR address */
+ offset |= address & (0x3ull << 44);
+ if (address != offset)
+ bdk_fatal("BAR write address 0x%llx doesn't match CSR address 0x%llx\n", address, offset);
+ }
+ switch (size)
+ {
+ case 1:
+ bdk_write64_uint8(address, value);
+ return;
+ case 2:
+ bdk_write64_uint16(address, bdk_cpu_to_le16(value));
+ return;
+ case 4:
+ bdk_write64_uint32(address, bdk_cpu_to_le32(value));
+ return;
+ case 8:
+ bdk_write64_uint64(address, bdk_cpu_to_le64(value));
+ return;
+ }
+ bdk_fatal("%s: Unexpected write size %d\n", device->name, size);
+}
diff --git a/src/vendorcode/cavium/bdk/libbdk-hal/if/bdk-if-phy-marvell.c b/src/vendorcode/cavium/bdk/libbdk-hal/if/bdk-if-phy-marvell.c
new file mode 100644
index 0000000000..e8f3a009dd
--- /dev/null
+++ b/src/vendorcode/cavium/bdk/libbdk-hal/if/bdk-if-phy-marvell.c
@@ -0,0 +1,115 @@
+/***********************license start***********************************
+* Copyright (c) 2003-2016 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-hal/bdk-mdio.h>
+#include <libbdk-hal/bdk-qlm.h>
+#include <libbdk-hal/if/bdk-if.h>
+
+/**
+ * Setup marvell PHYs
+ * This function sets up one port in a marvell 88E1512 in SGMII mode
+ */
+static void setup_marvell_phy(bdk_node_t node, int mdio_bus, int mdio_addr)
+{
+ int phy_status = 0;
+
+ BDK_TRACE(PHY, "%s In SGMII mode for Marvell PHY 88E1512\n", __FUNCTION__);
+ /* Switch to Page 18 */
+ phy_status = bdk_mdio_write(node, mdio_bus, mdio_addr, 22, 18);
+ if (phy_status < 0)
+ return;
+
+ phy_status = bdk_mdio_read(node, mdio_bus, mdio_addr, 22);
+ if (phy_status < 0)
+ return;
+
+ /* Change the Phy System mode from RGMII(default hw reset mode) to SGMII */
+ phy_status = bdk_mdio_write(node, mdio_bus, mdio_addr, 20, 1);
+ if (phy_status < 0)
+ return;
+
+ /* Requires a Software reset */
+ phy_status = bdk_mdio_write(node, mdio_bus, mdio_addr, 20, 0x8001);
+ if (phy_status < 0)
+ return;
+
+ phy_status = bdk_mdio_read(node, mdio_bus, mdio_addr, 20);
+ if (phy_status < 0)
+ return;
+
+ /* Change the Page back to 0 */
+ phy_status = bdk_mdio_write(node, mdio_bus, mdio_addr, 22, 0);
+ if (phy_status < 0)
+ return;
+
+ phy_status = bdk_mdio_read(node, mdio_bus, mdio_addr, 22);
+ if (phy_status < 0)
+ return;
+
+ phy_status = bdk_mdio_read(node, mdio_bus, mdio_addr, 17);
+ if (phy_status < 0)
+ return;
+}
+
+int bdk_if_phy_marvell_setup(bdk_node_t node, int qlm, int mdio_bus, int phy_addr)
+{
+ BDK_TRACE(PHY,"In %s\n",__FUNCTION__);
+
+ /* Check if the PHY is marvell PHY we expect */
+ int phy_status = bdk_mdio_read(node, mdio_bus, phy_addr, BDK_MDIO_PHY_REG_ID1);
+ if (phy_status != 0x0141)
+ return 0;
+
+ /* Check that the GSER mode is SGMII */
+ /* Switch the marvell PHY to the correct mode */
+ bdk_qlm_modes_t qlm_mode = bdk_qlm_get_mode(node, qlm);
+
+ BDK_TRACE(PHY,"%s: QLM:%d QLM_MODE:%d\n",__FUNCTION__, qlm, qlm_mode);
+
+ if ((qlm_mode != BDK_QLM_MODE_SGMII_1X1) &&
+ (qlm_mode != BDK_QLM_MODE_SGMII_2X1))
+ return 0;
+
+ BDK_TRACE(PHY,"%s: Detected Marvell Phy in SGMII mode\n", __FUNCTION__);
+ for (int port = 0; port < 2; port++)
+ {
+ setup_marvell_phy(node, mdio_bus, phy_addr + port);
+ }
+ return 0;
+}
diff --git a/src/vendorcode/cavium/bdk/libbdk-hal/if/bdk-if-phy-vetesse-8514.c b/src/vendorcode/cavium/bdk/libbdk-hal/if/bdk-if-phy-vetesse-8514.c
new file mode 100644
index 0000000000..4d6ef8d25d
--- /dev/null
+++ b/src/vendorcode/cavium/bdk/libbdk-hal/if/bdk-if-phy-vetesse-8514.c
@@ -0,0 +1,224 @@
+/***********************license start***********************************
+* Copyright (c) 2003-2016 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-hal/if/bdk-if.h>
+#include <libbdk-hal/bdk-mdio.h>
+#include <libbdk-hal/bdk-qlm.h>
+
+#define VSC_PHY_STD_PAGE (0x0)
+#define VSC_PHY_EXT1_PAGE (0x1)
+#define VSC_PHY_EXT2_PAGE (0x2)
+#define VSC_PHY_EXT3_PAGE (0x3)
+#define VSC_PHY_EXT4_PAGE (0x4)
+#define VSC_PHY_GPIO_PAGE (0x10)
+#define VSC_PHY_TEST_PAGE (0x2A30)
+#define VSC_PHY_TR_PAGE (0x52B5)
+
+const uint16_t init_script_rev_a[] = {
+// Op, Page, Reg, Value, Mask
+// 0, 1, 2, 3, 4
+// --, ------, ----, ------, -----
+ 0, 0x0000, 0x1f, 0x0000, 0xffff,
+ 1, 0x0000, 0x16, 0x0001, 0x0001,
+ 0, 0x0001, 0x1f, 0x2A30, 0xffff,
+ 1, 0x2A30, 0x08, 0x8000, 0x8000,
+ 0, 0x2A30, 0x1f, 0x52B5, 0xffff,
+ 0, 0x52B5, 0x12, 0x0068, 0xffff,
+ 0, 0x52B5, 0x11, 0x8980, 0xffff,
+ 0, 0x52B5, 0x10, 0x8f90, 0xffff,
+ 0, 0x52B5, 0x12, 0x0000, 0xffff,
+ 0, 0x52B5, 0x11, 0x0003, 0xffff,
+ 0, 0x52B5, 0x10, 0x8796, 0xffff,
+ 0, 0x52B5, 0x12, 0x0050, 0xffff,
+ 0, 0x52B5, 0x11, 0x100f, 0xffff,
+ 0, 0x52B5, 0x10, 0x87fa, 0xffff,
+ 0, 0x52B5, 0x1f, 0x2A30, 0xffff,
+ 1, 0x2A30, 0x08, 0x0000, 0x8000,
+ 0, 0x2A30, 0x1f, 0x0000, 0xffff,
+ 1, 0x0000, 0x16, 0x0000, 0x0001,
+ 0xf, 0xffff, 0xff, 0xffff, 0xffff
+};
+
+static void wr_masked(bdk_node_t node, int mdio_bus, int phy_addr, int reg, int value, int mask)
+{
+ int nmask = ~mask;
+ int old = bdk_mdio_read(node, mdio_bus, phy_addr, reg);
+ int vmask = value & mask;
+ int newv = old & nmask;
+ newv = newv | vmask;
+ bdk_mdio_write(node, mdio_bus, phy_addr, reg, newv);
+}
+static void vitesse_init_script(bdk_node_t node, int mdio_bus, int phy_addr)
+{
+ const uint16_t *ptr;
+ uint16_t reg_addr;
+ uint16_t reg_val;
+ uint16_t mask;
+
+ BDK_TRACE(PHY,"In %s\n",__FUNCTION__);
+ BDK_TRACE(PHY,"Loading init script for VSC8514\n");
+
+ ptr = init_script_rev_a;
+ while (*ptr != 0xf)
+ {
+ reg_addr = *(ptr+2);
+ reg_val = *(ptr+3);
+ mask = *(ptr+4);
+ ptr+=5;
+ if (mask != 0xffff)
+ {
+ wr_masked(node, mdio_bus, phy_addr, reg_addr,reg_val,mask);
+ }
+ else
+ {
+ bdk_mdio_write(node,mdio_bus,phy_addr,reg_addr,reg_val);
+ }
+ }
+
+ BDK_TRACE(PHY,"loading init script is done\n");
+
+}
+
+static void vitesse_program(bdk_node_t node, int mdio_bus, int phy_addr)
+{
+ return;
+}
+
+/**
+ * Setup Vitesse PHYs
+ * This function sets up one port in a Vitesse VSC8514
+ */
+static void setup_vitesse_phy(bdk_node_t node, int mdio_bus, int phy_addr)
+{
+ /*setting MAC if*/
+ bdk_mdio_write(node, mdio_bus, phy_addr, 31, VSC_PHY_GPIO_PAGE);
+ wr_masked(node,mdio_bus,phy_addr, 19, 0x4000, 0xc000);
+ bdk_mdio_write(node, mdio_bus, phy_addr, 18, 0x80e0);
+
+ /*Setting media if*/
+ bdk_mdio_write(node, mdio_bus, phy_addr, 31, VSC_PHY_STD_PAGE);
+ // Reg23, 10:8 Select copper, CAT5 copper only
+ wr_masked(node,mdio_bus,phy_addr, 23, 0x0000, 0x0700);
+
+ // Reg0:15, soft Reset
+ wr_masked(node,mdio_bus,phy_addr, 0, 0x8000, 0x8000);
+ int time_out = 100;
+ while (time_out && bdk_mdio_read(node,mdio_bus,phy_addr, 0) & 0x8000)
+ {
+ bdk_wait_usec(100000);
+ time_out--;
+ }
+
+ if (time_out == 0)
+ {
+ BDK_TRACE(PHY,"setting PHY TIME OUT\n");
+ return;
+ }
+ else
+ {
+ BDK_TRACE(PHY,"Setting a phy port is done\n");
+ }
+
+ bdk_mdio_write(node, mdio_bus, phy_addr, 31, VSC_PHY_EXT3_PAGE);
+ bdk_mdio_write(node, mdio_bus, phy_addr, 16, 0x80);
+ // Select main registers
+ bdk_mdio_write(node, mdio_bus, phy_addr, 31, VSC_PHY_STD_PAGE);
+
+ /*
+
+ if (LOOP_INTERNAL)
+ {
+ reg0 = bdk_mdio_read(node, mdio_bus, phy_addr, 0);
+ reg0 = bdk_insert(reg0, 1, 14, 1);
+ bdk_mdio_write(node, mdio_bus, phy_addr, 0, reg0);
+ }
+
+ // Far end loopback (External side)
+ if (LOOP_EXTERNAL)
+ {
+ reg23 = bdk_mdio_read(node, mdio_bus, phy_addr, 23);
+ reg23 = bdk_insert(reg23, 1, 3, 1);
+ bdk_mdio_write(node, mdio_bus, phy_addr, 23, reg23);
+ }
+
+
+ // Dump registers
+ if (false)
+ {
+ printf("\nVitesse PHY register dump, PHY address %d, mode %s\n",
+ phy_addr, (qsgmii) ? "QSGMII" : "SGMII");
+ int phy_addr = 4;
+ for (int reg_set = 0; reg_set <= 0x10; reg_set += 0x10)
+ {
+ printf("\nDump registers with reg[31]=0x%x\n", reg_set);
+ bdk_mdio_write(node, mdio_bus, phy_addr, 31, reg_set);
+ for (int reg=0; reg < 32; reg++)
+ printf("reg[%02d]=0x%x\n", reg, bdk_mdio_read(node, mdio_bus, phy_addr, reg));
+ }
+ }
+ */
+}
+
+//static void vetesse_setup(bdk_node_t node, int qlm, int mdio_bus, int phy_addr)
+int bdk_if_phy_vsc8514_setup(bdk_node_t node, int qlm, int mdio_bus, int phy_addr)
+{
+ /* Check if the PHY is Vetesse PHY we expect */
+ int phy_status_1 = bdk_mdio_read(node, mdio_bus, phy_addr, BDK_MDIO_PHY_REG_ID1);
+ int phy_status_2 = bdk_mdio_read(node, mdio_bus, phy_addr, BDK_MDIO_PHY_REG_ID2);
+ if (phy_status_1 != 0x0007 || phy_status_2 != 0x0670)
+ {
+ bdk_error("The PHY on this board is NOT VSC8514.\n");
+ return -1;
+ }
+
+ /* Check that the GSER mode is SGMII or QSGMII */
+ bdk_qlm_modes_t qlm_mode = bdk_qlm_get_mode(node, qlm);
+ if (qlm_mode != BDK_QLM_MODE_QSGMII_4X1)
+ return -1;
+
+ vitesse_init_script(node, mdio_bus, phy_addr);
+ vitesse_program(node, mdio_bus, phy_addr);
+
+ /* VSC8514 just support QSGMII */
+ for (int port = 0; port < 4; port++)
+ setup_vitesse_phy(node, mdio_bus, phy_addr + port);
+
+ return 1;
+
+}
diff --git a/src/vendorcode/cavium/bdk/libbdk-hal/if/bdk-if-phy-vetesse-xfi.c b/src/vendorcode/cavium/bdk/libbdk-hal/if/bdk-if-phy-vetesse-xfi.c
new file mode 100644
index 0000000000..b6f052ad47
--- /dev/null
+++ b/src/vendorcode/cavium/bdk/libbdk-hal/if/bdk-if-phy-vetesse-xfi.c
@@ -0,0 +1,395 @@
+/***********************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-hal/if/bdk-if.h>
+#include <libbdk-hal/bdk-mdio.h>
+#include <libbdk-hal/bdk-twsi.h>
+
+/* This code is an optional part of the BDK. It is only linked in
+ * if BDK_REQUIRE() needs it */
+//BDK_REQUIRE(TWSI);
+BDK_REQUIRE_DEFINE(XFI);
+
+/*
+Rate Select Settings
+Mode State : 6/8
+Rate Select State : 0
+RSEL1 : 0
+RSEL0 : 0
+Ref Clock Gen(MHz) : 156.25
+Data Rate(Gbps) : 10.3125
+Description : 10 GbE
+
+
+Data Rate Detection Configuration Registers
+
+Mode Pin Settings:
+Mode State : 0
+MODE1 : 0
+MODE0 : 0
+Mode : Two-wire serial interface mode
+
+LOS Pin Strap Mode Settings
+Mode State : 2/6/8
+State : 4
+LOS1 : Float
+LOS0 : Float
+LOS Amplitude(mVpp) : 20
+LOS Hysteresis(dB) : 2
+
+Input Equalization Retimer Mode Settings
+Mode State : 6/8
+EQ State : 0
+EQ1 : 0
+EQ0 : 0
+EQ(dB) : Auto
+DFE : Auto
+Comment : Full Auto
+
+Input Equalization Re-Driver Mode Settings
+Mode State :
+EQ State : 0
+EQ1 : 0
+EQ0 : 0
+EQ(dB) : Auto
+DFE : APowered Down
+Comment : Analog EQ Only
+
+
+
+Output De-Emphasis Retimer Mode Settings
+Mode State : 6/8
+DE State : 3
+TX1 : Float
+TX0 : 0
+PRE c(-1) mA : -1
+MAIN c( 0) mA : 15
+POST c(+1) mA : 4
+DC Amplitude(mV): 500
+De-Emphasis(dB) : -6.02
+Comment :
+
+
+Output De-Emphasis Re-Driver Mode Settings
+Mode State : 2
+DE State : 3
+TX1 : Float
+TX0 : 0
+Frequency(Gbps) : 10.3125
+DC Amplitude(mV): 600
+De-Emphasis(dB) : 4
+Comment : 10GbE
+
+
+*/
+
+static int debug = 0;
+
+#define xfi_printf(fmt, args...) \
+ do { \
+ if(debug == 1){ \
+ printf(fmt, ##args); \
+ } \
+ } while(0)
+
+
+int bdk_xfi_vsc7224_dump(int twsi_id, int unit){
+ bdk_node_t node=0;
+ uint8_t dev_addr=0x10 + unit;
+ uint16_t internal_addr=0x7F;
+ int num_bytes=2;
+ int ia_width_bytes=1;
+ uint64_t data=0;
+ int p, i;
+ uint64_t result[0x100] = {0};
+
+ uint64_t pagenum[9] = {0x00, 0x01, 0x02, 0x03, 0x20, 0x21, 0x30, 0x31, 0x40};
+
+ for(p=0; p < (sizeof(pagenum)/sizeof(pagenum[0])); p++){
+ data = pagenum[p];
+ bdk_twsix_write_ia(node, twsi_id, dev_addr, internal_addr, num_bytes, ia_width_bytes, data);
+ for(i=0x80; i<=0xFF; i++){
+ result[i] = 0x00;
+ result[i] = bdk_twsix_read_ia(node, twsi_id, dev_addr, (uint16_t)i, num_bytes, ia_width_bytes);
+ }
+ for(i=0x80; i<=0xFF; i++){
+ if(i==0x80){
+ printf("\npage_%02X[0x100] = {\n", (uint8_t)pagenum[p]);
+ }
+ if(i % 8 == 0){
+ printf("/* 0x%2X */", i);
+ }
+ printf(" 0x%04X,", (uint16_t)result[i]);
+ if(i==0xFF){
+ printf("};");
+ }
+ if((i+1) % 8 == 0){
+ printf("\n");
+ }
+ }
+ }
+
+ return 0;
+}
+
+/* XFI ReTimer/ReDriver Mode Settings */
+
+/*
+power down regs:
+Page Reg Position Mask val RegFieldName
+0x00 0x89 b07 0x0080 1 PD_INBUF
+0x00 0x8A b10 0x0400 1 PD_DFECRU
+0x00 0x8A b01 0x0002 1 PD_DFE
+0x00 0x8A b00 0x0001 1 PD_DFEADAPT
+0x00 0x97 b15 0x8000 1 ASYN_SYNN
+0x00 0x97 b09 0x0200 1 PD_OD
+0x00 0xA0 b11 0x0800 1 PD_LOS
+0x00 0xA4 b15 0x8000 1 PD_CH
+0x00 0xB5 b07 0x0080 1 PD_INBUF
+0x00 0xB9 b15 0x8000 1 ASYN_SYNN
+0x00 0xB9 b09 0x0200 1 PD_OD
+0x00 0xBF b07 0x0080 1 PD_INBUF
+0x00 0xF0 b15 0x8000 1 ASYN_SYNN
+0x00 0xF0 b09 0x0200 1 PD_OD
+0x00 0xF6 b07 0x0080 1 PD_INBUF
+0x00 0xFA b15 0x8000 1 ASYN_SYNN
+0x00 0xFA b09 0x0200 1 PD_OD
+*/
+struct regmap{
+ short int page;
+ unsigned char reg;
+ unsigned short int retimer;
+ unsigned short int redriver;
+};
+
+/* This table only applies to SFF8104 */
+struct regmap xfiregmap[64] = {
+//CH 0
+{0x00, 0x84, 0x0800, 0x0000}, //EQTABLE_DCOFF0 (0n_84)
+{0x00, 0x8A, 0x7000, 0x0400}, //DFECRU_CTRL (0n_8A)
+{0x00, 0x8B, 0x4060, 0x0000}, //DFECRU_CFVF_CFAP (0n_8B)
+{0x00, 0x90, 0xDE85, 0x0000}, //DFECRU_DFEAUTO (0n_90)
+{0x00, 0x91, 0x2020, 0x0000}, //DFECRU_BTMX_BFMX (0n_91)
+{0x00, 0x92, 0x0860, 0x0000}, //DFECRU_DXMX_TRMX (0n_92)
+{0x00, 0x93, 0x6000, 0x0000}, //DFECRU_TRMN_ERRI (0n_93)
+{0x00, 0x94, 0x0001, 0x0000}, //DFECRU_DFEMODE (0n_94)
+{0x00, 0x95, 0x0008, 0x0000}, //DFECRU_RATESEL (0n_95)
+{0x00, 0x97, 0x0000, 0x8080}, //OUTDRVCTRL (0n_97)
+{0x00, 0x99, 0x001E, 0x0014}, //KR_MAINTAP (0n_99)
+{0x00, 0x9A, 0x000B, 0x0000}, //KR_PRETAP (0n_9A)
+{0x00, 0x9B, 0x0010, 0x0000}, //KR_POSTTAP (0n_9B)
+{0x00, 0x9E, 0x03E8, 0x07D0}, //LOSASSRT (0n_9E)
+{0x00, 0x9F, 0x04EA, 0x09D5}, //LOSDASSRT (0n_9F)
+{0x00, 0xB2, 0x0888, 0x0000}, //NA
+
+//CH 1
+{0x01, 0x84, 0x0800, 0x0000},
+{0x01, 0x8A, 0x7000, 0x0400},
+{0x01, 0x8B, 0x4060, 0x0000},
+{0x01, 0x90, 0xDE85, 0x0000},
+{0x01, 0x91, 0x2020, 0x0000},
+{0x01, 0x92, 0x0860, 0x0000},
+{0x01, 0x93, 0x6000, 0x0000},
+{0x01, 0x94, 0x0001, 0x0000},
+{0x01, 0x95, 0x0008, 0x0000},
+{0x01, 0x97, 0x0000, 0x8080},
+{0x01, 0x99, 0x001E, 0x0014},
+{0x01, 0x9A, 0x000B, 0x0000},
+{0x01, 0x9B, 0x0010, 0x0000},
+{0x01, 0x9E, 0x03E8, 0x07D0},
+{0x01, 0x9F, 0x04EA, 0x09D5},
+{0x01, 0xB2, 0x0888, 0x0000},
+
+//POWER_DOWN Channel 2 and 3
+{0x02, 0x8A, 0x0400, 0x0400},
+{0x02, 0xA4, 0x8000, 0x8000},
+{0x03, 0x8A, 0x0400, 0x0400},
+{0x03, 0xA4, 0x8000, 0x8000},
+
+{0x30, 0x80, 0x3453, 0x0000}, //FSYNM_NVAL (3f_80)
+{0x30, 0x81, 0x00F6, 0x0000}, //FSYNFVAL_MSB (3f_81)
+{0x30, 0x82, 0x8800, 0x0000}, //FSYNFVAL_LSB (3f_82)
+{0x30, 0x83, 0x000F, 0x0000}, //FSYNRVAL_MSB (3f_83)
+{0x30, 0x84, 0xB5E0, 0x0000}, //FSYNRVAL_LSB (3f_84)
+{0x30, 0x85, 0x0000, 0x0400}, //FSYNTST (3f_85)
+
+{0x40, 0x80, 0x4C00, 0x0000}, //ANMUXSEL (40_80)
+{0x40, 0x81, 0x4000, 0x0000}, //DGMUXCTRL (40_81)
+{0x40, 0x82, 0x7800, 0xC000}, //RCKINCTRL (40_82)
+{0x40, 0x84, 0x0020, 0x0000}, //CHRCKSEL (40_84)
+
+{-1, 0, 0, 0},
+};
+
+int bdk_vsc7224_modeset(int twsi_id, int unit, int xfi_mode){
+ bdk_node_t node=0;
+ uint8_t dev_addr=0x10 + unit;
+ uint16_t internal_addr=0x7F;
+ uint16_t page=0;
+ int num_bytes=2;
+ int ia_width_bytes=1;
+ uint64_t data=0;
+ int val=0;
+ int ret = 0, r=0;
+ uint16_t reg = 0;
+
+ if(xfi_mode==0){
+ printf("XFI Mode Retimer\n");
+ }else{
+ printf("XFI Mode Redriver\n");
+ }
+
+ while(xfiregmap[r].page != -1){
+ page = xfiregmap[r].page;
+ reg = xfiregmap[r].reg;
+ if(xfi_mode==0){
+ data = xfiregmap[r].retimer;
+ }else{
+ data = xfiregmap[r].redriver;
+ }
+ ret = bdk_twsix_write_ia(node, twsi_id, dev_addr, internal_addr, num_bytes, ia_width_bytes, (uint64_t)page);
+ if(ret !=0){
+ printf("XFI init Error\n");
+ break;
+ }
+ ret = bdk_twsix_write_ia(node, twsi_id, dev_addr, reg, num_bytes, ia_width_bytes, data);
+ if(ret !=0){
+ printf("XFI init Error\n");
+ break;
+ }
+ val = bdk_twsix_read_ia(node, twsi_id, dev_addr, reg, num_bytes, ia_width_bytes);
+ if(val == -1){
+ printf("XFI Read Reg Failed @ page:reg :: %2X:%2X \n",page, reg);
+ break;
+ }else{
+ xfi_printf(" Page: reg: data: val :: %2X:%2X:%04X:%04X\n", page, reg, (uint16_t)data, val);
+ }
+ r++;
+ }
+
+ return ret;
+}
+
+
+int bdk_vsc7224_regmap_modeget(int twsi_id, int unit){
+ bdk_node_t node=0;
+ uint8_t dev_addr=0x10 + unit;
+ uint16_t internal_addr=0x7F;
+ uint16_t page=0;
+ int num_bytes=2;
+ int ia_width_bytes=1;
+ //uint64_t data=0;
+ uint16_t reg = 0;
+ int ret = 0, r=0;
+ int data;
+
+ printf("\n===========================================\n");
+ printf("Page :Reg :Value :Retimer :Redriver\n");
+ printf("===========================================\n");
+ while(xfiregmap[r].page != -1){
+ page = xfiregmap[r].page;
+ reg = xfiregmap[r].reg;
+
+ ret = bdk_twsix_write_ia(node, twsi_id, dev_addr, internal_addr, num_bytes, ia_width_bytes, (uint64_t)page);
+ if(ret !=0){
+ printf("XFI init Error\n");
+ break;
+ }
+ data = bdk_twsix_read_ia(node, twsi_id, dev_addr, reg, num_bytes, ia_width_bytes);
+ if(data == -1){
+ printf("XFI Read Reg Failed @ page:reg :: %2X:%2X \n",page, reg);
+ break;
+ }
+ printf(" %02X: %02X: %04X: %04X: %04X\n", page, reg, (uint16_t)data, xfiregmap[r].retimer, xfiregmap[r].redriver);
+ r++;
+ }
+ printf("=======================================\n");
+
+ return ret;
+}
+
+int bdk_vsc7224_wp_regs(int twsi_id, int unit, int xfi_wp){
+ bdk_node_t node=0;
+ uint8_t dev_addr=0x10 + unit;
+ uint16_t internal_addr=0x7E;
+ uint16_t data=0x0000;
+ int num_bytes=2;
+ int ia_width_bytes=1;
+ int ret =0;
+
+ if(xfi_wp == 1){
+ data = 0x0000;
+ }else{
+ data = 0xFFFF;
+ }
+
+ ret = bdk_twsix_write_ia(node, twsi_id, dev_addr, internal_addr, num_bytes, ia_width_bytes, (uint64_t)data);
+ if(ret !=0){
+ printf("XFI VSC7224 Write Protect Error\n");
+ }
+
+ return ret;
+}
+
+int bdk_vsc7224_set_reg(int twsi_id, int unit, int page, int reg, int val){
+ bdk_node_t node=0;
+ uint8_t dev_addr=0x10 + unit;
+ uint16_t internal_addr = reg;
+ int num_bytes=2;
+ int ia_width_bytes=1;
+ int ret=0;
+
+ xfi_printf(" Unit: Page: reg: val :: %02x:%2X:%2X:%04X\n", unit, page, reg, val & 0xFFFF);
+ ret = bdk_twsix_write_ia(node, twsi_id, dev_addr, 0x7F, num_bytes, ia_width_bytes, (uint64_t)(page & 0xFF));
+ if (ret) {
+ printf("XFI VSC7224 TWSI Set Page Register Error\n");
+ }
+
+ ret = bdk_twsix_write_ia(node, twsi_id, dev_addr, internal_addr, num_bytes, ia_width_bytes, (uint64_t)(val & 0xFFFF));
+ if (ret) {
+ printf("XFI VSC7224 TWSI Set Register Error\n");
+ }
+
+ return ret;
+}
+
+int bdk_vsc7224_debug(int _debug){
+ debug =_debug;
+ return 0;
+}
diff --git a/src/vendorcode/cavium/bdk/libbdk-hal/if/bdk-if-phy-vetesse.c b/src/vendorcode/cavium/bdk/libbdk-hal/if/bdk-if-phy-vetesse.c
new file mode 100644
index 0000000000..e1ef6b0f2d
--- /dev/null
+++ b/src/vendorcode/cavium/bdk/libbdk-hal/if/bdk-if-phy-vetesse.c
@@ -0,0 +1,372 @@
+/***********************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-hal/if/bdk-if.h>
+#include <libbdk-hal/bdk-mdio.h>
+#include <libbdk-hal/bdk-qlm.h>
+
+static bool LOOP_INTERNAL = false;
+static bool LOOP_EXTERNAL = false;
+
+static uint8_t patch_arr[] = {
+ 0x44, 0x83, 0x02, 0x42, 0x12, 0x02, 0x44, 0x93, 0x02, 0x44,
+ 0xca, 0x02, 0x44, 0x4d, 0x02, 0x43, 0xef, 0xed, 0xff, 0xe5,
+ 0xfc, 0x54, 0x38, 0x64, 0x20, 0x70, 0x08, 0x65, 0xff, 0x70,
+ 0x04, 0xed, 0x44, 0x80, 0xff, 0x22, 0x8f, 0x19, 0x7b, 0xbb,
+ 0x7d, 0x0e, 0x7f, 0x04, 0x12, 0x3d, 0xd7, 0xef, 0x4e, 0x60,
+ 0x03, 0x02, 0x41, 0xf9, 0xe4, 0xf5, 0x1a, 0x74, 0x01, 0x7e,
+ 0x00, 0xa8, 0x1a, 0x08, 0x80, 0x05, 0xc3, 0x33, 0xce, 0x33,
+ 0xce, 0xd8, 0xf9, 0xff, 0xef, 0x55, 0x19, 0x70, 0x03, 0x02,
+ 0x41, 0xed, 0x85, 0x1a, 0xfb, 0x7b, 0xbb, 0xe4, 0xfd, 0xff,
+ 0x12, 0x3d, 0xd7, 0xef, 0x4e, 0x60, 0x03, 0x02, 0x41, 0xed,
+ 0xe5, 0x1a, 0x54, 0x02, 0x75, 0x1d, 0x00, 0x25, 0xe0, 0x25,
+ 0xe0, 0xf5, 0x1c, 0xe4, 0x78, 0xc5, 0xf6, 0xd2, 0x02, 0x12,
+ 0x41, 0xfa, 0x7b, 0xff, 0x7d, 0x12, 0x7f, 0x07, 0x12, 0x3d,
+ 0xd7, 0xef, 0x4e, 0x60, 0x03, 0x02, 0x41, 0xe7, 0xc2, 0x02,
+ 0x74, 0xc7, 0x25, 0x1a, 0xf9, 0x74, 0xe7, 0x25, 0x1a, 0xf8,
+ 0xe6, 0x27, 0xf5, 0x1b, 0xe5, 0x1d, 0x24, 0x5b, 0x12, 0x44,
+ 0x2a, 0x12, 0x3e, 0xda, 0x7b, 0xfc, 0x7d, 0x11, 0x7f, 0x07,
+ 0x12, 0x3d, 0xd7, 0x78, 0xcc, 0xef, 0xf6, 0x78, 0xc1, 0xe6,
+ 0xfe, 0xef, 0xd3, 0x9e, 0x40, 0x06, 0x78, 0xcc, 0xe6, 0x78,
+ 0xc1, 0xf6, 0x12, 0x41, 0xfa, 0x7b, 0xec, 0x7d, 0x12, 0x7f,
+ 0x07, 0x12, 0x3d, 0xd7, 0x78, 0xcb, 0xef, 0xf6, 0xbf, 0x07,
+ 0x06, 0x78, 0xc3, 0x76, 0x1a, 0x80, 0x1f, 0x78, 0xc5, 0xe6,
+ 0xff, 0x60, 0x0f, 0xc3, 0xe5, 0x1b, 0x9f, 0xff, 0x78, 0xcb,
+ 0xe6, 0x85, 0x1b, 0xf0, 0xa4, 0x2f, 0x80, 0x07, 0x78, 0xcb,
+ 0xe6, 0x85, 0x1b, 0xf0, 0xa4, 0x78, 0xc3, 0xf6, 0xe4, 0x78,
+ 0xc2, 0xf6, 0x78, 0xc2, 0xe6, 0xff, 0xc3, 0x08, 0x96, 0x40,
+ 0x03, 0x02, 0x41, 0xd1, 0xef, 0x54, 0x03, 0x60, 0x33, 0x14,
+ 0x60, 0x46, 0x24, 0xfe, 0x60, 0x42, 0x04, 0x70, 0x4b, 0xef,
+ 0x24, 0x02, 0xff, 0xe4, 0x33, 0xfe, 0xef, 0x78, 0x02, 0xce,
+ 0xa2, 0xe7, 0x13, 0xce, 0x13, 0xd8, 0xf8, 0xff, 0xe5, 0x1d,
+ 0x24, 0x5c, 0xcd, 0xe5, 0x1c, 0x34, 0xf0, 0xcd, 0x2f, 0xff,
+ 0xed, 0x3e, 0xfe, 0x12, 0x44, 0x6a, 0x7d, 0x11, 0x80, 0x0b,
+ 0x78, 0xc2, 0xe6, 0x70, 0x04, 0x7d, 0x11, 0x80, 0x02, 0x7d,
+ 0x12, 0x7f, 0x07, 0x12, 0x3e, 0x9a, 0x8e, 0x1e, 0x8f, 0x1f,
+ 0x80, 0x03, 0xe5, 0x1e, 0xff, 0x78, 0xc5, 0xe6, 0x06, 0x24,
+ 0xcd, 0xf8, 0xa6, 0x07, 0x78, 0xc2, 0x06, 0xe6, 0xb4, 0x1a,
+ 0x0a, 0xe5, 0x1d, 0x24, 0x5c, 0x12, 0x44, 0x2a, 0x12, 0x3e,
+ 0xda, 0x78, 0xc5, 0xe6, 0x65, 0x1b, 0x70, 0x82, 0x75, 0xdb,
+ 0x20, 0x75, 0xdb, 0x28, 0x12, 0x44, 0x42, 0x12, 0x44, 0x42,
+ 0xe5, 0x1a, 0x12, 0x44, 0x35, 0xe5, 0x1a, 0xc3, 0x13, 0x12,
+ 0x44, 0x35, 0x78, 0xc5, 0x16, 0xe6, 0x24, 0xcd, 0xf8, 0xe6,
+ 0xff, 0x7e, 0x08, 0x1e, 0xef, 0xa8, 0x06, 0x08, 0x80, 0x02,
+ 0xc3, 0x13, 0xd8, 0xfc, 0xfd, 0xc4, 0x33, 0x54, 0xe0, 0xf5,
+ 0xdb, 0xef, 0xa8, 0x06, 0x08, 0x80, 0x02, 0xc3, 0x13, 0xd8,
+ 0xfc, 0xfd, 0xc4, 0x33, 0x54, 0xe0, 0x44, 0x08, 0xf5, 0xdb,
+ 0xee, 0x70, 0xd8, 0x78, 0xc5, 0xe6, 0x70, 0xc8, 0x75, 0xdb,
+ 0x10, 0x02, 0x40, 0xfd, 0x78, 0xc2, 0xe6, 0xc3, 0x94, 0x17,
+ 0x50, 0x0e, 0xe5, 0x1d, 0x24, 0x62, 0x12, 0x42, 0x08, 0xe5,
+ 0x1d, 0x24, 0x5c, 0x12, 0x42, 0x08, 0x20, 0x02, 0x03, 0x02,
+ 0x40, 0x76, 0x05, 0x1a, 0xe5, 0x1a, 0xc3, 0x94, 0x04, 0x50,
+ 0x03, 0x02, 0x40, 0x3a, 0x22, 0xe5, 0x1d, 0x24, 0x5c, 0xff,
+ 0xe5, 0x1c, 0x34, 0xf0, 0xfe, 0x12, 0x44, 0x6a, 0x22, 0xff,
+ 0xe5, 0x1c, 0x34, 0xf0, 0xfe, 0x12, 0x44, 0x6a, 0x22, 0xd2,
+ 0x00, 0x75, 0xfb, 0x03, 0xab, 0x7e, 0xaa, 0x7d, 0x7d, 0x19,
+ 0x7f, 0x03, 0x12, 0x3e, 0xda, 0xe5, 0x7e, 0x54, 0x0f, 0x24,
+ 0xf3, 0x60, 0x03, 0x02, 0x42, 0xb9, 0x12, 0x44, 0xa3, 0x12,
+ 0x44, 0xaa, 0xd8, 0xfb, 0xff, 0x20, 0xe2, 0x2a, 0x13, 0x92,
+ 0x04, 0xef, 0xa2, 0xe1, 0x92, 0x03, 0x30, 0x04, 0x1f, 0xe4,
+ 0xf5, 0x10, 0xe5, 0x10, 0x24, 0x17, 0xfd, 0x7b, 0x54, 0x7f,
+ 0x04, 0x12, 0x3d, 0xd7, 0x74, 0x25, 0x25, 0x10, 0xf8, 0xa6,
+ 0x07, 0x05, 0x10, 0xe5, 0x10, 0xc3, 0x94, 0x02, 0x40, 0xe4,
+ 0x12, 0x44, 0xa3, 0x12, 0x44, 0xaa, 0xd8, 0xfb, 0x54, 0x05,
+ 0x64, 0x04, 0x70, 0x27, 0x78, 0xc4, 0xe6, 0x78, 0xc6, 0xf6,
+ 0xe5, 0x7d, 0xff, 0x33, 0x95, 0xe0, 0xef, 0x54, 0x0f, 0x78,
+ 0xc4, 0xf6, 0x12, 0x42, 0xcf, 0x20, 0x04, 0x0c, 0x12, 0x44,
+ 0xa3, 0x12, 0x44, 0xaa, 0xd8, 0xfb, 0x13, 0x92, 0x05, 0x22,
+ 0xc2, 0x05, 0x22, 0x12, 0x44, 0xa3, 0x12, 0x44, 0xaa, 0xd8,
+ 0xfb, 0x54, 0x05, 0x64, 0x05, 0x70, 0x1e, 0x78, 0xc4, 0x7d,
+ 0xb8, 0x12, 0x42, 0xc5, 0x78, 0xc1, 0x7d, 0x74, 0x12, 0x42,
+ 0xc5, 0xe4, 0x78, 0xc1, 0xf6, 0x22, 0x7b, 0x01, 0x7a, 0x00,
+ 0x7d, 0xee, 0x7f, 0x92, 0x12, 0x38, 0xbd, 0x22, 0xe6, 0xfb,
+ 0x7a, 0x00, 0x7f, 0x92, 0x12, 0x38, 0xbd, 0x22, 0x78, 0xc1,
+ 0xe6, 0xfb, 0x7a, 0x00, 0x7d, 0x74, 0x7f, 0x92, 0x12, 0x38,
+ 0xbd, 0xe4, 0x78, 0xc1, 0xf6, 0xf5, 0x11, 0x74, 0x01, 0x7e,
+ 0x00, 0xa8, 0x11, 0x08, 0x80, 0x05, 0xc3, 0x33, 0xce, 0x33,
+ 0xce, 0xd8, 0xf9, 0xff, 0x78, 0xc4, 0xe6, 0xfd, 0xef, 0x5d,
+ 0x60, 0x44, 0x85, 0x11, 0xfb, 0xe5, 0x11, 0x54, 0x02, 0x25,
+ 0xe0, 0x25, 0xe0, 0xfe, 0xe4, 0x24, 0x5b, 0xfb, 0xee, 0x12,
+ 0x44, 0x2d, 0x12, 0x3e, 0xda, 0x7b, 0x40, 0x7d, 0x11, 0x7f,
+ 0x07, 0x12, 0x3d, 0xd7, 0x74, 0xc7, 0x25, 0x11, 0xf8, 0xa6,
+ 0x07, 0x7b, 0x11, 0x7d, 0x12, 0x7f, 0x07, 0x12, 0x3d, 0xd7,
+ 0xef, 0x4e, 0x60, 0x09, 0x74, 0xe7, 0x25, 0x11, 0xf8, 0x76,
+ 0x04, 0x80, 0x07, 0x74, 0xe7, 0x25, 0x11, 0xf8, 0x76, 0x0a,
+ 0x05, 0x11, 0xe5, 0x11, 0xc3, 0x94, 0x04, 0x40, 0x9a, 0x78,
+ 0xc6, 0xe6, 0x70, 0x15, 0x78, 0xc4, 0xe6, 0x60, 0x10, 0x75,
+ 0xd9, 0x38, 0x75, 0xdb, 0x10, 0x7d, 0xfe, 0x12, 0x43, 0x7d,
+ 0x7d, 0x76, 0x12, 0x43, 0x7d, 0x79, 0xc6, 0xe7, 0x78, 0xc4,
+ 0x66, 0xff, 0x60, 0x03, 0x12, 0x40, 0x25, 0x78, 0xc4, 0xe6,
+ 0x70, 0x09, 0xfb, 0xfa, 0x7d, 0xfe, 0x7f, 0x8e, 0x12, 0x38,
+ 0xbd, 0x22, 0x7b, 0x01, 0x7a, 0x00, 0x7f, 0x8e, 0x12, 0x38,
+ 0xbd, 0x22, 0xe4, 0xf5, 0x19, 0x74, 0x25, 0x25, 0x19, 0xf8,
+ 0xe6, 0x64, 0x03, 0x60, 0x51, 0xe5, 0x19, 0x24, 0x17, 0xfd,
+ 0x7b, 0xeb, 0x7f, 0x04, 0x12, 0x3d, 0xd7, 0x8f, 0xfb, 0x7b,
+ 0x22, 0x7d, 0x18, 0x7f, 0x06, 0x12, 0x3d, 0xd7, 0xef, 0x64,
+ 0x01, 0x4e, 0x60, 0x1c, 0x7d, 0x1c, 0xe4, 0xff, 0x12, 0x3e,
+ 0x9a, 0xef, 0x54, 0x1b, 0x64, 0x0a, 0x70, 0x15, 0x7b, 0xcc,
+ 0x7d, 0x10, 0xff, 0x12, 0x3d, 0xd7, 0xef, 0x64, 0x01, 0x4e,
+ 0x70, 0x07, 0x12, 0x44, 0xb1, 0x7b, 0x03, 0x80, 0x0a, 0x12,
+ 0x44, 0xb1, 0x74, 0x25, 0x25, 0x19, 0xf8, 0xe6, 0xfb, 0x7a,
+ 0x00, 0x7d, 0x54, 0x12, 0x38, 0xbd, 0x05, 0x19, 0xe5, 0x19,
+ 0xc3, 0x94, 0x02, 0x40, 0x9c, 0x22, 0xe5, 0x7e, 0x30, 0xe5,
+ 0x35, 0x30, 0xe4, 0x0b, 0x7b, 0x02, 0x7d, 0x33, 0x7f, 0x35,
+ 0x12, 0x36, 0x29, 0x80, 0x10, 0x7b, 0x01, 0x7d, 0x33, 0x7f,
+ 0x35, 0x12, 0x36, 0x29, 0x90, 0x47, 0xd2, 0xe0, 0x44, 0x04,
+ 0xf0, 0x90, 0x47, 0xd2, 0xe0, 0x54, 0xf7, 0xf0, 0x90, 0x47,
+ 0xd1, 0xe0, 0x44, 0x10, 0xf0, 0x7b, 0x05, 0x7d, 0x84, 0x7f,
+ 0x86, 0x12, 0x36, 0x29, 0x22, 0xfb, 0xe5, 0x1c, 0x34, 0xf0,
+ 0xfa, 0x7d, 0x10, 0x7f, 0x07, 0x22, 0x54, 0x01, 0xc4, 0x33,
+ 0x54, 0xe0, 0xf5, 0xdb, 0x44, 0x08, 0xf5, 0xdb, 0x22, 0xf5,
+ 0xdb, 0x75, 0xdb, 0x08, 0xf5, 0xdb, 0x75, 0xdb, 0x08, 0x22,
+ 0xe5, 0x7e, 0x54, 0x0f, 0x64, 0x01, 0x70, 0x0d, 0xe5, 0x7e,
+ 0x30, 0xe4, 0x08, 0x90, 0x47, 0xd0, 0xe0, 0x44, 0x02, 0xf0,
+ 0x22, 0x90, 0x47, 0xd0, 0xe0, 0x54, 0xfd, 0xf0, 0x22, 0xab,
+ 0x07, 0xaa, 0x06, 0x7d, 0x10, 0x7f, 0x07, 0x12, 0x3e, 0xda,
+ 0x7b, 0xff, 0x7d, 0x10, 0x7f, 0x07, 0x12, 0x3d, 0xd7, 0xef,
+ 0x4e, 0x60, 0xf3, 0x22, 0x12, 0x44, 0xc5, 0x12, 0x44, 0xbb,
+ 0x90, 0x47, 0xfa, 0xe0, 0x54, 0xf8, 0x44, 0x02, 0xf0, 0x22,
+ 0x30, 0x04, 0x03, 0x12, 0x43, 0x87, 0x78, 0xc4, 0xe6, 0xff,
+ 0x60, 0x03, 0x12, 0x40, 0x25, 0x22, 0xe5, 0x7e, 0xae, 0x7d,
+ 0x78, 0x04, 0x22, 0xce, 0xa2, 0xe7, 0x13, 0xce, 0x13, 0x22,
+ 0xe5, 0x19, 0x24, 0x17, 0x54, 0x1f, 0x44, 0x80, 0xff, 0x22,
+ 0xe4, 0x78, 0xc4, 0xf6, 0xc2, 0x05, 0x78, 0xc1, 0xf6, 0x22,
+ 0xc2, 0x04, 0xc2, 0x03, 0x22, 0x22
+};
+
+/**
+ * Setup Vitesse PHYs
+ * This function sets up one port in a Vitesse VSC8574 for
+ * either SGMII or QSGMII
+ */
+static void setup_vitesse_phy(bdk_node_t node, int mdio_bus, int phy_addr, bool qsgmii)
+{
+ // Select "G" registers
+ bdk_mdio_write(node, mdio_bus, phy_addr, 31, 0x10);
+ // Reg 19G, bit 15:14
+ // 0 = SGMII
+ // 1 = QSGMII
+ int reg19 = bdk_mdio_read(node, mdio_bus, phy_addr, 19);
+ int reg18;
+ if (qsgmii)
+ {
+ // QSGMII
+ reg19 = (reg19 & ~(3 << 14)) | (1 << 14);
+ reg18 = 0x80e0;
+ }
+ else
+ {
+ // SGMII
+ reg19 = (reg19 & ~(3 << 14)) | (0 << 14);
+ reg18 = 0x80f0;
+ }
+ bdk_mdio_write(node, mdio_bus, phy_addr, 19, reg19);
+ // Write 18G, change all 4 ports
+ bdk_mdio_write(node, mdio_bus, phy_addr, 18, reg18);
+ // Select main registers
+ bdk_mdio_write(node, mdio_bus, phy_addr, 31, 0);
+ // Reg23, 10:8 Select copper
+ int reg23 = bdk_mdio_read(node, mdio_bus, phy_addr, 23);
+ reg23 = (reg23 & ~(7 << 8)) | (0 << 8);
+ bdk_mdio_write(node, mdio_bus, phy_addr, 23, reg23);
+ // Reg0, Reset
+ int reg0 = bdk_mdio_read(node, mdio_bus, phy_addr, 0);
+ reg0 |= (1 << 15);
+ bdk_mdio_write(node, mdio_bus, phy_addr, 0, reg0);
+ // Reg 16E3, bit 7 auto negotiation
+ bdk_mdio_write(node, mdio_bus, phy_addr, 31, 3);
+ bdk_mdio_write(node, mdio_bus, phy_addr, 16, 0x80);
+ // Select main registers
+ bdk_mdio_write(node, mdio_bus, phy_addr, 31, 0);
+ // Near end loopback (Thunder side)
+ if (LOOP_INTERNAL)
+ {
+ reg0 = bdk_mdio_read(node, mdio_bus, phy_addr, 0);
+ reg0 |= (1 << 14);
+ bdk_mdio_write(node, mdio_bus, phy_addr, 0, reg0);
+ }
+
+ // Far end loopback (External side)
+ if (LOOP_EXTERNAL)
+ {
+ reg23 = bdk_mdio_read(node, mdio_bus, phy_addr, 23);
+ reg23 |= (1 << 3);
+ bdk_mdio_write(node, mdio_bus, phy_addr, 23, reg23);
+ }
+}
+
+static void wr_masked(bdk_node_t node, int mdio_bus, int phy_addr, int reg, int value, int mask)
+{
+ int nmask = ~mask;
+ int old = bdk_mdio_read(node, mdio_bus, phy_addr, reg);
+ int vmask = value & mask;
+ int newv = old & nmask;
+ newv = newv | vmask;
+ bdk_mdio_write(node, mdio_bus, phy_addr, reg, newv);
+}
+
+static void vitesse_program(bdk_node_t node, int mdio_bus, int phy_addr)
+{
+ printf("Programming Vitesse PHY at address %d\n", phy_addr);
+ bdk_mdio_write(node, mdio_bus, phy_addr, 31, 0x0010);
+ bdk_mdio_write(node, mdio_bus, phy_addr, 18, 0x800f);
+ bdk_mdio_write(node, mdio_bus, phy_addr, 31, 0x0010);
+
+ int reg18g = bdk_mdio_read(node, mdio_bus, phy_addr, 18);
+ int timeout = 10;
+ while ((reg18g & (1<<15)) && (timeout > 0))
+ {
+ bdk_wait_usec(100000);
+ reg18g = bdk_mdio_read(node, mdio_bus, phy_addr, 18);
+ timeout = timeout - 1;
+ }
+ if (timeout == 0)
+ bdk_error("Vetesse: Timeout waiting for complete\n");
+
+ bdk_mdio_write(node, mdio_bus, phy_addr, 31, 0x0000);
+ bdk_mdio_write(node, mdio_bus, phy_addr, 31, 0x0010);
+ wr_masked(node, mdio_bus, phy_addr, 12, 0x0000, 0x0800);
+ bdk_mdio_write(node, mdio_bus, phy_addr, 9, 0x005b);
+ bdk_mdio_write(node, mdio_bus, phy_addr, 10, 0x005b);
+ wr_masked(node, mdio_bus, phy_addr, 12, 0x0800, 0x0800);
+ bdk_mdio_write(node, mdio_bus, phy_addr, 18, 0x800f);
+ wr_masked(node, mdio_bus, phy_addr, 0, 0x0000, 0x8000);
+ bdk_mdio_write(node, mdio_bus, phy_addr, 18, 0x0000);
+ wr_masked(node, mdio_bus, phy_addr, 12, 0x0000, 0x0800);
+ bdk_mdio_write(node, mdio_bus, phy_addr, 31, 0x10);
+ bdk_mdio_write(node, mdio_bus, phy_addr, 0, 0x7009);
+ bdk_mdio_write(node, mdio_bus, phy_addr, 12, 0x5002);
+ bdk_mdio_write(node, mdio_bus, phy_addr, 11, 0x0000);
+
+ for (unsigned int i=0; i<sizeof(patch_arr); i++)
+ {
+ int d = 0x5000 | patch_arr[i];
+ bdk_mdio_write(node, mdio_bus, phy_addr, 12, d);
+ }
+ bdk_mdio_write(node, mdio_bus, phy_addr, 12, 0x0000);
+
+ bdk_mdio_write(node, mdio_bus, phy_addr, 3, 0x3eb7);
+ bdk_mdio_write(node, mdio_bus, phy_addr, 4, 0x4012);
+ bdk_mdio_write(node, mdio_bus, phy_addr, 12, 0x0100);
+ bdk_mdio_write(node, mdio_bus, phy_addr, 0, 0x4018);
+ bdk_mdio_write(node, mdio_bus, phy_addr, 0, 0xc018);
+
+ // below verifies CRC is correct in 8051 RAM. CRC is 16-bit.
+ bdk_mdio_write(node, mdio_bus, phy_addr, 31, 0x0001);
+ bdk_mdio_write(node, mdio_bus, phy_addr, 25, 0x4000);
+ bdk_mdio_write(node, mdio_bus, phy_addr, 26, sizeof(patch_arr) + 1);
+ bdk_mdio_write(node, mdio_bus, phy_addr, 31, 0x0010);
+ bdk_mdio_write(node, mdio_bus, phy_addr, 18, 0x8008);
+
+ reg18g = bdk_mdio_read(node, mdio_bus, phy_addr, 18);
+ timeout = 10;
+ while ((reg18g & (1<<15)) && (timeout > 0))
+ {
+ bdk_wait_usec(100000);
+ reg18g = bdk_mdio_read(node, mdio_bus, phy_addr, 18);
+ timeout = timeout - 1;
+ }
+ if (timeout == 0)
+ bdk_error("Vetesse: Timeout waiting for complete\n");
+
+ bdk_mdio_write(node, mdio_bus, phy_addr, 31, 0x0001);
+
+ int crc_calculated = bdk_mdio_read(node, mdio_bus, phy_addr, 25);
+ if (crc_calculated != 0xB7C2)
+ printf("8051 crc_calculated = 0x%x, expected_crc = 0x%x\n", crc_calculated, 0xB7C2);
+
+ bdk_mdio_write(node, mdio_bus, phy_addr, 31, 0x0000);
+}
+
+//static void vetesse_setup(bdk_node_t node, int qlm, int mdio_bus, int phy_addr)
+int bdk_if_phy_vetesse_setup(bdk_node_t node, int qlm, int mdio_bus, int phy_addr)
+{
+ /* Check if the PHY is Vetesse PHY we expect */
+ int phy_status = bdk_mdio_read(node, mdio_bus, phy_addr, BDK_MDIO_PHY_REG_ID1);
+ if (phy_status != 0x0007)
+ return 0;
+
+ /* Check that the GSER mode is SGMII or QSGMII */
+ bdk_qlm_modes_t qlm_mode = bdk_qlm_get_mode(node, qlm);
+ if ((qlm_mode != BDK_QLM_MODE_SGMII_1X1) &&
+ (qlm_mode != BDK_QLM_MODE_SGMII_2X1) &&
+ (qlm_mode != BDK_QLM_MODE_SGMII_4X1) &&
+ (qlm_mode != BDK_QLM_MODE_QSGMII_4X1))
+ return 0;
+
+ /* Program the Vetesse PHY */
+ vitesse_program(node, mdio_bus, phy_addr);
+
+ /* Switch the Vitesse PHY to the correct mode */
+ bool is_qsgmii = (qlm_mode == BDK_QLM_MODE_QSGMII_4X1);
+ if (is_qsgmii)
+ {
+ for (int port = 0; port < 4; port++)
+ setup_vitesse_phy(node, mdio_bus, phy_addr + port, true);
+ }
+ else
+ setup_vitesse_phy(node, mdio_bus, phy_addr, false);
+ return 0;
+}
+
+#if 0
+int bdk_if_phy_vetesse_setup(bdk_node_t node)
+{
+ for (int bgx = 0; bgx < 4; bgx++)
+ {
+ int port = 0;
+ int phy_addr = bdk_config_get_int(BDK_CONFIG_PHY_ADDRESS, node, bgx, port);
+ if (phy_addr != -1)
+ {
+ int node = (phy_addr >> 24) & 0xff;
+ int mdio_bus = (phy_addr >> 8) & 0xff;
+ int mdio_addr = phy_addr & 0xff;
+ if (node == 0xff)
+ node = bdk_numa_local();
+ if ((phy_addr & BDK_IF_PHY_TYPE_MASK) == BDK_IF_PHY_MDIO)
+ {
+ int qlm = bdk_qlm_get(node, BDK_IF_BGX, bgx, port);
+ if (qlm != -1)
+ vetesse_setup(node, qlm, mdio_bus, mdio_addr);
+ }
+ }
+ }
+ return 0;
+}
+#endif
diff --git a/src/vendorcode/cavium/bdk/libbdk-hal/if/bdk-if-phy.c b/src/vendorcode/cavium/bdk/libbdk-hal/if/bdk-if-phy.c
new file mode 100644
index 0000000000..5b02eff0cd
--- /dev/null
+++ b/src/vendorcode/cavium/bdk/libbdk-hal/if/bdk-if-phy.c
@@ -0,0 +1,445 @@
+/***********************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-hal/if/bdk-if.h>
+#include <libbdk-hal/bdk-config.h>
+#include <libbdk-hal/bdk-mdio.h>
+#include <libbdk-hal/bdk-qlm.h>
+#include <libbdk-hal/bdk-twsi.h>
+
+/**
+ * Called when the PHY is connected through TWSI
+ *
+ * @param dev_node Node the ethernet device is on
+ * @param phy_addr Encoded address, see bdk-if.h for format
+ *
+ * @return Link status
+ */
+static bdk_if_link_t __bdk_if_phy_get_twsi(bdk_node_t dev_node, int phy_addr)
+{
+ /* For TWSI:
+ Bits[31:24]: Node ID, 0xff for device node
+ Bits[23:16]: TWSI internal address width in bytes (0-2)
+ Bits[15:12]: 2=TWSI
+ Bits[11:8]: TWSI bus number
+ Bits[7:0]: TWSI address */
+ int node = (phy_addr >> 24) & 0xff;
+ int twsi_ia_width = (phy_addr >> 16) & 0xff;
+ int twsi_bus = (phy_addr >> 8) & 0xf;
+ int twsi_addr = phy_addr & 0xff;
+ if (node == 0xff)
+ node = dev_node;
+
+ bdk_if_link_t result;
+ result.u64 = 0;
+
+ /* This is from the Avago SFP 1G Module data sheet
+ Register 17 (Extended Status 1) */
+ int64_t phy_status = bdk_twsix_read_ia(node, twsi_bus, twsi_addr, 17, 2, twsi_ia_width);
+ if (phy_status != -1)
+ {
+ int speed = (phy_status >> 14)& 3;
+ int duplex = (phy_status >> 13)& 1;
+ int resolved = (phy_status >> 11)& 1;
+ int link = (phy_status >> 10)& 1;
+ if (resolved)
+ {
+ result.s.up = link;
+ result.s.full_duplex = duplex;
+ switch (speed)
+ {
+ case 0: /* 10 Mbps */
+ result.s.speed = 10;
+ break;
+ case 1: /* 100 Mbps */
+ result.s.speed = 100;
+ break;
+ case 2: /* 1 Gbps */
+ result.s.speed = 1000;
+ break;
+ case 3: /* Illegal */
+ result.u64 = 0;
+ break;
+ }
+ }
+ }
+
+ return result;
+}
+
+/**
+ * Read the status of a PHY
+ *
+ * @param dev_node Node the ethernet device is on
+ * @param phy_addr Encoded PHY address, see bdk-if.h for format
+ *
+ * @return Link status
+ */
+bdk_if_link_t __bdk_if_phy_get(bdk_node_t dev_node, int phy_addr)
+{
+ int node = (phy_addr >> 24) & 0xff;
+ int mdio_bus = (phy_addr >> 8) & 0xff;
+ int mdio_addr = phy_addr & 0xff;
+ if (node == 0xff)
+ node = dev_node;
+ int phy_status;
+ bdk_if_link_t result;
+ result.u64 = 0;
+
+ /* PHY address of -1 menas there is no PHY and we should have never
+ gotten here */
+ if (phy_addr == -1)
+ return result;
+
+ /* A PHY address with the special value 0x1000 represents a PHY we can't
+ connect to through MDIO which is assumed to be at 1Gbps */
+ if (phy_addr == BDK_IF_PHY_FIXED_1GB)
+ {
+ result.s.up = 1;
+ result.s.full_duplex = 1;
+ result.s.speed = 1000;
+ return result;
+ }
+
+ /* A PHY address with the special value 0x1001 represents a PHY we can't
+ connect to through MDIO which is assumed to be at 100Mbps */
+ if (phy_addr == BDK_IF_PHY_FIXED_100MB)
+ {
+ result.s.up = 1;
+ result.s.full_duplex = 1;
+ result.s.speed = 100;
+ return result;
+ }
+
+ /* Check for a PHY connected through TWSI */
+ if ((phy_addr & BDK_IF_PHY_TYPE_MASK) == BDK_IF_PHY_TWSI)
+ return __bdk_if_phy_get_twsi(dev_node, phy_addr);
+
+ phy_status = bdk_mdio_read(node, mdio_bus, mdio_addr, BDK_MDIO_PHY_REG_ID1);
+ if ((phy_status <= 0) || (phy_status == 0xffff))
+ return result;
+
+ switch (phy_status)
+ {
+ case 0x0141: /* Marvell */
+ {
+
+ /* This code assumes we are using a Marvell Gigabit PHY. All the
+ speed information can be read from register 17 in one go. Somebody
+ using a different PHY will need to handle it above in the board
+ specific area */
+ phy_status = bdk_mdio_read(node, mdio_bus, mdio_addr, 17);
+ if (phy_status < 0)
+ return result;
+
+ /* If the resolve bit 11 isn't set, see if autoneg is turned off
+ (bit 12, reg 0). The resolve bit doesn't get set properly when
+ autoneg is off, so force it */
+ if ((phy_status & (1<<11)) == 0)
+ {
+ bdk_mdio_phy_reg_control_t control;
+ int phy_c = bdk_mdio_read(node, mdio_bus, mdio_addr, BDK_MDIO_PHY_REG_CONTROL);
+ if (phy_c < 0)
+ return result;
+ control.u16 = phy_c;
+ if (control.s.autoneg_enable == 0)
+ phy_status |= 1<<11;
+ }
+
+ /* Only return a link if the PHY has finished auto negotiation
+ and set the resolved bit (bit 11) */
+ if (phy_status & (1<<11))
+ {
+ result.s.up = 1;
+ result.s.full_duplex = ((phy_status>>13)&1);
+ switch ((phy_status>>14)&3)
+ {
+ case 0: /* 10 Mbps */
+ result.s.speed = 10;
+ break;
+ case 1: /* 100 Mbps */
+ result.s.speed = 100;
+ break;
+ case 2: /* 1 Gbps */
+ result.s.speed = 1000;
+ break;
+ case 3: /* Illegal */
+ result.u64 = 0;
+ break;
+ }
+ }
+ break;
+ }
+ case 0x0022: /* Kendin */
+ {
+ /* Register 1Fh - PHY Control */
+ /* Micrel KSZ9031RNX, EBB8104 RGMII transceiver */
+ /* Reports as "Kendin" in BDK_MDIO_PHY_REG_ID1 */
+ phy_status = bdk_mdio_read(node, mdio_bus, mdio_addr, 0x1F);
+ if (phy_status & (1 << 6)) // Speed Status - 1000Base-T
+ {
+ result.s.up = 1;
+ result.s.speed = 1000;
+ }
+ else if (phy_status & (1 << 5)) // Speed Status - 100Base-TX
+ {
+ result.s.up = 1;
+ result.s.speed = 100;
+ }
+ else if (phy_status & (1 << 4)) // Speed Status - 10Base-T
+ {
+ result.s.up = 1;
+ result.s.speed = 10;
+ }
+ if (phy_status & (1 << 3)) // Duplex Status
+ {
+ result.s.full_duplex = 1;
+ }
+ break;
+ }
+ case 0x0007: /* Vitesse */
+ {
+ /* Auxiliary Control and Status, Address 28 (0x1C) */
+ phy_status = bdk_mdio_read(node, mdio_bus, mdio_addr, 0x1c);
+ result.s.full_duplex = (phy_status>>5)&1;
+ switch ((phy_status>>3) & 3)
+ {
+ case 0:
+ result.s.speed = 10;
+ result.s.up = 1;
+ break;
+ case 1:
+ result.s.speed = 100;
+ result.s.up = 1;
+ break;
+ default:
+ result.s.speed = 1000;
+ break;
+ }
+ phy_status = bdk_mdio_read(node, mdio_bus, mdio_addr, 0x01);
+ result.s.up = (phy_status>>2)&1;
+ break;
+ }
+ default: /* Treat like Broadcom */
+ {
+ /* Below we are going to read SMI/MDIO register 0x19 which works
+ on Broadcom parts */
+ phy_status = bdk_mdio_read(node, mdio_bus, mdio_addr, 0x19);
+ if (phy_status < 0)
+ return result;
+
+ switch ((phy_status>>8) & 0x7)
+ {
+ case 0:
+ result.u64 = 0;
+ break;
+ case 1:
+ result.s.up = 1;
+ result.s.full_duplex = 0;
+ result.s.speed = 10;
+ break;
+ case 2:
+ result.s.up = 1;
+ result.s.full_duplex = 1;
+ result.s.speed = 10;
+ break;
+ case 3:
+ result.s.up = 1;
+ result.s.full_duplex = 0;
+ result.s.speed = 100;
+ break;
+ case 4:
+ result.s.up = 1;
+ result.s.full_duplex = 1;
+ result.s.speed = 100;
+ break;
+ case 5:
+ result.s.up = 1;
+ result.s.full_duplex = 1;
+ result.s.speed = 100;
+ break;
+ case 6:
+ result.s.up = 1;
+ result.s.full_duplex = 0;
+ result.s.speed = 1000;
+ break;
+ case 7:
+ result.s.up = 1;
+ result.s.full_duplex = 1;
+ result.s.speed = 1000;
+ break;
+ }
+ break;
+ }
+ }
+
+ /* If link is down, return all fields as zero. */
+ if (!result.s.up)
+ result.u64 = 0;
+
+ return result;
+}
+
+/**
+ * PHY XS initialization, primarily for RXAUI
+ *
+ * @param dev_node Node the ethernet device is on
+ * @param phy_addr Encoded PHY address, see bdk-if.h for format
+ *
+ * @return none
+ */
+void __bdk_if_phy_xs_init(bdk_node_t dev_node, int phy_addr)
+{
+ /* This code only supports PHYs connected through MDIO */
+ if ((phy_addr & BDK_IF_PHY_TYPE_MASK) != BDK_IF_PHY_MDIO)
+ return;
+
+ int node = (phy_addr >> 24) & 0xff;
+ int mdio_bus = (phy_addr >> 8) & 0xff;
+ int mdio_addr = phy_addr & 0xff;
+ if (node == 0xff)
+ node = dev_node;
+
+ /* Read the PMA/PMD Device Identifier (1.2, 1.3)
+ OUI is spread across both registers */
+ int dev_addr = 1;
+ int reg_addr = 2;
+ int phy_id1 = bdk_mdio_45_read(node, mdio_bus, mdio_addr, dev_addr, reg_addr);
+ if (phy_id1 == -1)
+ return;
+ reg_addr = 3;
+ int phy_id2 = bdk_mdio_45_read(node, mdio_bus, mdio_addr, dev_addr, reg_addr);
+ if (phy_id2 == -1)
+ return;
+ int model_number = (phy_id2 >> 4) & 0x3F;
+ int oui = phy_id1;
+ oui <<= 6;
+ oui |= (phy_id2 >> 10) & 0x3F;
+ switch (oui)
+ {
+ case 0x5016: /* Marvell */
+ if (model_number == 9) /* 88X3140/3120 */
+ {
+ BDK_TRACE(BGX, "N%d.MDIO%d.%d: Performing PHY reset on Marvell RXAUI PHY\n",
+ node, mdio_bus, mdio_addr);
+ dev_addr = 4;
+ reg_addr = 0;
+ /* Write bit 15, Software Reset, in PHY XS Control 1 (4.0). On CN78xx,
+ sometimes the PHY/BGX gets stuck in local fault mode, link never comes up,
+ and this appears to clear it up. Haven't seen this on CN81xx or T88,
+ but the reset seems like cheap insurance. */
+ if (bdk_mdio_45_write(node, mdio_bus, mdio_addr, dev_addr, reg_addr, (1 << 15)))
+ {
+ bdk_error("PHY XS: MDIO write to (%d.%d) failed\n", dev_addr, reg_addr);
+ return;
+ }
+
+ int reset_pending = 1;
+ while (reset_pending)
+ {
+ reset_pending = bdk_mdio_45_read(node, mdio_bus, mdio_addr, dev_addr, reg_addr);
+ reset_pending &= (1 << 15);
+ }
+
+ /* Adjust the RXAUI TX Level for Marvell PHY, per Brendan Metzner
+ write 5 to register 4.49155 */
+ reg_addr = 49155;
+ if (bdk_mdio_45_write(node, mdio_bus, mdio_addr, dev_addr, reg_addr, 5))
+ {
+ bdk_error("PHY XS: MDIO write to (%d.%d) failed\n", dev_addr, reg_addr);
+ return;
+ }
+ }
+ break;
+
+ default: /* Unknown PHY, or no PHY present */
+ break;
+ }
+}
+
+int bdk_if_phy_setup(bdk_node_t dev_node)
+{
+ /* 81xx has only 2 BGX (BGX0-BGX1); BGX2 is RGMII */
+ for (int bgx = 0; bgx < 2; bgx++)
+ {
+ int port = 0;
+ int phy_addr = bdk_config_get_int(BDK_CONFIG_PHY_ADDRESS, dev_node, bgx, port);
+ if (phy_addr != -1)
+ {
+ int node = (phy_addr >> 24) & 0xff;
+ int mdio_bus = (phy_addr >> 8) & 0xff;
+ int mdio_addr = phy_addr & 0xff;
+ if (node == 0xff)
+ node = bdk_numa_local();
+ if ((phy_addr & BDK_IF_PHY_TYPE_MASK) == BDK_IF_PHY_MDIO)
+ {
+ int qlm = bdk_qlm_get_qlm_num(node, BDK_IF_BGX, bgx, port);
+ if (qlm == -1)
+ continue;
+
+ BDK_TRACE(PHY, "N%d.BGX%d.%d: Configuring ...\n", node, bgx, port);
+
+ /* Check PHY id */
+ int phy_status_1 = bdk_mdio_read(node, mdio_bus, phy_addr, BDK_MDIO_PHY_REG_ID1);
+ int phy_status_2 = bdk_mdio_read(node, mdio_bus, phy_addr, BDK_MDIO_PHY_REG_ID2);
+
+ /* Vitesse */
+ if (phy_status_1 == 0x0007)
+ {
+ if (phy_status_2 == 0x0670)
+ {
+ bdk_if_phy_vsc8514_setup(node, qlm, mdio_bus, mdio_addr);
+ }
+ else
+ {
+ bdk_if_phy_vetesse_setup(node, qlm, mdio_bus, mdio_addr);
+ }
+ }
+
+ /* Marvell */
+ else if (phy_status_1 == 0x0141)
+ bdk_if_phy_marvell_setup(node, qlm, mdio_bus, mdio_addr);
+ else
+ BDK_TRACE(PHY, "N%d.BGX%d.%d: Unknown PHY %x\n", node, bgx, port, phy_status_1);
+ }
+ }
+ }
+ return 0;
+}
+
diff --git a/src/vendorcode/cavium/bdk/libbdk-hal/qlm/bdk-qlm-cn81xx.c b/src/vendorcode/cavium/bdk/libbdk-hal/qlm/bdk-qlm-cn81xx.c
new file mode 100644
index 0000000000..303b276a8b
--- /dev/null
+++ b/src/vendorcode/cavium/bdk/libbdk-hal/qlm/bdk-qlm-cn81xx.c
@@ -0,0 +1,1003 @@
+/***********************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-hal/bdk-qlm.h"
+#include "libbdk-hal/qlm/bdk-qlm-common.h"
+#include "libbdk-arch/bdk-csrs-bgx.h"
+#include "libbdk-arch/bdk-csrs-gser.h"
+#include "libbdk-arch/bdk-csrs-pem.h"
+#include "libbdk-arch/bdk-csrs-sata.h"
+#include "libbdk-arch/bdk-csrs-rst.h"
+#include "libbdk-hal/bdk-config.h"
+#include "libbdk-hal/qlm/bdk-qlm-errata-cn8xxx.h"
+#include "libbdk-hal/bdk-gpio.h"
+
+/**
+ * Return the number of QLMs supported for the chip
+ *
+ * @return Number of QLMs
+ */
+int bdk_qlm_get_num(bdk_node_t node)
+{
+ return 4; /* 4 DLM */
+}
+
+/**
+ * Return the number of lanes in a QLM. QLMs normally contain
+ * 4 lanes, except for chips which only have half of a QLM.
+ *
+ * @param qlm QLM to get lanes number for
+ *
+ * @return Number of lanes on the QLM
+ */
+int bdk_qlm_get_lanes(bdk_node_t node, int qlm)
+{
+
+ if ((qlm < 2) && cavium_is_altpkg(CAVIUM_CN81XX))
+ return 1; /* DLM0 and DLM1 are a single lane on CN80XX */
+ else
+ return 2; /* DLMs */
+}
+
+/**
+ * Lookup the hardware QLM number for a given interface type and index. This
+ * function will fail with a fatal error if called on invalid interfaces for
+ * a chip. It returns the QLM number for an interface without checking to
+ * see if the QLM is in the correct mode.
+ *
+ * @param iftype Interface type
+ * @param interface Interface index number
+ *
+ * @return QLM number. Dies on a fatal error on failure.
+ */
+int bdk_qlm_get_qlm_num(bdk_node_t node, bdk_if_t iftype, int interface, int index)
+{
+ switch (iftype)
+ {
+ case BDK_IF_BGX:
+ {
+ int qlm;
+ switch (interface)
+ {
+ case 0:
+ {
+ /* This BGX spans two DLMs. The index must be used to
+ figure out which DLM we are using */
+ BDK_CSR_INIT(gserx_cfg, node, BDK_GSERX_CFG(0));
+ if (gserx_cfg.s.bgx)
+ {
+ if (gserx_cfg.s.bgx_quad) /* 4 lanes together */
+ qlm = 0;
+ else if (gserx_cfg.s.bgx_dual) /* 2 lanes together */
+ qlm = (index >= 1) ? 1 : 0;
+ else /* All lanes independent */
+ {
+ bdk_qlm_modes_t mode = bdk_qlm_get_mode(node, 0);
+ if (mode == BDK_QLM_MODE_QSGMII_4X1)
+ qlm = 0;
+ else if (mode <= BDK_QLM_MODE_PCIE_1X8)
+ qlm = 1;
+ else if (cavium_is_altpkg(CAVIUM_CN81XX))
+ {
+ bdk_qlm_modes_t mode1 = bdk_qlm_get_mode(node, 1);
+ if ((mode1 != BDK_QLM_MODE_QSGMII_4X1) && (index >= 2))
+ return -1;
+ qlm = (index >= 1) ? 1 : 0;
+ }
+ else
+ qlm = (index >= 2) ? 1 : 0;
+ }
+ }
+ else
+ qlm = 1;
+ break;
+ }
+ case 1:
+ {
+ /* This BGX spans two DLMs. The index must be used to
+ figure out which DLM we are using */
+ BDK_CSR_INIT(gserx_cfg, node, BDK_GSERX_CFG(2));
+ if (gserx_cfg.s.bgx)
+ {
+ if (gserx_cfg.s.bgx_quad) /* 4 lanes together */
+ qlm = 2;
+ else if (gserx_cfg.s.bgx_dual) /* 2 lanes together */
+ qlm = (index >= 1) ? 3 : 2;
+ else /* All lanes independent */
+ {
+ bdk_qlm_modes_t mode = bdk_qlm_get_mode(node, 2);
+ if (mode == BDK_QLM_MODE_QSGMII_4X1)
+ qlm = 2;
+ else if (mode <= BDK_QLM_MODE_PCIE_1X8)
+ qlm = 1;
+ else
+ qlm = (index >= 2) ? 3 : 2;
+ }
+ }
+ else
+ qlm = 3;
+ break;
+ }
+ default:
+ return -1;
+ }
+ /* Make sure the QLM is powered up and out of reset */
+ BDK_CSR_INIT(phy_ctl, node, BDK_GSERX_PHY_CTL(qlm));
+ if (phy_ctl.s.phy_pd || phy_ctl.s.phy_reset)
+ return -1;
+ /* Make sure the QLM is in BGX mode */
+ BDK_CSR_INIT(gserx_cfg, node, BDK_GSERX_CFG(qlm));
+ if (gserx_cfg.s.bgx)
+ return qlm;
+ else
+ return -1;
+ }
+ case BDK_IF_PCIE: /* PCIe */
+ {
+ switch (interface)
+ {
+ case 0: /* PEM0 */
+ {
+ BDK_CSR_INIT(gserx_cfg, node, BDK_GSERX_CFG(0));
+ if (gserx_cfg.s.pcie)
+ return 0; /* PEM0 is on DLM0 */
+ else
+ return -1; /* PEM0 is disabled */
+ }
+ case 1: /* PEM1 */
+ {
+ BDK_CSR_INIT(gserx_cfg, node, BDK_GSERX_CFG(2));
+ if (gserx_cfg.s.pcie)
+ return 2; /* PEM1 is on DLM2 */
+ else
+ return -1; /* PEM1 is disabled */
+ }
+ case 2: /* PEM2 */
+ {
+ BDK_CSR_INIT(pem1_cfg, node, BDK_PEMX_CFG(1));
+ BDK_CSR_INIT(gserx_cfg, node, BDK_GSERX_CFG(3));
+ if (!pem1_cfg.cn81xx.lanes4 && gserx_cfg.s.pcie)
+ return 3; /* PEM2 is on DLM3 */
+ else
+ return -1; /* PEM2 is disabled */
+ }
+ default: /* Max of 3 PEMs, 0-2 */
+ return -1;
+ }
+ }
+ default: /* Not supported by CN81XX */
+ return -1;
+ }
+}
+
+/**
+ * Get the mode of a QLM as a human readable string
+ *
+ * @param qlm QLM to examine
+ *
+ * @return String mode
+ */
+bdk_qlm_modes_t bdk_qlm_get_mode(bdk_node_t node, int qlm)
+{
+ BDK_CSR_INIT(gserx_cfg, node, BDK_GSERX_CFG(qlm));
+ if (gserx_cfg.s.pcie)
+ {
+ switch (qlm)
+ {
+ case 0: /* PEM0 */
+ {
+ BDK_CSR_INIT(pemx_cfg, node, BDK_PEMX_CFG(0));
+ if (cavium_is_altpkg(CAVIUM_CN81XX))
+ return BDK_QLM_MODE_PCIE_1X1; /* PEM0 x1 */
+ else if (pemx_cfg.cn81xx.lanes4)
+ return BDK_QLM_MODE_PCIE_1X4; /* PEM0 x4 */
+ else
+ return BDK_QLM_MODE_PCIE_1X2; /* PEM0 x2 */
+ }
+ case 1: /* PEM0 second two lanes */
+ return BDK_QLM_MODE_PCIE_1X4; /* PEM0 x4 */
+ case 2: /* Either PEM1 x4 or PEM1 x2 */
+ {
+ BDK_CSR_INIT(pemx_cfg, node, BDK_PEMX_CFG(1));
+ if (pemx_cfg.cn81xx.lanes4)
+ return BDK_QLM_MODE_PCIE_1X4; /* PEM1 x4 */
+ else
+ return BDK_QLM_MODE_PCIE_1X2; /* PEM1 x2 */
+ }
+ case 3: /* Either PEM1 x4 or PEM2 x2 */
+ {
+ /* Can be last 2 lanes of PEM1 */
+ BDK_CSR_INIT(pem1_cfg, node, BDK_PEMX_CFG(1));
+ if (pem1_cfg.cn81xx.lanes4)
+ return BDK_QLM_MODE_PCIE_1X4; /* PEM1 x4 */
+ /* Can be 2 lanes of PEM2 */
+ return BDK_QLM_MODE_PCIE_1X2; /* PEM2 x2 */
+ }
+ default:
+ return BDK_QLM_MODE_DISABLED;
+ }
+ }
+ else if (gserx_cfg.s.bgx)
+ {
+ int bgx;
+ int bgx_index;
+ switch (qlm)
+ {
+ case 0:
+ {
+ bgx = 0;
+ bgx_index = 0;
+ break;
+ }
+ case 1:
+ bgx = 0;
+ bgx_index = 2;
+ break;
+ case 2:
+ {
+ bgx = 1;
+ bgx_index = 0;
+ break;
+ }
+ case 3:
+ bgx = 1;
+ bgx_index = 2;
+ break;
+ default:
+ return BDK_QLM_MODE_DISABLED;
+ }
+ BDK_CSR_INIT(cmrx_config, node, BDK_BGXX_CMRX_CONFIG(bgx, bgx_index));
+ bool is_kr = __bdk_qlm_is_lane_kr(node, qlm, 0);
+ switch (cmrx_config.s.lmac_type)
+ {
+ case BDK_BGX_LMAC_TYPES_E_SGMII:
+ if (cavium_is_altpkg(CAVIUM_CN81XX) && (qlm < 2))
+ return BDK_QLM_MODE_SGMII_1X1;
+ else
+ return BDK_QLM_MODE_SGMII_2X1;
+ case BDK_BGX_LMAC_TYPES_E_XAUI: return BDK_QLM_MODE_XAUI_1X4; /* Doesn't differntiate between XAUI and DXAUI */
+ case BDK_BGX_LMAC_TYPES_E_RXAUI: return BDK_QLM_MODE_RXAUI_1X2;
+ case BDK_BGX_LMAC_TYPES_E_TENG_R:
+ if (is_kr)
+ return (cavium_is_altpkg(CAVIUM_CN81XX) && (qlm < 2)) ? BDK_QLM_MODE_10G_KR_1X1 : BDK_QLM_MODE_10G_KR_2X1;
+ else
+ return (cavium_is_altpkg(CAVIUM_CN81XX) && (qlm < 2)) ? BDK_QLM_MODE_XFI_1X1 : BDK_QLM_MODE_XFI_2X1;
+ case BDK_BGX_LMAC_TYPES_E_FORTYG_R:
+ if (is_kr)
+ return BDK_QLM_MODE_40G_KR4_1X4;
+ else
+ return BDK_QLM_MODE_XLAUI_1X4;
+ case BDK_BGX_LMAC_TYPES_E_QSGMII: return BDK_QLM_MODE_QSGMII_4X1;
+ default: return BDK_QLM_MODE_DISABLED;
+ }
+ }
+ else if (gserx_cfg.s.sata)
+ return BDK_QLM_MODE_SATA_2X1;
+ else
+ return BDK_QLM_MODE_DISABLED;
+}
+
+static int qlm_set_sata(bdk_node_t node, int qlm, bdk_qlm_modes_t mode, int baud_mhz, bdk_qlm_mode_flags_t flags)
+{
+ /* SATA has a fixed mapping for ports on CN81XX */
+ int sata_port;
+ switch (qlm)
+ {
+ case 3: /* SATA 0-1 = DLM3 lanes 0-1 */
+ sata_port = 0;
+ break;
+ default:
+ bdk_error("Attempted to configure SATA on QLM that doesn't support it\n");
+ return -1;
+ }
+ return __bdk_qlm_set_sata_cn8xxx(node, qlm, baud_mhz, sata_port, sata_port + 1);
+}
+
+/**
+ * For chips that don't use pin strapping, this function programs
+ * the QLM to the specified mode
+ *
+ * @param node Node to use in a Numa setup
+ * @param qlm QLM to configure
+ * @param mode Desired mode
+ * @param baud_mhz Desired speed
+ * @param flags Flags to specify mode specific options
+ *
+ * @return Zero on success, negative on failure
+ */
+int bdk_qlm_set_mode(bdk_node_t node, int qlm, bdk_qlm_modes_t mode, int baud_mhz, bdk_qlm_mode_flags_t flags)
+{
+ int lane_mode = 0xf;
+ int lmac_type = -1;
+ int is_pcie = 0;
+ int is_sata = 0;
+ int is_ilk = 0;
+ int is_bgx = 0;
+ int bgx_block;
+ int bgx_index;
+
+ switch (qlm)
+ {
+ case 0:
+ bgx_block = 0;
+ bgx_index = 0;
+ break;
+ case 1:
+ bgx_block = 0;
+ bgx_index = 2;
+ break;
+ case 2:
+ bgx_block = 1;
+ bgx_index = 0;
+ break;
+ case 3:
+ bgx_block = 1;
+ bgx_index = 2;
+ break;
+ default:
+ bgx_block = -1;
+ bgx_index = -1;
+ break;
+ }
+
+ int measured_ref = bdk_qlm_measure_clock(node, qlm);
+ int ref_clk = (mode == BDK_QLM_MODE_DISABLED) ? 0 : __bdk_qlm_round_refclock(node, qlm, measured_ref);
+ int kr_mode = 0;
+
+ switch (mode)
+ {
+ case BDK_QLM_MODE_PCIE_1X1:
+ case BDK_QLM_MODE_PCIE_1X2:
+ case BDK_QLM_MODE_PCIE_1X4:
+ {
+ /* Note: PCIe ignores baud_mhz. Use the GEN 1/2/3 flags
+ to control speed */
+ is_pcie = 1;
+ if (ref_clk == REF_100MHZ)
+ {
+ BDK_CSR_MODIFY(c, node, BDK_GSERX_REFCLK_SEL(qlm),
+ c.s.pcie_refclk125 = 0);
+ if (baud_mhz == 2500)
+ lane_mode = BDK_GSER_LMODE_E_R_25G_REFCLK100;
+ else if (baud_mhz == 5000)
+ lane_mode = BDK_GSER_LMODE_E_R_5G_REFCLK100;
+ else
+ lane_mode = BDK_GSER_LMODE_E_R_8G_REFCLK100;
+ }
+ else if (ref_clk == REF_125MHZ)
+ {
+ BDK_CSR_MODIFY(c, node, BDK_GSERX_REFCLK_SEL(qlm),
+ c.s.pcie_refclk125 = 1);
+ if (baud_mhz == 2500)
+ lane_mode = BDK_GSER_LMODE_E_R_25G_REFCLK125;
+ else if (baud_mhz == 5000)
+ lane_mode = BDK_GSER_LMODE_E_R_5G_REFCLK125;
+ else
+ lane_mode = BDK_GSER_LMODE_E_R_8G_REFCLK125;
+ }
+ else
+ {
+ bdk_error("Invalid reference clock for PCIe on QLM%d\n", qlm);
+ return -1;
+ }
+ int cfg_md;
+ if (baud_mhz == 2500)
+ cfg_md = 0; /* Gen1 Speed */
+ else if (baud_mhz == 5000)
+ cfg_md = 1; /* Gen2 Speed */
+ else
+ cfg_md = 2; /* Gen3 Speed */
+ switch (qlm)
+ {
+ case 0: /* Either PEM0 x4 or PEM0 x2 or PEM0 x1 */
+ BDK_CSR_MODIFY(c, node, BDK_RST_SOFT_PRSTX(0),
+ c.s.soft_prst = !(flags & BDK_QLM_MODE_FLAG_ENDPOINT));
+ __bdk_qlm_setup_pem_reset(node, 0, flags & BDK_QLM_MODE_FLAG_ENDPOINT);
+ BDK_CSR_MODIFY(c, node, BDK_PEMX_CFG(0),
+ c.cn81xx.lanes4 = (mode == BDK_QLM_MODE_PCIE_1X4);
+ //c.cn81xx.hostmd = !(flags & BDK_QLM_MODE_FLAG_ENDPOINT);
+ c.cn81xx.md = cfg_md);
+ break;
+ case 1: /* Second two lanes for PEM0 x4 */
+ /* PEMX_CFG already setup */
+ break;
+ case 2: /* Either PEM1 x4 or PEM1 x2 */
+ BDK_CSR_MODIFY(c, node, BDK_RST_SOFT_PRSTX(1),
+ c.s.soft_prst = !(flags & BDK_QLM_MODE_FLAG_ENDPOINT));
+ __bdk_qlm_setup_pem_reset(node, 1, flags & BDK_QLM_MODE_FLAG_ENDPOINT);
+ BDK_CSR_MODIFY(c, node, BDK_PEMX_CFG(1),
+ c.cn81xx.lanes4 = (mode == BDK_QLM_MODE_PCIE_1X4);
+ //c.cn81xx.hostmd = !(flags & BDK_QLM_MODE_FLAG_ENDPOINT);
+ c.cn81xx.md = cfg_md);
+ break;
+ case 3: /* Either PEM1 x4 or PEM2 x2 */
+ if (mode == BDK_QLM_MODE_PCIE_1X4)
+ {
+ /* Last 2 lanes of PEM1 */
+ /* PEMX_CFG already setup */
+ }
+ else
+ {
+ /* Two lanes for PEM2 */
+ BDK_CSR_MODIFY(c, node, BDK_RST_SOFT_PRSTX(2),
+ c.s.soft_prst = !(flags & BDK_QLM_MODE_FLAG_ENDPOINT));
+ __bdk_qlm_setup_pem_reset(node, 2, flags & BDK_QLM_MODE_FLAG_ENDPOINT);
+ BDK_CSR_MODIFY(c, node, BDK_PEMX_CFG(2),
+ c.cn81xx.lanes4 = 0;
+ //c.cn81xx.hostmd = !(flags & BDK_QLM_MODE_FLAG_ENDPOINT);
+ c.cn81xx.md = cfg_md);
+ }
+ break;
+ default:
+ return -1;
+ }
+ break;
+ }
+ case BDK_QLM_MODE_SGMII_4X1:
+ case BDK_QLM_MODE_SGMII_2X1:
+ case BDK_QLM_MODE_SGMII_1X1:
+ /* Disable port BGX ports 2-3 on CN80XX */
+ if ((qlm < 2) && cavium_is_altpkg(CAVIUM_CN81XX))
+ {
+ BDK_CSR_WRITE(node, BDK_BGXX_CMRX_RX_DMAC_CTL(0, 2), 0);
+ BDK_CSR_WRITE(node, BDK_BGXX_CMRX_RX_DMAC_CTL(0, 3), 0);
+ }
+ lmac_type = BDK_BGX_LMAC_TYPES_E_SGMII; /* SGMII */
+ is_bgx = 1;
+ lane_mode = __bdk_qlm_get_lane_mode_for_speed_and_ref_clk("SGMII", qlm, ref_clk, baud_mhz);
+ if (lane_mode == -1)
+ return -1;
+ break;
+ case BDK_QLM_MODE_XAUI_1X4:
+ lmac_type = BDK_BGX_LMAC_TYPES_E_XAUI; /* XAUI */
+ is_bgx = 5;
+ lane_mode = __bdk_qlm_get_lane_mode_for_speed_and_ref_clk("XAUI", qlm, ref_clk, baud_mhz);
+ if (lane_mode == -1)
+ return -1;
+ break;
+ case BDK_QLM_MODE_RXAUI_2X2:
+ case BDK_QLM_MODE_RXAUI_1X2:
+ lmac_type = BDK_BGX_LMAC_TYPES_E_RXAUI; /* RXAUI */
+ is_bgx = 3;
+ lane_mode = __bdk_qlm_get_lane_mode_for_speed_and_ref_clk("RXAUI", qlm, ref_clk, baud_mhz);
+ if (lane_mode == -1)
+ return -1;
+ break;
+ case BDK_QLM_MODE_XFI_4X1:
+ case BDK_QLM_MODE_XFI_2X1:
+ case BDK_QLM_MODE_XFI_1X1:
+ /* Disable port BGX ports 2-3 on CN80XX */
+ if ((qlm < 2) && cavium_is_altpkg(CAVIUM_CN81XX))
+ {
+ BDK_CSR_WRITE(node, BDK_BGXX_CMRX_RX_DMAC_CTL(0, 2), 0);
+ BDK_CSR_WRITE(node, BDK_BGXX_CMRX_RX_DMAC_CTL(0, 3), 0);
+ }
+ lmac_type = BDK_BGX_LMAC_TYPES_E_TENG_R; /* 10G_R */
+ is_bgx = 1;
+ lane_mode = __bdk_qlm_get_lane_mode_for_speed_and_ref_clk("XFI", qlm, ref_clk, baud_mhz);
+ if (lane_mode == -1)
+ return -1;
+ break;
+ case BDK_QLM_MODE_XLAUI_1X4:
+ lmac_type = BDK_BGX_LMAC_TYPES_E_FORTYG_R; /* 40G_R */
+ is_bgx = 5;
+ lane_mode = __bdk_qlm_get_lane_mode_for_speed_and_ref_clk("XLAUI", qlm, ref_clk, baud_mhz);
+ if (lane_mode == -1)
+ return -1;
+ break;
+ case BDK_QLM_MODE_10G_KR_4X1:
+ case BDK_QLM_MODE_10G_KR_2X1:
+ case BDK_QLM_MODE_10G_KR_1X1:
+ /* Disable port BGX ports 2-3 on CN80XX */
+ if ((qlm < 2) && cavium_is_altpkg(CAVIUM_CN81XX))
+ {
+ BDK_CSR_WRITE(node, BDK_BGXX_CMRX_RX_DMAC_CTL(0, 2), 0);
+ BDK_CSR_WRITE(node, BDK_BGXX_CMRX_RX_DMAC_CTL(0, 3), 0);
+ }
+ lmac_type = BDK_BGX_LMAC_TYPES_E_TENG_R; /* 10G_R */
+ is_bgx = 1;
+ lane_mode = __bdk_qlm_get_lane_mode_for_speed_and_ref_clk("10G-KR", qlm, ref_clk, baud_mhz);
+ if (lane_mode == -1)
+ return -1;
+ kr_mode = 1;
+ break;
+ case BDK_QLM_MODE_40G_KR4_1X4:
+ lmac_type = BDK_BGX_LMAC_TYPES_E_FORTYG_R; /* 40G_R */
+ is_bgx = 5;
+ lane_mode = __bdk_qlm_get_lane_mode_for_speed_and_ref_clk("40G-KR", qlm, ref_clk, baud_mhz);
+ if (lane_mode == -1)
+ return -1;
+ kr_mode = 1;
+ break;
+ case BDK_QLM_MODE_QSGMII_4X1:
+ lmac_type = BDK_BGX_LMAC_TYPES_E_QSGMII; /* QSGMII */
+ is_bgx = 1;
+ lane_mode = BDK_GSER_LMODE_E_R_5G_REFCLK15625_QSGMII;
+ break;
+ case BDK_QLM_MODE_SATA_2X1:
+ BDK_CSR_MODIFY(c, node, BDK_GSERX_LANE_MODE(qlm), c.s.lmode = BDK_GSER_LMODE_E_R_8G_REFCLK100);
+ /* SATA initialization is different than BGX. Call its init function
+ and skip the rest of this routine */
+ return qlm_set_sata(node, qlm, mode, baud_mhz, flags);
+ case BDK_QLM_MODE_DISABLED:
+ /* Set gser for the interface mode */
+ BDK_CSR_MODIFY(c, node, BDK_GSERX_CFG(qlm),
+ c.u = 0);
+ /* Put the PHY in reset */
+ BDK_CSR_MODIFY(c, node, BDK_GSERX_PHY_CTL(qlm),
+ c.s.phy_reset = 1);
+ return 0;
+ default:
+ bdk_error("Unsupported QLM mode %d\n", mode);
+ return -1;
+ }
+
+ BDK_TRACE(QLM, "N%u.QLM%u: Power up...\n", node, qlm);
+
+ /* Power up phy, but keep it in reset */
+ BDK_CSR_MODIFY(c, node, BDK_GSERX_PHY_CTL(qlm),
+ c.s.phy_pd = 0;
+ c.s.phy_reset = 1);
+
+ /* Set gser for the interface mode */
+ BDK_CSR_MODIFY(c, node, BDK_GSERX_CFG(qlm),
+ c.s.sata = is_sata;
+ c.s.ila = is_ilk;
+ c.s.bgx = is_bgx & 1;
+ c.s.bgx_quad = (is_bgx >> 2) & 1;
+ c.s.bgx_dual = (is_bgx >> 1) & 1;
+ c.s.pcie = is_pcie);
+
+ /* Lane mode */
+ BDK_CSR_MODIFY(c, node, BDK_GSERX_LANE_MODE(qlm),
+ c.s.lmode = lane_mode);
+
+ /* LMAC type. We only program one port as the full setup is done in BGX */
+ if (lmac_type != -1)
+ {
+ BDK_CSR_MODIFY(c, node, BDK_BGXX_CMRX_CONFIG(bgx_block, bgx_index),
+ c.s.enable = 0;
+ c.s.lmac_type = lmac_type);
+ }
+
+ BDK_TRACE(QLM, "N%u.QLM%u: Deassert reset...\n", node, qlm);
+
+ /* Bring phy out of reset */
+ BDK_CSR_MODIFY(c, node, BDK_GSERX_PHY_CTL(qlm),
+ c.s.phy_reset = 0);
+
+ /* Wait 1us until the management interface is ready to accept
+ read/write commands.*/
+ bdk_wait_usec(1);
+
+ /* Configure the gser pll */
+ __bdk_qlm_init_mode_table(node, qlm, ref_clk);
+
+ /* Remember which lanes are using KR over BGX */
+ if (is_bgx)
+ {
+ int num_lanes = bdk_qlm_get_lanes(node, qlm);
+ for (int lane = 0; lane < num_lanes; lane++)
+ __bdk_qlm_set_lane_kr(node, qlm, lane, kr_mode);
+ }
+
+ /* Wait for reset to complete and the PLL to lock */
+ if (BDK_CSR_WAIT_FOR_FIELD(node, BDK_GSERX_PLL_STAT(qlm), pll_lock, ==, 1, 10000))
+ {
+ bdk_error("QLM%d: Timeout waiting for GSERX_PLL_STAT[pll_lock]\n", qlm);
+ return -1;
+ }
+
+ /* PCIe mode doesn't become ready until the PEM block attempts to bring
+ the interface up. Skip this check for PCIe */
+ if (!is_pcie && BDK_CSR_WAIT_FOR_FIELD(node, BDK_GSERX_QLM_STAT(qlm), rst_rdy, ==, 1, 10000))
+ {
+ bdk_error("QLM%d: Timeout waiting for GSERX_QLM_STAT[rst_rdy]\n", qlm);
+ return -1;
+ }
+
+ /* cdrlock will be checked in the BGX */
+
+ /* Errata (GSER-27140) SERDES temperature drift sensitivity in receiver */
+ int channel_loss = bdk_config_get_int(BDK_CONFIG_QLM_CHANNEL_LOSS, node, qlm);
+ __bdk_qlm_errata_gser_27140(node, qlm, baud_mhz, channel_loss);
+
+ /* Apply any custom tuning */
+ __bdk_qlm_tune(node, qlm, mode, baud_mhz);
+
+ /* Some modes require 4 lanes, which spans DLMs. For these modes, we need
+ to setup the second DLM at the same time we setup the first. The second
+ DLM also must use the same reference clock as the first */
+ bool paired_dlm = ((qlm & 1) == 0) && /* We're on the first (even) DLM */
+ ((mode == BDK_QLM_MODE_PCIE_1X4) || /* We're using a 4 lane mode */
+ (mode == BDK_QLM_MODE_XAUI_1X4) ||
+ (mode == BDK_QLM_MODE_XLAUI_1X4) ||
+ (mode == BDK_QLM_MODE_40G_KR4_1X4));
+ if (paired_dlm)
+ {
+ /* Use the same reference clock for the second QLM */
+ BDK_CSR_WRITE(node, BDK_GSERX_REFCLK_SEL(qlm + 1),
+ BDK_CSR_READ(node, BDK_GSERX_REFCLK_SEL(qlm)));
+ return bdk_qlm_set_mode(node, qlm + 1, mode, baud_mhz, flags);
+ }
+
+ return 0;
+}
+
+/**
+ * Get the speed (Gbaud) of the QLM in Mhz.
+ *
+ * @param qlm QLM to examine
+ *
+ * @return Speed in Mhz
+ */
+int bdk_qlm_get_gbaud_mhz(bdk_node_t node, int qlm)
+{
+ BDK_CSR_INIT(gserx_cfg, node, BDK_GSERX_CFG(qlm));
+ if (gserx_cfg.u == 0)
+ return 0;
+ if (gserx_cfg.s.pcie)
+ {
+ /* QLMs in PCIe mode ignore LMODE and get their speed from
+ the PEM block that controls them */
+ int pem;
+ switch (qlm)
+ {
+ case 0: /* PEM0 */
+ case 1: /* PEM0 */
+ pem = 0;
+ break;
+ case 2: /* PEM1 */
+ pem = 1;
+ break;
+ case 3: /* PEM1 or PEM2 */
+ {
+ BDK_CSR_INIT(pemx_cfg, node, BDK_PEMX_CFG(1));
+ if (pemx_cfg.cn81xx.lanes4)
+ pem = 1;
+ else
+ pem = 2;
+ break;
+ }
+ default:
+ bdk_fatal("QLM%d: In PCIe mode, which shouldn't happen\n", qlm);
+ }
+ return __bdk_qlm_get_gbaud_mhz_pem(node, pem);
+ }
+ else if (gserx_cfg.s.sata)
+ {
+ int sata;
+ switch (qlm)
+ {
+ case 3:
+ sata = 0;
+ break;
+ default:
+ return 0;
+ }
+ BDK_CSR_INIT(sata_uctl_ctl, node, BDK_SATAX_UCTL_CTL(sata));
+ if (!sata_uctl_ctl.s.a_clk_en)
+ return 0;
+ BDK_CSR_INIT(sctl, node, BDK_SATAX_UAHC_P0_SCTL(sata));
+ switch (sctl.s.spd)
+ {
+ case 1: return 1500;
+ case 2: return 3000;
+ case 3: return 6000;
+ default: return 6000; /* No limit, assume 6G */
+ }
+ }
+ else
+ return __bdk_qlm_get_gbaud_mhz_lmode(node, qlm);
+}
+
+/**
+ * Initialize the QLM layer
+ */
+void bdk_qlm_init(bdk_node_t node)
+{
+ /* Setup how each PEM drives the PERST lines */
+ for (int pem = 0; pem < 3; pem++)
+ {
+ BDK_CSR_INIT(rst_ctlx, node, BDK_RST_CTLX(pem));
+ __bdk_qlm_setup_pem_reset(node, pem, !rst_ctlx.s.host_mode);
+ }
+}
+
+static void __bdk_qlm_sff81xx_set_reference(bdk_node_t node, int qlm, int ref_clk)
+{
+ int use_clock;
+
+ if (CAVIUM_IS_MODEL(CAVIUM_CN88XX) || CAVIUM_IS_MODEL(CAVIUM_CN83XX) || CAVIUM_IS_MODEL(CAVIUM_CN81XX))
+ {
+ // Common clock 0 is 156MHz
+ // Common clock 1 is 100MHz
+ switch (qlm)
+ {
+ case 0:
+ use_clock = 1; /* DLMC_REF_CLK1 of 100MHz */
+ break;
+ case 1:
+ if (ref_clk == REF_100MHZ)
+ use_clock = 1; /* DLMC_REF_CLK1 of 100MHz */
+ else
+ use_clock = 2; /* DLM1_REF_CLK of 156MHz */
+ break;
+ case 2:
+ case 3:
+ default:
+ if (ref_clk == REF_100MHZ)
+ use_clock = 1; /* DLMC_REF_CLK1 of 100MHz */
+ else
+ use_clock = 2; /* DLM1_REF_CLK of 156MHz */
+ break;
+ }
+
+ BDK_TRACE(QLM, "Setting N%d.QLM%d to use ref clock %d\n", node, qlm, use_clock);
+ }
+ else
+ {
+ bdk_error("Update %s for qlm auto config of this chip\n",__FUNCTION__);
+ return;
+ }
+ BDK_CSR_MODIFY(c, node, BDK_GSERX_REFCLK_SEL(qlm),
+ c.s.com_clk_sel = (use_clock != 2);
+ c.s.use_com1 = (use_clock == 1));
+}
+
+int bdk_qlm_auto_config(bdk_node_t node)
+{
+ return -1;
+}
+
+/**
+ * For Cavium SFF board, query the DIP switches in GPIO o determine the QLM setup.
+ * Configure the GPIOs to read the DLM settings
+ * SW1.1 -> DLM0_SEL -> GPIO_26
+ * SW1.2 -> DLM1_SEL -> GPIO_25
+ * SW1.3 -> DLM2_SEL -> GPIO_31
+ * SW1.4 -> DLM3_SEL -> GPIO_4
+ *V1.x boards SW3.8 -> QSGMII/XFI SEL ->GPIO_9
+ *V2.x boards SW3.7 -> QSGMII/XFI SEL ->GPIO_36
+*/
+int bdk_qlm_dip_auto_config(bdk_node_t node)
+{
+ bdk_qlm_modes_t dlm_mode[4];
+ int dlm_speed = 0;
+ int use_ref = 0;
+ bdk_qlm_mode_flags_t dlm_flags = 0;
+
+ unsigned int dlm_config, dlm3, dlm2, dlm1, dlm0;
+ uint64_t gpio = 0;
+
+ /* Configure the GPIOs to read the DLM settings */
+ /* SW1.1 -> DLM0_SEL -> GPIO_26 */
+ /* SW1.2 -> DLM1_SEL -> GPIO_25 */
+ /* SW1.3 -> DLM2_SEL -> GPIO_31 */
+ /* SW1.4 -> DLM3_SEL -> GPIO_4 */
+ //V1.x boards /* SW3.8 -> QSGMII/XFI SEL ->GPIO_9 */
+ //V2.x boards /* SW3.7 -> QSGMII/XFI SEL ->GPIO_36 */
+ /* Configure the GPIOs are input */
+ bdk_gpio_initialize(node, 26, 0, 0);
+ bdk_gpio_initialize(node, 25, 0, 0);
+ bdk_gpio_initialize(node, 31, 0, 0);
+ bdk_gpio_initialize(node, 4, 0, 0);
+ bdk_gpio_initialize(node, 36, 0, 0);
+
+
+ /* Read the GPIOs */
+ gpio = bdk_gpio_read(node, 0);
+
+ dlm3 = !!(gpio & (1ULL<<4));
+ dlm2 = !!(gpio & (1ULL<<31));
+ dlm1 = !!(gpio & (1ULL<<25));
+ dlm0 = !!(gpio & (1ULL<<26));
+
+
+ dlm_config = (dlm0<<3)| (dlm1<<2) | (dlm2<<1) | (dlm3);
+
+ BDK_TRACE(QLM, "DLM CONFIG:%d gpio36: %d\n", dlm_config, !!(gpio & (1ULL<<36)));
+
+ switch(dlm_config)
+ {
+ case 0:
+ dlm_mode[0] = BDK_QLM_MODE_PCIE_1X2;
+ dlm_mode[1] = BDK_QLM_MODE_DISABLED;
+ dlm_mode[2] = BDK_QLM_MODE_PCIE_1X2;
+ dlm_mode[3] = BDK_QLM_MODE_PCIE_1X2;
+ break;
+ case 1:
+ dlm_mode[0] = BDK_QLM_MODE_PCIE_1X2;
+ dlm_mode[1] = BDK_QLM_MODE_DISABLED;
+ dlm_mode[2] = BDK_QLM_MODE_PCIE_1X2;
+ dlm_mode[3] = BDK_QLM_MODE_SATA_2X1;
+ break;
+ case 2:
+ dlm_mode[0] = BDK_QLM_MODE_PCIE_1X2;
+ dlm_mode[1] = BDK_QLM_MODE_DISABLED;
+ dlm_mode[2] = BDK_QLM_MODE_XFI_2X1;
+ dlm_mode[3] = BDK_QLM_MODE_PCIE_1X2;
+ break;
+ case 3:
+ dlm_mode[0] = BDK_QLM_MODE_PCIE_1X2;
+ dlm_mode[1] = BDK_QLM_MODE_DISABLED;
+ dlm_mode[2] = BDK_QLM_MODE_XFI_2X1;
+ dlm_mode[3] = BDK_QLM_MODE_SATA_2X1;
+ break;
+ case 4:
+ dlm_mode[0] = BDK_QLM_MODE_PCIE_1X2;
+ dlm_mode[1] = (!!(gpio & (1ULL<<36)) ? BDK_QLM_MODE_XFI_1X1 : BDK_QLM_MODE_QSGMII_4X1);
+ dlm_mode[2] = BDK_QLM_MODE_PCIE_1X2;
+ dlm_mode[3] = BDK_QLM_MODE_PCIE_1X2;
+ break;
+ case 5:
+ dlm_mode[0] = BDK_QLM_MODE_PCIE_1X2;
+ dlm_mode[1] = (!!(gpio & (1ULL<<36)) ? BDK_QLM_MODE_XFI_1X1 : BDK_QLM_MODE_QSGMII_4X1);
+ dlm_mode[2] = BDK_QLM_MODE_PCIE_1X2;
+ dlm_mode[3] = BDK_QLM_MODE_SATA_2X1;
+ break;
+ case 6:
+ dlm_mode[0] = BDK_QLM_MODE_PCIE_1X2;
+ dlm_mode[1] = (!!(gpio & (1ULL<<36)) ? BDK_QLM_MODE_XFI_1X1 : BDK_QLM_MODE_QSGMII_4X1);
+ dlm_mode[2] = BDK_QLM_MODE_XFI_2X1;
+ dlm_mode[3] = BDK_QLM_MODE_PCIE_1X2;
+ break;
+ case 7:
+ dlm_mode[0] = BDK_QLM_MODE_PCIE_1X2;
+ dlm_mode[1] = (!!(gpio & (1ULL<<36)) ? BDK_QLM_MODE_XFI_1X1 : BDK_QLM_MODE_QSGMII_4X1);
+ dlm_mode[2] = BDK_QLM_MODE_XFI_2X1;
+ dlm_mode[3] = BDK_QLM_MODE_SATA_2X1;
+ break;
+ case 8:
+ dlm_mode[0] = BDK_QLM_MODE_PCIE_1X4;
+ dlm_mode[1] = BDK_QLM_MODE_PCIE_1X4;
+ dlm_mode[2] = BDK_QLM_MODE_PCIE_1X2;
+ dlm_mode[3] = BDK_QLM_MODE_PCIE_1X2;
+ break;
+ case 9:
+ dlm_mode[0] = BDK_QLM_MODE_PCIE_1X4;
+ dlm_mode[1] = BDK_QLM_MODE_PCIE_1X4;
+ dlm_mode[2] = BDK_QLM_MODE_PCIE_1X2;
+ dlm_mode[3] = BDK_QLM_MODE_SATA_2X1;
+ break;
+ case 10:
+ dlm_mode[0] = BDK_QLM_MODE_PCIE_1X4;
+ dlm_mode[1] = BDK_QLM_MODE_PCIE_1X4;
+ dlm_mode[2] = BDK_QLM_MODE_XFI_2X1;
+ dlm_mode[3] = BDK_QLM_MODE_PCIE_1X2;
+ break;
+ case 11:
+ dlm_mode[0] = BDK_QLM_MODE_PCIE_1X4;
+ dlm_mode[1] = BDK_QLM_MODE_PCIE_1X4;
+ dlm_mode[2] = BDK_QLM_MODE_XFI_2X1;
+ dlm_mode[3] = BDK_QLM_MODE_SATA_2X1;
+ break;
+ case 12:
+ dlm_mode[0] = BDK_QLM_MODE_PCIE_1X2;
+ dlm_mode[1] = (!!(gpio & (1ULL<<36)) ? BDK_QLM_MODE_XFI_1X1 : BDK_QLM_MODE_QSGMII_4X1);
+ dlm_mode[2] = BDK_QLM_MODE_PCIE_1X2;
+ dlm_mode[3] = BDK_QLM_MODE_PCIE_1X2;
+ break;
+ case 13:
+ dlm_mode[0] = BDK_QLM_MODE_PCIE_1X2;
+ dlm_mode[1] = (!!(gpio & (1ULL<<36)) ? BDK_QLM_MODE_XFI_1X1 : BDK_QLM_MODE_QSGMII_4X1);
+ dlm_mode[2] = BDK_QLM_MODE_PCIE_1X2;
+ dlm_mode[3] = BDK_QLM_MODE_SATA_2X1;
+ break;
+ case 14:
+ dlm_mode[0] = BDK_QLM_MODE_PCIE_1X2;
+ dlm_mode[1] = (!!(gpio & (1ULL<<36)) ? BDK_QLM_MODE_XFI_1X1 : BDK_QLM_MODE_QSGMII_4X1);
+ dlm_mode[2] = BDK_QLM_MODE_XFI_2X1;
+ dlm_mode[3] = BDK_QLM_MODE_PCIE_1X2;
+ break;
+ case 15:
+ dlm_mode[0] = BDK_QLM_MODE_PCIE_1X2;
+ dlm_mode[1] = (!!(gpio & (1ULL<<36)) ? BDK_QLM_MODE_XFI_1X1 : BDK_QLM_MODE_QSGMII_4X1);
+ dlm_mode[2] = BDK_QLM_MODE_XFI_2X1;
+ dlm_mode[3] = BDK_QLM_MODE_SATA_2X1;
+ break;
+ default:
+ return -1;
+ }
+
+ for(int dlm = 0; dlm < 4; dlm++)
+ {
+ const char *dlm_mode_str = bdk_qlm_mode_tostring(dlm_mode[dlm]);
+ switch(dlm_mode[dlm])
+ {
+ case BDK_QLM_MODE_DISABLED:
+ break;
+ case BDK_QLM_MODE_XFI_2X1:
+ case BDK_QLM_MODE_XFI_1X1:
+ use_ref = REF_156MHZ;
+ dlm_speed = 10312;
+ break;
+ case BDK_QLM_MODE_SATA_2X1:
+ dlm_speed = 6000;
+ use_ref = REF_100MHZ;
+ break;
+ case BDK_QLM_MODE_PCIE_1X2:
+ case BDK_QLM_MODE_PCIE_1X4:
+ dlm_speed = 8000;
+ use_ref =REF_100MHZ;
+ break;
+ case BDK_QLM_MODE_QSGMII_4X1:
+ use_ref = REF_100MHZ;
+ dlm_speed = 5000;
+ break;
+ default:
+ bdk_error("Unsupported N%d.QLM%d mode: %s(%d)",
+ node, dlm,
+ dlm_mode_str ? dlm_mode_str : "???",
+ dlm_mode[dlm]);
+ return -1;
+ }
+ if ((1 == dlm) && (dlm_mode[dlm] != BDK_QLM_MODE_QSGMII_4X1) && (dlm_mode[dlm] != BDK_QLM_MODE_DISABLED))
+ {
+ /* This code is specific to sff8104 board
+ ** QSGMII phy is wired to dlm1-gser lane 2
+ ** AQR-107 phy is wired to dlm1-gser lane 3
+ ** bdk always uses bgx0.port0 on that board
+ */
+ // If dlm1 is in XFI mode, change PHY address to mdio of aquantia phy
+ unsigned mdio_bus = 1;
+ unsigned mdio_addr = 0;
+ int phy_cfg = 0xff<<24 | ((mdio_bus& 0xf)<<8) | (mdio_addr & 0xff);
+ bdk_config_set_int((uint32_t) phy_cfg,BDK_CONFIG_PHY_ADDRESS, node, 0, 0);
+ /* Indicate serdes lane 3 , aquantia phy active */
+ int aq_phy = (0x3<<8) | 1;
+ bdk_config_set_int(aq_phy, BDK_CONFIG_AQUANTIA_PHY,node,0,0);
+ BDK_TRACE(QLM,"Disabling phys 0.1,0.2,0.3\n");
+ for (int i = 1; i<4; i++) {
+ bdk_config_set_int(-1,BDK_CONFIG_PHY_ADDRESS, node, 0, i);
+ bdk_config_set_int(0,BDK_CONFIG_BGX_ENABLE,node,0,i);
+ }
+ }
+
+ BDK_TRACE(QLM, "Setting N%d.QLM%d mode %s(%d), speed %d, flags 0x%x\n",
+ node, dlm, dlm_mode_str, dlm_mode[dlm], dlm_speed, dlm_flags);
+
+ /* Set the reference clock for this QLM */
+ __bdk_qlm_sff81xx_set_reference(node, dlm, use_ref);
+
+ if (bdk_qlm_set_mode(node, dlm, dlm_mode[dlm], dlm_speed, dlm_flags))
+ return -1;
+ }
+ return 0;
+}
diff --git a/src/vendorcode/cavium/bdk/libbdk-hal/qlm/bdk-qlm-common-sata.c b/src/vendorcode/cavium/bdk/libbdk-hal/qlm/bdk-qlm-common-sata.c
new file mode 100644
index 0000000000..9e31ad1dce
--- /dev/null
+++ b/src/vendorcode/cavium/bdk/libbdk-hal/qlm/bdk-qlm-common-sata.c
@@ -0,0 +1,625 @@
+/***********************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-hal/if/bdk-if.h"
+#include "libbdk-hal/bdk-qlm.h"
+#include "libbdk-hal/qlm/bdk-qlm-common.h"
+#include "libbdk-arch/bdk-csrs-gser.h"
+#include "libbdk-arch/bdk-csrs-sata.h"
+
+/**
+ * Initialize a DLM/QLM for use with SATA controllers
+ *
+ * @param node Node to intialize
+ * @param qlm Which DLM/QLM to init
+ * @param baud_mhz QLM speed in Gbaud
+ * @param sata_first First SATA controller connected to this DLM/QLM
+ * @param sata_last Last SATA controller connected to this DLM/QLM (inclusive)
+ *
+ * @return Zero on success, negative on failure
+ */
+int __bdk_qlm_set_sata_cn8xxx(bdk_node_t node, int qlm, int baud_mhz, int sata_first, int sata_last)
+{
+ const int NUM_LANES = sata_last - sata_first + 1;
+ const int MAX_A_CLK = 333000000; /* Max of 333Mhz */
+
+ /* 26.4.1 Cold Reset */
+ /* 1. Ensure that the SerDes reference clock is up and stable. */
+ /* Already done */
+
+ /* 2. Optionally program the GPIO CSRs for SATA features.
+ a. For cold-presence detect, select a GPIO for the input and program GPI-
+ O_BIT_CFG(0..50)[PIN_SEL] = GPIO_PIN_SEL_E::SATA(0..15)_CP_DET.
+ b. For mechanical-presence detect, select a GPIO for the input and program
+ GPIO_BIT_CFG(0..50)[PIN_SEL] = GPI-
+ O_PIN_SEL_E::SATA(0..15)_MP_SWITCH.
+ c. For BIST board-test loopback, select a GPIO for the input and program GPI-
+ O_BIT_CFG(0..50)[PIN_SEL] = GPIO_PIN_SEL_E:::SATA_LAB_LB.
+ d. For LED activity, select a GPIO for the output and program GPI-
+ O_BIT_CFG(0..50)[PIN_SEL] = GPIO_PIN_SEL_E:::SATA(0..15)_ACT_LED.
+ e. For cold-presence power-on-device, select a GPIO for the output and program
+ GPIO_BIT_CFG(0..50)[PIN_SEL] = GPIO_PIN_SEL_E:::SATA(0..15)_CP_-
+ POD. */
+ /* Skipping */
+
+ /* 3. Optionally program the SGPIO unit. */
+ /* Skipping */
+
+ /* 4. Assert all resets:
+ a. UAHC reset: SATA(0..15)_UCTL_CTL[SATA_UAHC_RST] = 1
+ b. UCTL reset: SATA(0..15)_UCTL_CTL[SATA_UCTL_RST] = 1 */
+ for (int p = sata_first; p <= sata_last; p++)
+ {
+ BDK_CSR_MODIFY(c, node, BDK_SATAX_UCTL_CTL(p),
+ c.s.sata_uahc_rst = 1;
+ c.s.sata_uctl_rst = 1);
+ }
+
+ /* 5. Configure the ACLK:
+ a. Reset the clock dividers: SATA(0..15)_UCTL_CTL[A_CLKDIV_RST] = 1.
+ b. Select the ACLK frequency (refer to maximum values in Table 26 1).
+ i. SATA(0..15)_UCTL_CTL[A_CLKDIV_SEL] = desired value,
+ ii. SATA(0..15)_UCTL_CTL[A_CLK_EN] = 1 to enable the ACLK.
+ c. Deassert the ACLK clock divider reset:
+ SATA(0..15)_UCTL_CTL[A_CLKDIV_RST] = 0. */
+ int divisor = (bdk_clock_get_rate(node, BDK_CLOCK_SCLK) + MAX_A_CLK - 1) / MAX_A_CLK;
+ int a_clkdiv;
+ /* This screwy if logic is from the description of
+ SATAX_UCTL_CTL[a_clkdiv_sel] in the CSR */
+ if (divisor <= 4)
+ {
+ a_clkdiv = divisor - 1;
+ /* Divisor matches calculated value */
+ }
+ else if (divisor <= 6)
+ {
+ a_clkdiv = 4;
+ divisor = 6;
+ }
+ else if (divisor <= 8)
+ {
+ a_clkdiv = 5;
+ divisor = 8;
+ }
+ else if (divisor <= 16)
+ {
+ a_clkdiv = 6;
+ divisor = 16;
+ }
+ else if (divisor <= 24)
+ {
+ a_clkdiv = 7;
+ divisor = 24;
+ }
+ else
+ {
+ bdk_error("Unable to determine SATA clock divisor\n");
+ return -1;
+ }
+ /* Calculate the final clock rate */
+ int a_clk = bdk_clock_get_rate(node, BDK_CLOCK_SCLK) / divisor;
+
+ for (int p = sata_first; p <= sata_last; p++)
+ {
+ BDK_CSR_MODIFY(c, node, BDK_SATAX_UCTL_CTL(p),
+ c.s.a_clkdiv_rst = 1);
+ BDK_CSR_MODIFY(c, node, BDK_SATAX_UCTL_CTL(p),
+ c.s.a_clk_byp_sel = 0;
+ c.s.a_clkdiv_sel = a_clkdiv;
+ c.s.a_clk_en = 1);
+ BDK_CSR_MODIFY(c, node, BDK_SATAX_UCTL_CTL(p),
+ c.s.a_clkdiv_rst = 0);
+ }
+ bdk_wait_usec(1);
+
+ /* 8. Configure PHY for SATA. Refer to Section 21.1.2. */
+ /* Done below, section 24.1.2.3 */
+
+ /* 9. TBD: Poll QLM2_MPLL_STATUS for MPLL lock */
+ /* Not needed */
+
+ /* 10. Initialize UAHC as described in the AHCI specification
+ (UAHC_* registers). */
+ /* Done when a SATA driver is initialized */
+
+ /* 24.1.2.3 SATA Configuration
+ Software must perform the following steps to configure the GSER_WEST
+ for a SATA application. Note that the GSERW steps are on a QLM basis. */
+
+ /* 1. Configure the SATA controller (refer to Chapter 26). */
+ /* This is the code above */
+
+ /* 2. Configure the QLM Reference clock.
+ Set GSER(0..13)_REFCLK_SEL[COM_CLK_SEL] = 1 to source the reference
+ clock from the external clock multiplexer.
+ Configure GSER(0..13)_REFCLK_SEL[USE_COM1]:
+ 0 = use QLMC_REF_CLK0_P/N
+ 1 = use QLMC_REF_CLK1_P/N */
+ /* Already done */
+
+ /* Make sure the PHY is in reset before we reconfig */
+ BDK_CSR_MODIFY(c, node, BDK_GSERX_PHY_CTL(qlm),
+ c.s.phy_reset = 1);
+ bdk_wait_usec(1);
+
+ /* 3. Configure the QLM for SATA mode: set GSER(0..13)_CFG[SATA] = 1. */
+ BDK_CSR_MODIFY(c, node, BDK_GSERX_CFG(qlm),
+ c.u = 0;
+ c.s.sata = 1);
+
+ /* 9. Clear the appropriate lane resets:
+ GSER(0..13)_SATA_LANE_RST[Ln_RST] = 0, where n is the lane number 0-3. */
+ BDK_CSR_WRITE(node, BDK_GSERX_SATA_LANE_RST(qlm), 0);
+ BDK_CSR_READ(node, BDK_GSERX_SATA_LANE_RST(qlm));
+
+ /* We'll check for the SATA_PCS Ready in step 8a below */
+ /* Short 1 usec wait */
+ bdk_wait_usec(1);
+
+ /* 4. Take the PHY out of reset: write GSER(0..13)_PHY_CTL[PHY_RESET] = 0. */
+ BDK_CSR_MODIFY(c, node, BDK_GSERX_PHY_CTL(qlm),
+ c.s.phy_reset = 0);
+
+ /* 4a. Poll for PHY RST_RDY indicating the PHY has initialized before
+ trying to access internal registers to reconfigure for SATA */
+ /* 8. Wait for GSER(0..13)_QLM_STAT[RST_RDY] = 1, indicating that the PHY
+ has been reconfigured and PLLs are locked. */
+ if (BDK_CSR_WAIT_FOR_FIELD(node, BDK_GSERX_QLM_STAT(qlm), rst_rdy, ==, 1, 10000))
+ {
+ bdk_error("QLM%d: Timeout waiting for GSERX_QLM_STAT[rst_rdy]\n", qlm);
+ return -1;
+ }
+
+ /* Workaround for errata GSER-30310: SATA HDD Not Ready due to
+ PHY SDLL/LDLL lockup at 3GHz */
+ for (int slice = 0; slice < NUM_LANES / 2; slice++)
+ {
+ BDK_CSR_MODIFY(c, node, BDK_GSERX_SLICEX_PCIE1_MODE(qlm, slice),
+ c.s.rx_pi_bwsel = 1;
+ c.s.rx_ldll_bwsel = 1;
+ c.s.rx_sdll_bwsel = 1);
+ BDK_CSR_MODIFY(c, node, BDK_GSERX_SLICEX_PCIE2_MODE(qlm, slice),
+ c.s.rx_pi_bwsel = 1;
+ c.s.rx_ldll_bwsel = 1;
+ c.s.rx_sdll_bwsel = 1);
+ BDK_CSR_MODIFY(c, node, BDK_GSERX_SLICEX_PCIE3_MODE(qlm, slice),
+ c.s.rx_pi_bwsel = 1;
+ c.s.rx_ldll_bwsel = 1;
+ c.s.rx_sdll_bwsel = 1);
+ }
+
+ /* 5. Change the P2 termination
+ GSERn_RX_PWR_CTRL_P2[P2_RX_SUBBLK_PD<0>] = 0 (termination) */
+ BDK_CSR_MODIFY(c, node, BDK_GSERX_RX_PWR_CTRL_P2(qlm),
+ c.s.p2_rx_subblk_pd &= 0x1e);
+
+ /* 6. Modify the electrical IDLE detect on delay: set
+ GSER(0..13)_LANE(0..3)_MISC_CFG_0[EIE_DET_STL_ON_TIME] = 0x4 */
+ for (int lane = 0; lane < NUM_LANES; lane++)
+ {
+ BDK_CSR_MODIFY(c, node, BDK_GSERX_LANEX_MISC_CFG_0(qlm, lane),
+ c.s.eie_det_stl_on_time = 4);
+ }
+
+ /* 7. Modify the PLL and lane-protocol-mode registers to configure the
+ PHY for SATA */
+ /* Errata (GSER-26724) SATA never indicates GSER QLM_STAT[RST_RDY]
+ We program PLL_PX_MODE_0 last due to this errata */
+ for (int p=0; p<3; p++)
+ {
+ BDK_CSR_MODIFY(c, node, BDK_GSERX_PLL_PX_MODE_1(qlm, p),
+ c.s.pll_16p5en = 0x0;
+ c.s.pll_cpadj = 0x2;
+ c.s.pll_pcie3en = 0;
+ c.s.pll_opr = 0x0;
+ c.s.pll_div = 0x1e);
+ BDK_CSR_MODIFY(c, node, BDK_GSERX_LANE_PX_MODE_0(qlm, p),
+ c.s.ctle = 0x0;
+ c.s.pcie = 0;
+ c.s.tx_ldiv = 0x0;
+ c.s.rx_ldiv = 2 - p;
+ c.s.srate = 0;
+ c.s.tx_mode = 3;
+ c.s.rx_mode = 3);
+ BDK_CSR_MODIFY(c, node, BDK_GSERX_LANE_PX_MODE_1(qlm, p),
+ c.s.vma_fine_cfg_sel = 0;
+ c.s.vma_mm = 1;
+ c.s.cdr_fgain = 0xa;
+ c.s.ph_acc_adj = 0x15);
+ }
+ for (int p=0; p<3; p++)
+ {
+ BDK_CSR_MODIFY(c, node, BDK_GSERX_PLL_PX_MODE_0(qlm, p),
+ c.s.pll_icp = 0x1;
+ c.s.pll_rloop = 0x3;
+ c.s.pll_pcs_div = 0x5);
+ }
+
+ for (int s = 0; s < NUM_LANES / 2; s++)
+ {
+ BDK_CSR_MODIFY(c, node, BDK_GSERX_SLICEX_RX_SDLL_CTRL(qlm, s),
+ c.s.pcs_sds_oob_clk_ctrl = 2;
+ c.s.pcs_sds_rx_sdll_tune = 0;
+ c.s.pcs_sds_rx_sdll_swsel = 0);
+ }
+
+ for (int lane = 0; lane < NUM_LANES; lane++)
+ {
+ BDK_CSR_MODIFY(c, node, BDK_GSERX_LANEX_MISC_CFG_0(qlm, lane),
+ c.s.use_pma_polarity = 0;
+ c.s.cfg_pcs_loopback = 0;
+ c.s.pcs_tx_mode_ovrrd_en = 0;
+ c.s.pcs_rx_mode_ovrrd_en = 0;
+ c.s.cfg_eie_det_cnt = 0;
+ c.s.eie_det_stl_on_time = 4;
+ c.s.eie_det_stl_off_time = 0;
+ c.s.tx_bit_order = 1;
+ c.s.rx_bit_order = 1);
+ }
+
+ /* 8. Wait for GSER(0..13)_QLM_STAT[RST_RDY] = 1, indicating that the PHY
+ has been reconfigured and PLLs are locked. */
+ if (BDK_CSR_WAIT_FOR_FIELD(node, BDK_GSERX_QLM_STAT(qlm), rst_rdy, ==, 1, 10000))
+ {
+ bdk_error("QLM%d: Timeout waiting for GSERX_QLM_STAT[rst_rdy]\n", qlm);
+ return -1;
+ }
+ /* 8a. Check that the SATA_PCS is "Ready" here, should be but check it */
+ /* Poll GSERX_SATA_STATUS for PX_RDY = 1 */
+ if (BDK_CSR_WAIT_FOR_FIELD(node, BDK_GSERX_SATA_STATUS(qlm), p0_rdy, ==, 1, 10000))
+ {
+ bdk_error("QLM%d: Timeout waiting for GSERX_SATA_STATUS[p0_rdy]\n", qlm);
+ return -1;
+ }
+
+ /* Add 1ms delay for everything to stabilize*/
+ bdk_wait_usec(1000);
+
+ /* Apply any custom tuning */
+ __bdk_qlm_tune(node, qlm, BDK_QLM_MODE_SATA_4X1, baud_mhz);
+ bdk_wait_usec(1000);
+
+
+ /* 6. Deassert UCTL and UAHC resets:
+ a. SATA(0..15)_UCTL_CTL[SATA_UAHC_RST] = 0
+ b. SATA(0..15)_UCTL_CTL[SATA_UCTL_RST] = 0
+ c. Wait 10 ACLK cycles before accessing any ACLK-only registers. */
+ for (int p = sata_first; p <= sata_last; p++)
+ {
+ BDK_CSR_MODIFY(c, node, BDK_SATAX_UCTL_CTL(p),
+ c.s.sata_uahc_rst = 0;
+ c.s.sata_uctl_rst = 0);
+ }
+ bdk_wait_usec(1);
+
+ /* 7. Enable conditional SCLK of UCTL by writing
+ SATA(0..15)_UCTL_CTL[CSCLK_EN] = 1. */
+ for (int p = sata_first; p <= sata_last; p++)
+ {
+ if (CAVIUM_IS_MODEL(CAVIUM_CN8XXX))
+ {
+ /* CN9XXX make coprocessor clock automatic */
+ BDK_CSR_MODIFY(c, node, BDK_SATAX_UCTL_CTL(p),
+ c.cn8.csclk_en = 1);
+ }
+ }
+
+ /* Check BIST on the SATA controller. Start BIST in parallel on the
+ controllers */
+
+ for (int p = sata_first; p <= sata_last; p++)
+ {
+ /* Make sure BIST is configured properly before we start it. We
+ want full BIST, not just CLEAR */
+ BDK_CSR_MODIFY(c, node, BDK_SATAX_UCTL_CTL(p),
+ c.s.clear_bist = 0;
+ c.s.start_bist = 0);
+ /* Start BIST */
+ BDK_CSR_MODIFY(c, node, BDK_SATAX_UCTL_CTL(p),
+ c.s.start_bist = 1);
+ }
+ bdk_wait_usec(1000);
+ for (int p = sata_first; p <= sata_last; p++)
+ {
+ BDK_CSR_INIT(bist, node, BDK_SATAX_UCTL_BIST_STATUS(p));
+ if (bist.u)
+ bdk_error("N%d.SATA%d: Controller failed BIST (0x%llx)\n", node, p, bist.u);
+ else
+ BDK_TRACE(SATA, "N%d.SATA%d: Passed BIST\n", node, p);
+ }
+ /* Clear start_bist so it is ready for the next run */
+ for (int p = sata_first; p <= sata_last; p++)
+ {
+ BDK_CSR_MODIFY(c, node, BDK_SATAX_UCTL_CTL(p),
+ c.s.start_bist = 0);
+ }
+
+ int spd;
+ if (baud_mhz < 3000)
+ spd = 1;
+ else if (baud_mhz < 6000)
+ spd = 2;
+ else
+ spd = 3;
+
+ for (int p = sata_first; p <= sata_last; p++)
+ {
+ /* From the synopsis data book, SATAX_UAHC_GBL_TIMER1MS is the
+ AMBA clock in MHz * 1000, which is a_clk(Hz) / 1000 */
+ BDK_TRACE(QLM, "QLM%d: SATA%d set to %d Hz\n", qlm, p, a_clk);
+ BDK_CSR_MODIFY(c, node, BDK_SATAX_UAHC_GBL_TIMER1MS(p),
+ c.s.timv = a_clk / 1000);
+ /* Set speed */
+ BDK_CSR_MODIFY(c, node, BDK_SATAX_UAHC_P0_SCTL(p),
+ c.s.ipm = 3; /* Disable parial and slumber power management */
+ c.s.spd = spd);
+ /* The following SATA setup is from the AHCI 1.3 spec, section
+ 10.1.1, Firmware Specific Initialization. */
+ BDK_CSR_MODIFY(c, node, BDK_SATAX_UAHC_GBL_CAP(p),
+ c.s.sss = 1; /* Support staggered spin-up */
+ c.s.smps = 1); /* Support mechanical presence switch */
+ BDK_CSR_MODIFY(c, node, BDK_SATAX_UAHC_GBL_PI(p),
+ c.s.pi = 1); /* One port per controller */
+ BDK_CSR_MODIFY(c, node, BDK_SATAX_UAHC_P0_CMD(p),
+ c.s.hpcp = 1; /* Hot-plug-capable support */
+ c.s.mpsp = 1; /* Mechanical presence switch attached to port */
+ c.s.cpd = 1); /* Cold-presence detection */
+ }
+ return 0;
+}
+
+/**
+ * Initialize a DLM/QLM for use with SATA controllers
+ *
+ * @param node Node to intialize
+ * @param qlm Which DLM/QLM to init
+ * @param baud_mhz QLM speed in Gbaud
+ * @param sata_first First SATA controller connected to this DLM/QLM
+ * @param sata_last Last SATA controller connected to this DLM/QLM (inclusive)
+ *
+ * @return Zero on success, negative on failure
+ */
+int __bdk_qlm_set_sata_cn9xxx(bdk_node_t node, int qlm, int baud_mhz, int sata_first, int sata_last)
+{
+ //const int NUM_LANES = sata_last - sata_first + 1;
+ const int MAX_A_CLK = 333000000; /* Max of 333Mhz */
+
+ /* 26.4.1 Cold Reset */
+ /* 1. Ensure that the SerDes reference clock is up and stable. */
+ /* Already done */
+
+ /* 2. Optionally program the GPIO CSRs for SATA features.
+ a. For cold-presence detect, select a GPIO for the input and program GPI-
+ O_BIT_CFG(0..50)[PIN_SEL] = GPIO_PIN_SEL_E::SATA(0..15)_CP_DET.
+ b. For mechanical-presence detect, select a GPIO for the input and program
+ GPIO_BIT_CFG(0..50)[PIN_SEL] = GPI-
+ O_PIN_SEL_E::SATA(0..15)_MP_SWITCH.
+ c. For BIST board-test loopback, select a GPIO for the input and program GPI-
+ O_BIT_CFG(0..50)[PIN_SEL] = GPIO_PIN_SEL_E:::SATA_LAB_LB.
+ d. For LED activity, select a GPIO for the output and program GPI-
+ O_BIT_CFG(0..50)[PIN_SEL] = GPIO_PIN_SEL_E:::SATA(0..15)_ACT_LED.
+ e. For cold-presence power-on-device, select a GPIO for the output and program
+ GPIO_BIT_CFG(0..50)[PIN_SEL] = GPIO_PIN_SEL_E:::SATA(0..15)_CP_-
+ POD. */
+ /* Skipping */
+
+ /* 3. Optionally program the SGPIO unit. */
+ /* Skipping */
+
+ /* 4. Assert all resets:
+ a. UAHC reset: SATA(0..15)_UCTL_CTL[SATA_UAHC_RST] = 1
+ b. UCTL reset: SATA(0..15)_UCTL_CTL[SATA_UCTL_RST] = 1 */
+ for (int p = sata_first; p <= sata_last; p++)
+ {
+ BDK_CSR_MODIFY(c, node, BDK_SATAX_UCTL_CTL(p),
+ c.s.sata_uahc_rst = 1;
+ c.s.sata_uctl_rst = 1);
+ }
+
+ /* 5. Configure the ACLK:
+ a. Reset the clock dividers: SATA(0..15)_UCTL_CTL[A_CLKDIV_RST] = 1.
+ b. Select the ACLK frequency (refer to maximum values in Table 26 1).
+ i. SATA(0..15)_UCTL_CTL[A_CLKDIV_SEL] = desired value,
+ ii. SATA(0..15)_UCTL_CTL[A_CLK_EN] = 1 to enable the ACLK.
+ c. Deassert the ACLK clock divider reset:
+ SATA(0..15)_UCTL_CTL[A_CLKDIV_RST] = 0. */
+ int divisor = (bdk_clock_get_rate(node, BDK_CLOCK_SCLK) + MAX_A_CLK - 1) / MAX_A_CLK;
+ int a_clkdiv;
+ /* This screwy if logic is from the description of
+ SATAX_UCTL_CTL[a_clkdiv_sel] in the CSR */
+ if (divisor <= 4)
+ {
+ a_clkdiv = divisor - 1;
+ /* Divisor matches calculated value */
+ }
+ else if (divisor <= 6)
+ {
+ a_clkdiv = 4;
+ divisor = 6;
+ }
+ else if (divisor <= 8)
+ {
+ a_clkdiv = 5;
+ divisor = 8;
+ }
+ else if (divisor <= 16)
+ {
+ a_clkdiv = 6;
+ divisor = 16;
+ }
+ else if (divisor <= 24)
+ {
+ a_clkdiv = 7;
+ divisor = 24;
+ }
+ else
+ {
+ bdk_error("Unable to determine SATA clock divisor\n");
+ return -1;
+ }
+ /* Calculate the final clock rate */
+ int a_clk = bdk_clock_get_rate(node, BDK_CLOCK_SCLK) / divisor;
+
+ for (int p = sata_first; p <= sata_last; p++)
+ {
+ BDK_CSR_MODIFY(c, node, BDK_SATAX_UCTL_CTL(p),
+ c.s.a_clkdiv_rst = 1);
+ BDK_CSR_MODIFY(c, node, BDK_SATAX_UCTL_CTL(p),
+ c.s.a_clk_byp_sel = 0;
+ c.s.a_clkdiv_sel = a_clkdiv;
+ c.s.a_clk_en = 1);
+ BDK_CSR_MODIFY(c, node, BDK_SATAX_UCTL_CTL(p),
+ c.s.a_clkdiv_rst = 0);
+ }
+ bdk_wait_usec(1);
+
+ /* 8. Configure PHY for SATA. Refer to Section 21.1.2. */
+ /* Done below, section 24.1.2.3 */
+
+ /* 9. TBD: Poll QLM2_MPLL_STATUS for MPLL lock */
+ /* Not needed */
+
+ /* 10. Initialize UAHC as described in the AHCI specification
+ (UAHC_* registers). */
+ /* Done when a SATA driver is initialized */
+
+ /* 24.1.2.3 SATA Configuration
+ Software must perform the following steps to configure the GSER_WEST
+ for a SATA application. Note that the GSERW steps are on a QLM basis. */
+
+ /* 1. Configure the SATA controller (refer to Chapter 26). */
+ /* This is the code above */
+
+ /* 2. Configure the QLM Reference clock.
+ Set GSER(0..13)_REFCLK_SEL[COM_CLK_SEL] = 1 to source the reference
+ clock from the external clock multiplexer.
+ Configure GSER(0..13)_REFCLK_SEL[USE_COM1]:
+ 0 = use QLMC_REF_CLK0_P/N
+ 1 = use QLMC_REF_CLK1_P/N */
+ /* Already done */
+
+ // FIXME: GSERN setup
+
+ /* 6. Deassert UCTL and UAHC resets:
+ a. SATA(0..15)_UCTL_CTL[SATA_UAHC_RST] = 0
+ b. SATA(0..15)_UCTL_CTL[SATA_UCTL_RST] = 0
+ c. Wait 10 ACLK cycles before accessing any ACLK-only registers. */
+ for (int p = sata_first; p <= sata_last; p++)
+ {
+ BDK_CSR_MODIFY(c, node, BDK_SATAX_UCTL_CTL(p),
+ c.s.sata_uahc_rst = 0;
+ c.s.sata_uctl_rst = 0);
+ }
+ bdk_wait_usec(1);
+
+ /* 7. Enable conditional SCLK of UCTL by writing
+ SATA(0..15)_UCTL_CTL[CSCLK_EN] = 1. */
+ for (int p = sata_first; p <= sata_last; p++)
+ {
+ if (CAVIUM_IS_MODEL(CAVIUM_CN8XXX))
+ {
+ /* CN9XXX make coprocessor clock automatic */
+ BDK_CSR_MODIFY(c, node, BDK_SATAX_UCTL_CTL(p),
+ c.cn8.csclk_en = 1);
+ }
+ }
+
+ /* Check BIST on the SATA controller. Start BIST in parallel on the
+ controllers */
+ for (int p = sata_first; p <= sata_last; p++)
+ {
+ /* Make sure BIST is configured properly before we start it. We
+ want full BIST, not just CLEAR */
+ BDK_CSR_MODIFY(c, node, BDK_SATAX_UCTL_CTL(p),
+ c.s.clear_bist = 0;
+ c.s.start_bist = 0);
+ /* Start BIST */
+ BDK_CSR_MODIFY(c, node, BDK_SATAX_UCTL_CTL(p),
+ c.s.start_bist = 1);
+ }
+ bdk_wait_usec(1000);
+ for (int p = sata_first; p <= sata_last; p++)
+ {
+ BDK_CSR_INIT(bist, node, BDK_SATAX_UCTL_BIST_STATUS(p));
+ if (bist.u)
+ bdk_error("N%d.SATA%d: Controller failed BIST (0x%llx)\n", node, p, bist.u);
+ else
+ BDK_TRACE(SATA, "N%d.SATA%d: Passed BIST\n", node, p);
+ }
+ /* Clear start_bist so it is ready for the next run */
+ for (int p = sata_first; p <= sata_last; p++)
+ {
+ BDK_CSR_MODIFY(c, node, BDK_SATAX_UCTL_CTL(p),
+ c.s.start_bist = 0);
+ }
+
+ int spd;
+ if (baud_mhz < 3000)
+ spd = 1;
+ else if (baud_mhz < 6000)
+ spd = 2;
+ else
+ spd = 3;
+
+ for (int p = sata_first; p <= sata_last; p++)
+ {
+ /* From the synopsis data book, SATAX_UAHC_GBL_TIMER1MS is the
+ AMBA clock in MHz * 1000, which is a_clk(Hz) / 1000 */
+ BDK_TRACE(QLM, "QLM%d: SATA%d set to %d Hz\n", qlm, p, a_clk);
+ BDK_CSR_MODIFY(c, node, BDK_SATAX_UAHC_GBL_TIMER1MS(p),
+ c.s.timv = a_clk / 1000);
+ /* Set speed */
+ BDK_CSR_MODIFY(c, node, BDK_SATAX_UAHC_P0_SCTL(p),
+ c.s.ipm = 3; /* Disable parial and slumber power management */
+ c.s.spd = spd);
+ /* The following SATA setup is from the AHCI 1.3 spec, section
+ 10.1.1, Firmware Specific Initialization. */
+ BDK_CSR_MODIFY(c, node, BDK_SATAX_UAHC_GBL_CAP(p),
+ c.s.sss = 1; /* Support staggered spin-up */
+ c.s.smps = 1); /* Support mechanical presence switch */
+ BDK_CSR_MODIFY(c, node, BDK_SATAX_UAHC_GBL_PI(p),
+ c.s.pi = 1); /* One port per controller */
+ BDK_CSR_MODIFY(c, node, BDK_SATAX_UAHC_P0_CMD(p),
+ c.s.hpcp = 1; /* Hot-plug-capable support */
+ c.s.mpsp = 1; /* Mechanical presence switch attached to port */
+ c.s.cpd = 1); /* Cold-presence detection */
+ }
+ return 0;
+}
+
diff --git a/src/vendorcode/cavium/bdk/libbdk-hal/qlm/bdk-qlm-common.c b/src/vendorcode/cavium/bdk/libbdk-hal/qlm/bdk-qlm-common.c
new file mode 100644
index 0000000000..2b3390228a
--- /dev/null
+++ b/src/vendorcode/cavium/bdk/libbdk-hal/qlm/bdk-qlm-common.c
@@ -0,0 +1,1636 @@
+/***********************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-hal/if/bdk-if.h"
+#include "libbdk-hal/bdk-qlm.h"
+#include "libbdk-hal/qlm/bdk-qlm-common.h"
+#include "libbdk-arch/bdk-csrs-gser.h"
+#include "libbdk-arch/bdk-csrs-pem.h"
+#include "libbdk-hal/bdk-config.h"
+#include "libbdk-hal/bdk-utils.h"
+#include "libbdk-hal/bdk-twsi.h"
+
+/* Indexed by QLM number and lane */
+static uint64_t prbs_errors[14][4];
+
+/**
+ * Figure out which lane mode to use for a given reference clock and GBaud
+ *
+ * @param mode_name String name for error messages
+ * @param qlm QlM being configured
+ * @param ref_clk Reference clock in hertz
+ * @param baud_mhz Baud rate in Mhz
+ *
+ * @return Lane mode or -1 on failure
+ */
+int __bdk_qlm_get_lane_mode_for_speed_and_ref_clk(const char *mode_name, int qlm, int ref_clk, int baud_mhz)
+{
+ if (baud_mhz <= 1250)
+ {
+ if ((ref_clk == REF_156MHZ) || (ref_clk == REF_100MHZ))
+ return BDK_GSER_LMODE_E_R_125G_REFCLK15625_SGMII;
+ else
+ {
+ bdk_error("Invalid reference clock for %s on QLM%d with speed %d, ref %d Mhz\n", mode_name, qlm, baud_mhz, ref_clk / 1000000);
+ return -1;
+ }
+ }
+ else if (baud_mhz <= 2500)
+ {
+ if (ref_clk == REF_100MHZ)
+ return BDK_GSER_LMODE_E_R_25G_REFCLK100;
+ else if (ref_clk == REF_125MHZ)
+ return BDK_GSER_LMODE_E_R_25G_REFCLK125;
+ else
+ {
+ bdk_error("Invalid reference clock for %s on QLM%d with speed %d, ref %d Mhz\n", mode_name, qlm, baud_mhz, ref_clk / 1000000);
+ return -1;
+ }
+ }
+ else if (baud_mhz <= 3125)
+ {
+ if (ref_clk == REF_156MHZ)
+ return BDK_GSER_LMODE_E_R_3125G_REFCLK15625_XAUI;
+ else
+ {
+ bdk_error("Invalid reference clock for %s on QLM%d with speed %d, ref %d Mhz\n", mode_name, qlm, baud_mhz, ref_clk / 1000000);
+ return -1;
+ }
+ }
+ else if (baud_mhz <= 5000)
+ {
+ if (ref_clk == REF_100MHZ)
+ return BDK_GSER_LMODE_E_R_5G_REFCLK100;
+ else if (ref_clk == REF_125MHZ)
+ return BDK_GSER_LMODE_E_R_5G_REFCLK125;
+ else
+ return BDK_GSER_LMODE_E_R_5G_REFCLK15625_QSGMII;
+ }
+ else if (baud_mhz <= 6250)
+ {
+ if (ref_clk == REF_156MHZ)
+ return BDK_GSER_LMODE_E_R_625G_REFCLK15625_RXAUI;
+ else
+ {
+ bdk_error("Invalid reference clock for %s on QLM%d with speed %d, ref %d Mhz\n", mode_name, qlm, baud_mhz, ref_clk / 1000000);
+ return -1;
+ }
+ }
+ else if (baud_mhz <= 8000)
+ {
+ if (ref_clk == REF_100MHZ)
+ return BDK_GSER_LMODE_E_R_8G_REFCLK100;
+ else if (ref_clk == REF_125MHZ)
+ return BDK_GSER_LMODE_E_R_8G_REFCLK125;
+ else
+ {
+ bdk_error("Invalid reference clock for %s on QLM%d with speed %d, ref %d Mhz\n", mode_name, qlm, baud_mhz, ref_clk / 1000000);
+ return -1;
+ }
+ }
+ else /* Baud 10312.5 */
+ {
+ if (ref_clk == REF_156MHZ)
+ return BDK_GSER_LMODE_E_R_103125G_REFCLK15625_KR;
+ else
+ {
+ bdk_error("Invalid reference clock for %s on QLM%d with speed %d, ref %d Mhz\n", mode_name, qlm, baud_mhz, ref_clk / 1000000);
+ return -1;
+ }
+ }
+ bdk_error("Invalid speed for %s on QLM%d with speed %d, ref %d Mhz\n", mode_name, qlm, baud_mhz, ref_clk / 1000000);
+ return -1;
+}
+
+/**
+ * Setup the PEM to either driver or receive reset from PRST based on RC or EP
+ *
+ * @param node Node to use in a Numa setup
+ * @param pem Which PEM to setuo
+ * @param is_endpoint
+ * Non zero if PEM is a EP
+ */
+void __bdk_qlm_setup_pem_reset(bdk_node_t node, int pem, int is_endpoint)
+{
+ /* Make sure is_endpoint is either 0 or 1 */
+ is_endpoint = (is_endpoint != 0);
+ BDK_CSR_MODIFY(c, node, BDK_RST_CTLX(pem),
+ c.s.prst_link = 0; /* Link down doesn't automatically assert PERST */
+ c.s.rst_link = is_endpoint; /* Link down automatically assert soft reset for EP */
+ c.s.rst_drv = !is_endpoint; /* PERST is output for RC, input for EP */
+ c.s.rst_rcv = is_endpoint; /* Only read PERST in EP mode */
+ c.s.rst_chip = 0); /* PERST doesn't pull CHIP_RESET */
+
+ if (is_endpoint)
+ {
+ /* If we're configuring an endpoint manually the PEM will not
+ be turned on by default by the hardware. Turn it on now */
+ BDK_CSR_INIT(pemx_on, node, BDK_PEMX_ON(pem));
+ if (!pemx_on.s.pemon)
+ {
+ BDK_CSR_MODIFY(c, node, BDK_PEMX_CLK_EN(pem),
+ c.cn83xx.pceclk_gate = 0;
+ c.cn83xx.csclk_gate = 0);
+ BDK_CSR_MODIFY(c, node, BDK_PEMX_ON(pem),
+ c.s.pemon = 1);
+ }
+ }
+}
+
+/**
+ * Measure the reference clock of a QLM
+ *
+ * @param qlm QLM to measure
+ *
+ * @return Clock rate in Hz
+ */
+int __bdk_qlm_measure_refclock(bdk_node_t node, int qlm)
+{
+ /* Clear the counter */
+ BDK_CSR_MODIFY(c, node, BDK_GSERX_REFCLK_EVT_CTRL(qlm),
+ c.s.enb = 0;
+ c.s.clr = 1);
+ bdk_wait_usec(1); /* Give counter a chance to clear */
+ if (BDK_CSR_READ(node, BDK_GSERX_REFCLK_EVT_CNTR(qlm)))
+ bdk_error("GSER%d: Ref clock counter not zero\n", qlm);
+ /* Start counting */
+ uint64_t start = bdk_clock_get_count(BDK_CLOCK_TIME);
+ BDK_CSR_MODIFY(c, node, BDK_GSERX_REFCLK_EVT_CTRL(qlm),
+ c.s.enb = 1;
+ c.s.clr = 0);
+ /* Wait for a short time to get a number of counts */
+ bdk_wait_usec(20000); /* 20ms */
+ /* Stop counting */
+ BDK_CSR_MODIFY(c, node, BDK_GSERX_REFCLK_EVT_CTRL(qlm),
+ c.s.enb = 0);
+ uint64_t stop = bdk_clock_get_count(BDK_CLOCK_TIME);
+ bdk_wait_usec(1); /* Give counter a chance to stabalize */
+
+ /* Calculate the rate */
+ uint64_t count = BDK_CSR_READ(node, BDK_GSERX_REFCLK_EVT_CNTR(qlm));
+ count *= bdk_clock_get_rate(bdk_numa_local(), BDK_CLOCK_TIME);
+ count /= stop - start;
+ return count;
+}
+
+/**
+ * Put a QLM into hardware reset
+ *
+ * @param node Node to use in a numa setup
+ * @param qlm QLM to use
+ *
+ * @return Zero on success, negative on failure
+ */
+int __bdk_qlm_reset(bdk_node_t node, int qlm)
+{
+ BDK_CSR_MODIFY(c, node, BDK_GSERX_PHY_CTL(qlm),
+ c.s.phy_reset = 1);
+ return 0;
+}
+
+/**
+ * Enable PRBS on a QLM
+ *
+ * @param node Node to use in a numa setup
+ * @param qlm QLM to use
+ * @param prbs PRBS mode (31, etc)
+ * @param dir Directions to enable. This is so you can enable TX and later
+ * enable RX after TX has run for a time
+ *
+ * @return Zero on success, negative on failure
+ */
+int __bdk_qlm_enable_prbs(bdk_node_t node, int qlm, int prbs, bdk_qlm_direction_t dir)
+{
+ const int NUM_LANES = bdk_qlm_get_lanes(node, qlm);
+ int mode;
+ switch (prbs)
+ {
+ case 31:
+ mode = 1;
+ break;
+ case 23:
+ mode = 2; /* Or 3? */
+ break;
+ case 16:
+ mode = 4;
+ break;
+ case 15:
+ mode = 5;
+ break;
+ case 11:
+ mode = 6;
+ break;
+ case 7:
+ mode = 7;
+ break;
+ default:
+ mode = prbs & 0xff;
+ for (int lane = 0; lane < NUM_LANES; lane++)
+ BDK_CSR_WRITE(node, BDK_GSERX_LANEX_LBERT_PAT_CFG(qlm, lane), prbs >> 8);
+ BDK_TRACE(QLM, "Using mode 0x%x with custom pattern 0x%x\n", mode, prbs >> 8);
+ break;
+ }
+
+ /* For some reason PRBS doesn't work if GSER is configured for PCIe.
+ Disconnect PCIe when we start PRBS */
+ BDK_CSR_INIT(gserx_cfg, node, BDK_GSERX_CFG(qlm));
+ if (gserx_cfg.s.pcie)
+ {
+ gserx_cfg.s.pcie = 0;
+ BDK_CSR_WRITE(node, BDK_GSERX_CFG(qlm), gserx_cfg.u);
+ bdk_warn("N%d.QLM%d: Disabling PCIe for PRBS/pattern generation\n", node, qlm);
+ }
+ /* For some reason PRBS doesn't work if GSER is configured for SATA.
+ Disconnect SATA when we start PRBS */
+ if (gserx_cfg.s.sata)
+ {
+ gserx_cfg.s.sata = 0;
+ BDK_CSR_WRITE(node, BDK_GSERX_CFG(qlm), gserx_cfg.u);
+ bdk_warn("N%d.QLM%d: Disabling SATA for PRBS/pattern generation\n", node, qlm);
+ bdk_warn("N%d.QLM%d: SATA PRBS/patterns always run at 6G\n", node, qlm);
+ }
+
+ BDK_CSR_MODIFY(c, node, BDK_GSERX_PHY_CTL(qlm),
+ c.s.phy_reset = 0);
+
+ if (dir & BDK_QLM_DIRECTION_TX)
+ {
+ /* Disable first in case already running */
+ for (int lane = 0; lane < NUM_LANES; lane++)
+ BDK_CSR_MODIFY(c, node, BDK_GSERX_LANEX_LBERT_CFG(qlm, lane),
+ c.s.lbert_pg_en = 0);
+ for (int lane = 0; lane < NUM_LANES; lane++)
+ BDK_CSR_MODIFY(c, node, BDK_GSERX_LANEX_LBERT_CFG(qlm, lane),
+ c.s.lbert_pg_en = 1; /* Enable generator */
+ c.s.lbert_pg_width = 3; /* 20 bit */
+ c.s.lbert_pg_mode = mode);
+ }
+
+ if (dir & BDK_QLM_DIRECTION_RX)
+ {
+ /* Clear the error counter and Disable the matcher */
+ for (int lane = 0; lane < NUM_LANES; lane++)
+ {
+ prbs_errors[qlm][lane] = 0;
+ BDK_CSR_MODIFY(c, node, BDK_GSERX_LANEX_LBERT_CFG(qlm, lane),
+ c.s.lbert_pm_en = 0);
+ }
+ for (int lane = 0; lane < NUM_LANES; lane++)
+ {
+ BDK_CSR_MODIFY(c, node, BDK_GSERX_LANEX_LBERT_CFG(qlm, lane),
+ c.s.lbert_pm_en = 1; /* Enable matcher */
+ c.s.lbert_pm_width = 3; /* 20 bit */
+ c.s.lbert_pm_mode = mode);
+ }
+ /* Tell the matcher to start sync */
+ for (int retry=0; retry < 4; retry++)
+ {
+ for (int lane = 0; lane < NUM_LANES; lane++)
+ {
+ BDK_CSR_MODIFY(c, node, BDK_GSERX_LANEX_LBERT_CFG(qlm, lane),
+ c.s.lbert_pm_sync_start = 1);
+ }
+ /* Wait 10ms */
+ bdk_wait_usec(10000);
+ }
+ }
+ return 0;
+}
+
+/**
+ * Disable PRBS on a QLM
+ *
+ * @param node Node to use in a numa setup
+ * @param qlm QLM to use
+ *
+ * @return Zero on success, negative on failure
+ */
+int __bdk_qlm_disable_prbs(bdk_node_t node, int qlm)
+{
+ const int NUM_LANES = bdk_qlm_get_lanes(node, qlm);
+ BDK_CSR_INIT(phy_ctl, node, BDK_GSERX_PHY_CTL(qlm));
+ if (phy_ctl.s.phy_reset)
+ return -1;
+
+ for (int lane = 0; lane < NUM_LANES; lane++)
+ {
+ prbs_errors[qlm][lane] = 0;
+ BDK_CSR_MODIFY(c, node, BDK_GSERX_LANEX_LBERT_CFG(qlm, lane),
+ c.s.lbert_pg_en = 0;
+ c.s.lbert_pm_en = 0);
+ }
+ return 0;
+}
+
+/**
+ * Return the number of PRBS errors since PRBS started running
+ *
+ * @param node Node to use in numa setup
+ * @param qlm QLM to use
+ * @param lane Which lane
+ * @param clear Clear counter after return the current value
+ *
+ * @return Number of errors
+ */
+uint64_t __bdk_qlm_get_prbs_errors(bdk_node_t node, int qlm, int lane, int clear)
+{
+ /* Restart synchronization */
+ BDK_CSR_MODIFY(c, node, BDK_GSERX_LANEX_LBERT_CFG(qlm, lane),
+ c.s.lbert_pm_sync_start = 1);
+ /* This CSR is self clearing per the CSR description, but it doesn't
+ seem to do that. Instead it clears when we trigger sync again */
+ BDK_CSR_INIT(rx, node, BDK_GSERX_LANEX_LBERT_ECNT(qlm, lane));
+ uint64_t errors = rx.s.lbert_err_cnt;
+ if (rx.s.lbert_err_ovbit14)
+ errors <<= 7;
+ prbs_errors[qlm][lane] += errors;
+ uint64_t result = prbs_errors[qlm][lane];
+ if (clear)
+ prbs_errors[qlm][lane] = 0;
+ return result;
+}
+
+/**
+ * Inject an error into PRBS
+ *
+ * @param node Node to use in numa setup
+ * @param qlm QLM to use
+ * @param lane Which lane
+ */
+void __bdk_qlm_inject_prbs_error(bdk_node_t node, int qlm, int lane)
+{
+ BDK_CSR_MODIFY(c, node, BDK_GSERX_LANEX_LBERT_CFG(qlm, lane),
+ c.s.lbert_pg_err_insert = 1);
+}
+
+/**
+ * Enable shallow loopback on a QLM
+ *
+ * @param node Node to use in a numa setup
+ * @param qlm QLM to use
+ * @param loop Type of loopback. Not all QLMs support all modes
+ *
+ * @return Zero on success, negative on failure
+ */
+int __bdk_qlm_enable_loop(bdk_node_t node, int qlm, bdk_qlm_loop_t loop)
+{
+ bdk_error("Chip doesn't support shallow QLM loopback\n");
+ return -1;
+}
+
+/**
+ * Initialize the QLM mode table
+ *
+ * @param node Node to initialize
+ * @param qlm Which QLM
+ * @param ref_clk Reference clock of the QLM in Hz
+ */
+void __bdk_qlm_init_mode_table(bdk_node_t node, int qlm, int ref_clk)
+{
+ /* The QLM PLLs are controlled by an array of parameters indexed
+ by the QLM mode for each QLM. We need to fill in these tables.
+ Also each lane has some mode parameters, again in a array index
+ by the lane_mode */
+ for (int lane_mode = 0; lane_mode < 12; lane_mode++)
+ {
+ /* The values used below are all from
+ http://mawiki.caveonetworks.com/wiki/78xx/GSER_WEST */
+ BDK_CSR_INIT(pll_mode_0 , node, BDK_GSERX_PLL_PX_MODE_0(qlm, lane_mode));
+ BDK_CSR_INIT(pll_mode_1 , node, BDK_GSERX_PLL_PX_MODE_1(qlm, lane_mode));
+ BDK_CSR_INIT(lane_mode_0, node, BDK_GSERX_LANE_PX_MODE_0(qlm, lane_mode));
+ BDK_CSR_INIT(lane_mode_1, node, BDK_GSERX_LANE_PX_MODE_1(qlm, lane_mode));
+ switch (lane_mode)
+ {
+ case BDK_GSER_LMODE_E_R_25G_REFCLK100:
+ case BDK_GSER_LMODE_E_R_5G_REFCLK100:
+ case BDK_GSER_LMODE_E_R_8G_REFCLK100:
+ /* These modes are used for PCIe where the defaults are
+ correct. Skip programming these */
+ continue;
+ case BDK_GSER_LMODE_E_R_125G_REFCLK15625_KX:
+ pll_mode_0.s.pll_icp = 0x1;
+ pll_mode_0.s.pll_rloop = 0x3;
+ pll_mode_0.s.pll_pcs_div = 0x28;
+
+ pll_mode_1.s.pll_16p5en = 0x1;
+ pll_mode_1.s.pll_cpadj = 0x3;
+ pll_mode_1.s.pll_pcie3en = 0x0;
+ pll_mode_1.s.pll_opr = 0x0;
+ pll_mode_1.s.pll_div = 0x10;
+
+ lane_mode_0.s.ctle = 0x0;
+ lane_mode_0.s.pcie = 0x0;
+ lane_mode_0.s.tx_ldiv = 0x2;
+ lane_mode_0.s.rx_ldiv = 0x2;
+ lane_mode_0.s.srate = 0x0;
+ lane_mode_0.s.tx_mode = 0x3;
+ lane_mode_0.s.rx_mode = 0x3;
+
+ lane_mode_1.s.vma_fine_cfg_sel = 0x0;
+ lane_mode_1.s.vma_mm = 0x1;
+ lane_mode_1.s.cdr_fgain = 0xc;
+ lane_mode_1.s.ph_acc_adj = 0x1e;
+ break;
+ case BDK_GSER_LMODE_E_R_3125G_REFCLK15625_XAUI:
+ pll_mode_0.s.pll_icp = 0x1;
+ pll_mode_0.s.pll_rloop = 0x3;
+ pll_mode_0.s.pll_pcs_div = 0x14;
+
+ pll_mode_1.s.pll_16p5en = 0x1;
+ pll_mode_1.s.pll_cpadj = 0x2;
+ pll_mode_1.s.pll_pcie3en = 0x0;
+ pll_mode_1.s.pll_opr = 0x0;
+ pll_mode_1.s.pll_div = 0x14;
+
+ lane_mode_0.s.ctle = 0x0;
+ lane_mode_0.s.pcie = 0x0;
+ lane_mode_0.s.tx_ldiv = 0x1;
+ lane_mode_0.s.rx_ldiv = 0x1;
+ lane_mode_0.s.srate = 0x0;
+ lane_mode_0.s.tx_mode = 0x3;
+ lane_mode_0.s.rx_mode = 0x3;
+
+ lane_mode_1.s.vma_fine_cfg_sel = 0x0;
+ lane_mode_1.s.vma_mm = 0x1;
+ lane_mode_1.s.cdr_fgain = 0xc;
+ lane_mode_1.s.ph_acc_adj = 0x1e;
+ break;
+ case BDK_GSER_LMODE_E_R_103125G_REFCLK15625_KR:
+ pll_mode_0.s.pll_icp = 0x1;
+ pll_mode_0.s.pll_rloop = 0x5;
+ pll_mode_0.s.pll_pcs_div = 0xa;
+
+ pll_mode_1.s.pll_16p5en = 0x1;
+ pll_mode_1.s.pll_cpadj = 0x2;
+ pll_mode_1.s.pll_pcie3en = 0x0;
+ pll_mode_1.s.pll_opr = 0x1;
+ pll_mode_1.s.pll_div = 0x21;
+
+ lane_mode_0.s.ctle = 0x3;
+ lane_mode_0.s.pcie = 0x0;
+ lane_mode_0.s.tx_ldiv = 0x0;
+ lane_mode_0.s.rx_ldiv = 0x0;
+ lane_mode_0.s.srate = 0x0;
+ lane_mode_0.s.tx_mode = 0x3;
+ lane_mode_0.s.rx_mode = 0x3;
+
+ lane_mode_1.s.vma_fine_cfg_sel = 0x1;
+ lane_mode_1.s.vma_mm = 0x0;
+ lane_mode_1.s.cdr_fgain = 0xa;
+ lane_mode_1.s.ph_acc_adj = 0xf;
+ break;
+ case BDK_GSER_LMODE_E_R_125G_REFCLK15625_SGMII:
+ pll_mode_0.s.pll_icp = 0x1;
+ pll_mode_0.s.pll_rloop = 0x3;
+ pll_mode_0.s.pll_pcs_div = 0x28;
+
+ pll_mode_1.s.pll_16p5en = 0x1;
+ pll_mode_1.s.pll_cpadj = 0x3;
+ pll_mode_1.s.pll_pcie3en = 0x0;
+ pll_mode_1.s.pll_opr = 0x0;
+ pll_mode_1.s.pll_div = 0x10;
+
+ lane_mode_0.s.ctle = 0x0;
+ lane_mode_0.s.pcie = 0x0;
+ lane_mode_0.s.tx_ldiv = 0x2;
+ lane_mode_0.s.rx_ldiv = 0x2;
+ lane_mode_0.s.srate = 0x0;
+ lane_mode_0.s.tx_mode = 0x3;
+ lane_mode_0.s.rx_mode = 0x3;
+
+ lane_mode_1.s.vma_fine_cfg_sel = 0x0;
+ lane_mode_1.s.vma_mm = 0x1;
+ lane_mode_1.s.cdr_fgain = 0xc;
+ lane_mode_1.s.ph_acc_adj = 0x1e;
+ if(ref_clk == REF_100MHZ)
+ {
+ pll_mode_0.s.pll_pcs_div = 0x28;
+ pll_mode_1.s.pll_div = 0x19;
+ pll_mode_1.s.pll_cpadj = 0x2;
+ }
+ break;
+ case BDK_GSER_LMODE_E_R_5G_REFCLK15625_QSGMII:
+ pll_mode_0.s.pll_icp = 0x1; /* Per Scott McIlhenny 5/17/2016 (t81) */
+ pll_mode_0.s.pll_rloop = 0x3;
+ pll_mode_0.s.pll_pcs_div = 0xa;
+
+ pll_mode_1.s.pll_16p5en = 0x0;
+ pll_mode_1.s.pll_cpadj = 0x2;
+ pll_mode_1.s.pll_pcie3en = 0x0;
+ pll_mode_1.s.pll_opr = 0x0;
+ /* QSGMII is a special case. We use the same table entry for
+ 100Mhz and 125Mhz clocks as the normal 156Mhz */
+ switch (ref_clk)
+ {
+ case REF_100MHZ:
+ pll_mode_1.s.pll_div = 0x19;
+ break;
+ case REF_125MHZ:
+ pll_mode_1.s.pll_div = 0x14;
+ break;
+ default: /* REF_156MHZ */
+ pll_mode_1.s.pll_div = 0x10;
+ break;
+ }
+
+ lane_mode_0.s.ctle = 0x0;
+ lane_mode_0.s.pcie = 0x0;
+ lane_mode_0.s.tx_ldiv = 0x0;
+ lane_mode_0.s.rx_ldiv = 0x0;
+ lane_mode_0.s.srate = 0x0;
+ lane_mode_0.s.tx_mode = 0x3;
+ lane_mode_0.s.rx_mode = 0x3;
+
+ lane_mode_1.s.vma_fine_cfg_sel = 0x0;
+ lane_mode_1.s.vma_mm = 0x1; /* Per Scott McIlhenny 5/17/2016 (t81) */
+ lane_mode_1.s.cdr_fgain = 0xc;
+ lane_mode_1.s.ph_acc_adj = 0x1e;
+ break;
+ case BDK_GSER_LMODE_E_R_625G_REFCLK15625_RXAUI:
+ pll_mode_0.s.pll_icp = 0x1;
+ pll_mode_0.s.pll_rloop = 0x3;
+ pll_mode_0.s.pll_pcs_div = 0xa;
+
+ pll_mode_1.s.pll_16p5en = 0x0;
+ pll_mode_1.s.pll_cpadj = 0x2;
+ pll_mode_1.s.pll_pcie3en = 0x0;
+ pll_mode_1.s.pll_opr = 0x0;
+ pll_mode_1.s.pll_div = 0x14;
+
+ lane_mode_0.s.ctle = 0x0;
+ lane_mode_0.s.pcie = 0x0;
+ lane_mode_0.s.tx_ldiv = 0x0;
+ lane_mode_0.s.rx_ldiv = 0x0;
+ lane_mode_0.s.srate = 0x0;
+ lane_mode_0.s.tx_mode = 0x3;
+ lane_mode_0.s.rx_mode = 0x3;
+
+ lane_mode_1.s.vma_fine_cfg_sel = 0x0;
+ lane_mode_1.s.vma_mm = 0x0;
+ lane_mode_1.s.cdr_fgain = 0xa;
+ lane_mode_1.s.ph_acc_adj = 0x14;
+ break;
+ case BDK_GSER_LMODE_E_R_25G_REFCLK125:
+ pll_mode_0.s.pll_icp = 0x3;
+ pll_mode_0.s.pll_rloop = 0x3;
+ pll_mode_0.s.pll_pcs_div = 0x5;
+
+ pll_mode_1.s.pll_16p5en = 0x0;
+ pll_mode_1.s.pll_cpadj = 0x1;
+ pll_mode_1.s.pll_pcie3en = 0x0;
+ pll_mode_1.s.pll_opr = 0x0;
+ pll_mode_1.s.pll_div = 0x14;
+
+ lane_mode_0.s.ctle = 0x0;
+ lane_mode_0.s.pcie = 0x1;
+ lane_mode_0.s.tx_ldiv = 0x1;
+ lane_mode_0.s.rx_ldiv = 0x1;
+ lane_mode_0.s.srate = 0x0;
+ lane_mode_0.s.tx_mode = 0x3;
+ lane_mode_0.s.rx_mode = 0x3;
+
+ lane_mode_1.s.vma_fine_cfg_sel = 0x0;
+ lane_mode_1.s.vma_mm = 0x1;
+ lane_mode_1.s.cdr_fgain = 0xa;
+ lane_mode_1.s.ph_acc_adj = 0x14;
+ break;
+ case BDK_GSER_LMODE_E_R_5G_REFCLK125:
+ pll_mode_0.s.pll_icp = 0x3;
+ pll_mode_0.s.pll_rloop = 0x3;
+ pll_mode_0.s.pll_pcs_div = 0xa;
+
+ pll_mode_1.s.pll_16p5en = 0x0;
+ pll_mode_1.s.pll_cpadj = 0x1;
+ pll_mode_1.s.pll_pcie3en = 0x0;
+ pll_mode_1.s.pll_opr = 0x0;
+ pll_mode_1.s.pll_div = 0x14;
+
+ lane_mode_0.s.ctle = 0x0;
+ lane_mode_0.s.pcie = 0x1;
+ lane_mode_0.s.tx_ldiv = 0x0;
+ lane_mode_0.s.rx_ldiv = 0x0;
+ lane_mode_0.s.srate = 0x0;
+ lane_mode_0.s.tx_mode = 0x3;
+ lane_mode_0.s.rx_mode = 0x3;
+
+ lane_mode_1.s.vma_fine_cfg_sel = 0x0;
+ lane_mode_1.s.vma_mm = 0x0;
+ lane_mode_1.s.cdr_fgain = 0xa;
+ lane_mode_1.s.ph_acc_adj = 0x14;
+ break;
+ case BDK_GSER_LMODE_E_R_8G_REFCLK125:
+ pll_mode_0.s.pll_icp = 0x2;
+ pll_mode_0.s.pll_rloop = 0x5;
+ pll_mode_0.s.pll_pcs_div = 0xa;
+
+ pll_mode_1.s.pll_16p5en = 0x0;
+ pll_mode_1.s.pll_cpadj = 0x1;
+ pll_mode_1.s.pll_pcie3en = 0x1;
+ pll_mode_1.s.pll_opr = 0x1;
+ pll_mode_1.s.pll_div = 0x20;
+
+ lane_mode_0.s.ctle = 0x3;
+ lane_mode_0.s.pcie = 0x0;
+ lane_mode_0.s.tx_ldiv = 0x0;
+ lane_mode_0.s.rx_ldiv = 0x0;
+ lane_mode_0.s.srate = 0x0;
+ lane_mode_0.s.tx_mode = 0x2;
+ lane_mode_0.s.rx_mode = 0x2;
+
+ lane_mode_1.s.vma_fine_cfg_sel = 0x0;
+ lane_mode_1.s.vma_mm = 0x0;
+ lane_mode_1.s.cdr_fgain = 0xb;
+ lane_mode_1.s.ph_acc_adj = 0x23;
+ break;
+ }
+ BDK_CSR_WRITE(node, BDK_GSERX_PLL_PX_MODE_0(qlm, lane_mode), pll_mode_0.u);
+ BDK_CSR_WRITE(node, BDK_GSERX_PLL_PX_MODE_1(qlm, lane_mode), pll_mode_1.u);
+ BDK_CSR_WRITE(node, BDK_GSERX_LANE_PX_MODE_0(qlm, lane_mode), lane_mode_0.u);
+ BDK_CSR_WRITE(node, BDK_GSERX_LANE_PX_MODE_1(qlm, lane_mode), lane_mode_1.u);
+ }
+}
+
+/**
+ * Given a valid PEM number, return its speed in Gbaud
+ *
+ * @param node Node to use in numa setup
+ * @param pem PEM to get speed of
+ *
+ * @return Speed in Gbaud. Zero if disabled
+ */
+int __bdk_qlm_get_gbaud_mhz_pem(bdk_node_t node, int pem)
+{
+ BDK_CSR_INIT(pem_cfg, node, BDK_PEMX_CFG(pem));
+ switch (pem_cfg.cn83xx.md)
+ {
+ case 0: /* Gen 1 */
+ return 2500;
+ case 1: /* Gen 2 */
+ return 5000;
+ case 2: /* Gen 3 */
+ return 8000;
+ default:
+ return 0;
+ }
+}
+
+/**
+ * Get the speed of a QLM using its LMODE. This can't be used on PCIe QLMs.
+ *
+ * @param node Node to use in numa setup
+ * @param qlm Which QLM
+ *
+ * @return QLM speed on Gbaud
+ */
+int __bdk_qlm_get_gbaud_mhz_lmode(bdk_node_t node, int qlm)
+{
+ /* QLM is not in PCIe, assume LMODE is good enough for determining
+ the speed */
+ BDK_CSR_INIT(lane_mode, node, BDK_GSERX_LANE_MODE(qlm));
+ switch (lane_mode.s.lmode)
+ {
+ case BDK_GSER_LMODE_E_R_25G_REFCLK100:
+ return 2500;
+ case BDK_GSER_LMODE_E_R_5G_REFCLK100:
+ return 5000;
+ case BDK_GSER_LMODE_E_R_8G_REFCLK100:
+ return 8000;
+ case BDK_GSER_LMODE_E_R_125G_REFCLK15625_KX:
+ return 1250;
+ case BDK_GSER_LMODE_E_R_3125G_REFCLK15625_XAUI:
+ return 3125;
+ case BDK_GSER_LMODE_E_R_103125G_REFCLK15625_KR:
+ return 10312;
+ case BDK_GSER_LMODE_E_R_125G_REFCLK15625_SGMII:
+ return 1250;
+ case BDK_GSER_LMODE_E_R_5G_REFCLK15625_QSGMII:
+ return 5000;
+ case BDK_GSER_LMODE_E_R_625G_REFCLK15625_RXAUI:
+ return 6250;
+ case BDK_GSER_LMODE_E_R_25G_REFCLK125:
+ return 2500;
+ case BDK_GSER_LMODE_E_R_5G_REFCLK125:
+ return 5000;
+ case BDK_GSER_LMODE_E_R_8G_REFCLK125:
+ return 8000;
+ default:
+ return 0;
+ }
+}
+
+/**
+ * Converts a measured reference clock to a likely ideal value. Rounds
+ * clock speed to the nearest REF_*Mhz define.
+ *
+ * @param node Node to use in numa setup
+ * @param qlm Which QLM
+ * @param measured_hz
+ * Measured value
+ *
+ * @return Value exactly matching a define
+ */
+int __bdk_qlm_round_refclock(bdk_node_t node, int qlm, int measured_hz)
+{
+ int ref_clk;
+ if ((measured_hz > REF_100MHZ - REF_100MHZ / 10) && (measured_hz < REF_100MHZ + REF_100MHZ / 10))
+ {
+ ref_clk = REF_100MHZ;
+ }
+ else if ((measured_hz > REF_125MHZ - REF_125MHZ / 10) && (measured_hz < REF_125MHZ + REF_125MHZ / 10))
+ {
+ ref_clk = REF_125MHZ;
+ }
+ else if ((measured_hz > REF_156MHZ - REF_156MHZ / 10) && (measured_hz < REF_156MHZ + REF_156MHZ / 10))
+ {
+ ref_clk = REF_156MHZ;
+ }
+ else if (measured_hz < 1000000)
+ {
+ ref_clk = 0; /* Used for disabled QLMs */
+ }
+ else
+ {
+ ref_clk = measured_hz;
+ bdk_error("N%d.QLM%d: Unexpected reference clock speed of %d Mhz\n", node, qlm, measured_hz / 1000000);
+ }
+ return ref_clk;
+}
+
+/**
+ * TWSI reads from the MCU randomly timeout. Retry a few times on
+ * failure to try and recover
+ *
+ * @param node Node to use in a Numa setup. Can be an exact ID or a special
+ * value.
+ * @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
+ */
+static int64_t mcu_read(bdk_node_t node, int twsi_id, uint8_t dev_addr, uint16_t internal_addr, int num_bytes, int ia_width_bytes)
+{
+ int read_tries = 0;
+ int64_t result;
+ do
+ {
+ result = bdk_twsix_read_ia(node, twsi_id, dev_addr, internal_addr, num_bytes, ia_width_bytes);
+ read_tries++;
+ if (result < 0)
+ {
+ BDK_TRACE(QLM, "Timeout %d reading from MCU\n", read_tries);
+ bdk_wait_usec(100000);
+ }
+ } while ((result < 0) && (read_tries < 3));
+ return result;
+}
+
+static void __bdk_qlm_set_reference(bdk_node_t node, int qlm, int ref_clk)
+{
+ int use_clock;
+ if (CAVIUM_IS_MODEL(CAVIUM_CN88XX) || CAVIUM_IS_MODEL(CAVIUM_CN83XX) || CAVIUM_IS_MODEL(CAVIUM_CN81XX))
+ {
+ switch (ref_clk)
+ {
+ case REF_100MHZ:
+ use_clock = 0; /* Common clock 0 */
+ BDK_TRACE(QLM, "Setting N%d.QLM%d to use common clock 0\n", node, qlm);
+ break;
+ case REF_156MHZ:
+ use_clock = 1; /* Common clock 1 */
+ BDK_TRACE(QLM, "Setting N%d.QLM%d to use common clock 1\n", node, qlm);
+ break;
+ default:
+ use_clock = 2; /* External clock */
+ BDK_TRACE(QLM, "Setting N%d.QLM%d to use external clock\n", node, qlm);
+ break;
+ }
+ }
+ else
+ {
+ bdk_error("Update __bdk_qlm_set_reference() for qlm auto config of this chip\n");
+ return;
+ }
+ BDK_CSR_MODIFY(c, node, BDK_GSERX_REFCLK_SEL(qlm),
+ c.s.com_clk_sel = (use_clock != 2);
+ c.s.use_com1 = (use_clock == 1));
+}
+
+/**
+ * For Cavium EVB and EBB board, query the MCU to determine the QLM setup. Applying
+ * any configuration found.
+ *
+ * @param node Node to configure
+ *
+ * @return Zero on success, negative on failure
+ */
+int bdk_qlm_mcu_auto_config(bdk_node_t node)
+{
+ const int MCU_TWSI_BUS = 0;
+ const int MCU_TWSI_ADDRESS = 0x60;
+ int64_t data;
+
+ /* Check the two magic number bytes the MCU should return */
+ data = mcu_read(node, MCU_TWSI_BUS, MCU_TWSI_ADDRESS, 0x00, 1, 1);
+ if (data != 0xa5)
+ {
+ printf("QLM Config: MCU not found, skipping auto configuration\n");
+ return -1;
+ }
+ data = mcu_read(node, MCU_TWSI_BUS, MCU_TWSI_ADDRESS, 0x01, 1, 1);
+ if (data != 0x5a)
+ {
+ bdk_error("QLM Config: MCU magic number incorrect\n");
+ return -1;
+ }
+
+ /* Read the MCU version */
+ int mcu_major = mcu_read(node, MCU_TWSI_BUS, MCU_TWSI_ADDRESS, 0x02, 1, 1);
+ int mcu_minor = mcu_read(node, MCU_TWSI_BUS, MCU_TWSI_ADDRESS, 0x03, 1, 1);
+ BDK_TRACE(QLM, "MCU version %d.%d\n", mcu_major, mcu_minor);
+ if ((mcu_major < 2) || ((mcu_major == 2) && (mcu_minor < 30)))
+ {
+ bdk_error("QLM Config: Unexpected MCU version %d.%d\n", mcu_major, mcu_minor);
+ return -1;
+ }
+
+ /* Find out how many lanes the MCU thinks are available */
+ int lanes = mcu_read(node, MCU_TWSI_BUS, MCU_TWSI_ADDRESS, 0x16, 1, 1);
+ BDK_TRACE(QLM, "MCU says board has %d lanes\n", lanes);
+ int correct_lanes = 0;
+ if (cavium_is_altpkg(CAVIUM_CN88XX))
+ correct_lanes = 22;
+ else if (CAVIUM_IS_MODEL(CAVIUM_CN88XX))
+ correct_lanes = 32;
+ else if (CAVIUM_IS_MODEL(CAVIUM_CN83XX))
+ correct_lanes = 22;
+ else if (CAVIUM_IS_MODEL(CAVIUM_CN81XX))
+ correct_lanes = 8;
+ if (lanes != correct_lanes)
+ {
+ bdk_error("QLM Config: Unexpected number of lanes (%d) from MCU\n", lanes);
+ return -1;
+ }
+
+ int lane = 0;
+ int qlm = 0;
+ while (lane < lanes)
+ {
+ int write_status;
+ int width;
+ int mode;
+ int speed;
+ int refclk;
+ /* TWSI reads from the MCU randomly timeout. Retry a few times on
+ failure to try and recover */
+ int read_tries = 0;
+ do
+ {
+ read_tries++;
+ if (read_tries > 3)
+ {
+ bdk_error("QLM Config: Timeouts reading from MCU\n");
+ return -1;
+ }
+ /* Space request out 20ms */
+ bdk_wait_usec(20000);
+ /* Select the lane we are interested in */
+ write_status = bdk_twsix_write_ia(node, MCU_TWSI_BUS, MCU_TWSI_ADDRESS, 0x16, 1, 1, lane);
+ /* Space request out 20ms */
+ bdk_wait_usec(20000);
+ /* Get the mode */
+ width = mcu_read(node, MCU_TWSI_BUS, MCU_TWSI_ADDRESS, 0x17, 1, 1);
+ mode = mcu_read(node, MCU_TWSI_BUS, MCU_TWSI_ADDRESS, 0x18, 2, 1);
+ speed = mcu_read(node, MCU_TWSI_BUS, MCU_TWSI_ADDRESS, 0x19, 2, 1);
+ refclk = mcu_read(node, MCU_TWSI_BUS, MCU_TWSI_ADDRESS, 0x1a, 1, 1);
+ } while ((write_status < 0) || (width < 0) || (mode < 0) || (speed < 0) || (refclk < 0));
+
+ BDK_TRACE(QLM, "MCU lane %d, width %d, mode 0x%x, speed 0x%x, ref 0x%x\n",
+ lane, width, mode, speed, refclk);
+ if ((width != 0) && (width != 1) && (width != 2) && (width != 4) && (width != 8))
+ {
+ bdk_error("QLM Config: Unexpected interface width (%d) from MCU\n", width);
+ return -1;
+ }
+ /* MCU reports a width of 0 for unconfigured QLMs. It reports a width
+ of 1 for some combinations on CN80XX, and two on others. Convert
+ either 0 or 1 to the actual width, or 2 for CN80XX. Yuck */
+ if ((width == 0) || (width == 1))
+ {
+ if (cavium_is_altpkg(CAVIUM_CN81XX) && (qlm < 2))
+ width = 2;
+ else
+ width = bdk_qlm_get_lanes(node, qlm);
+ }
+ bdk_qlm_modes_t qlm_mode;
+ int qlm_speed = (speed >> 8) * 1000 + (speed & 0xff) * 1000 / 256;
+ int use_ref = 0;
+ bdk_qlm_mode_flags_t qlm_flags = 0;
+ if (mode < 0x4000)
+ {
+ switch (mode)
+ {
+ case 0x0000: /* No Configuration */
+ qlm_mode = BDK_QLM_MODE_DISABLED;
+ break;
+ case 0x0101: /* PCIe Host */
+ qlm_mode = (width == 8) ? BDK_QLM_MODE_PCIE_1X8 :
+ (width == 4) ? BDK_QLM_MODE_PCIE_1X4 :
+ BDK_QLM_MODE_PCIE_1X2;
+ use_ref = REF_100MHZ;
+ break;
+ case 0x0102: /* PCIe Endpoint */
+ qlm_mode = (width == 8) ? BDK_QLM_MODE_PCIE_1X8 :
+ (width == 4) ? BDK_QLM_MODE_PCIE_1X4 :
+ BDK_QLM_MODE_PCIE_1X2;
+ qlm_flags = BDK_QLM_MODE_FLAG_ENDPOINT;
+ use_ref = 0; /* Use the external reference for EP mode */
+ break;
+ case 0x1000: /* SGMII */
+ qlm_mode = (width == 4) ? BDK_QLM_MODE_SGMII_4X1 :
+ (width == 2) ? BDK_QLM_MODE_SGMII_2X1 :
+ BDK_QLM_MODE_SGMII_1X1;
+ use_ref = REF_156MHZ;
+ /* CN80XX parts on EBBs use phy port 2 for SGMII, while QSGMII
+ uses the correct port. Fix this for DLM1 and DLM3 */
+ if (cavium_is_altpkg(CAVIUM_CN81XX))
+ {
+ int bgx = (qlm == 3) ? 1 : 0;
+ uint64_t phy = bdk_config_get_int(BDK_CONFIG_PHY_ADDRESS, 0, bgx, 2);
+ bdk_config_set_int(phy, BDK_CONFIG_PHY_ADDRESS, 0, bgx, 1);
+ }
+ break;
+ case 0x1100: /* QSGMII */
+ qlm_mode = BDK_QLM_MODE_QSGMII_4X1;
+ use_ref = REF_100MHZ;
+ break;
+ case 0x2000: /* XAUI */
+ qlm_mode = BDK_QLM_MODE_XAUI_1X4;
+ use_ref = REF_156MHZ;
+ break;
+ case 0x2100: /* RXAUI */
+ qlm_mode = (width == 2) ? BDK_QLM_MODE_RXAUI_1X2 : BDK_QLM_MODE_RXAUI_2X2;
+ use_ref = REF_156MHZ;
+ break;
+ case 0x2200: /* DXAUI */
+ qlm_mode = BDK_QLM_MODE_XAUI_1X4;
+ use_ref = REF_156MHZ;
+ break;
+ case 0x3001: /* Interlaken */
+ qlm_mode = BDK_QLM_MODE_ILK;
+ use_ref = REF_156MHZ;
+ break;
+ default:
+ bdk_error("QLM Config: Unexpected interface mode (0x%x) from MCU\n", mode);
+ qlm_mode = BDK_QLM_MODE_DISABLED;
+ break;
+ }
+ }
+ else
+ {
+ switch (mode)
+ {
+ case 0x4000: /* SATA */
+ qlm_mode = (width == 2) ? BDK_QLM_MODE_SATA_2X1 : BDK_QLM_MODE_SATA_4X1;
+ use_ref = REF_100MHZ;
+ break;
+ case 0x5001: /* XFI */
+ qlm_mode = (width == 4) ? BDK_QLM_MODE_XFI_4X1 :
+ (width == 2) ? BDK_QLM_MODE_XFI_2X1 :
+ BDK_QLM_MODE_XFI_1X1;
+ use_ref = REF_156MHZ;
+ break;
+ case 0x5002: /* 10G-KR */
+ qlm_mode = (width == 4) ? BDK_QLM_MODE_10G_KR_4X1 :
+ (width == 2) ? BDK_QLM_MODE_10G_KR_2X1 :
+ BDK_QLM_MODE_10G_KR_1X1;
+ use_ref = REF_156MHZ;
+ break;
+ case 0x6001: /* XLAUI */
+ qlm_mode = BDK_QLM_MODE_XLAUI_1X4;
+ use_ref = REF_156MHZ;
+ break;
+ case 0x6002: /* 40G-KR4 */
+ qlm_mode = BDK_QLM_MODE_40G_KR4_1X4;
+ use_ref = REF_156MHZ;
+ break;
+ default:
+ bdk_error("QLM Config: Unexpected interface mode (0x%x) from MCU\n", mode);
+ qlm_mode = BDK_QLM_MODE_DISABLED;
+ break;
+ }
+ }
+ lane += width;
+ do
+ {
+ int internal_qlm = qlm;
+ /* Alternate package parts have different QLM numbers for internal
+ versus external. The MCU uses the external numbers */
+ if (cavium_is_altpkg(CAVIUM_CN88XX))
+ {
+ switch (qlm)
+ {
+ case 0: /* QLM0 -> QLM4 */
+ internal_qlm = 4;
+ break;
+ case 1: /* QLM1 -> QLM5 */
+ internal_qlm = 5;
+ break;
+ case 2: /* QLM2 -> QLM0 */
+ internal_qlm = 0;
+ break;
+ case 3: /* QLM3 -> QLM1 */
+ internal_qlm = 1;
+ break;
+ case 4: /* DLM4 -> QLM2 */
+ internal_qlm = 2;
+ break;
+ case 5: /* DLM5 -> QLM6 */
+ internal_qlm = 6;
+ break;
+ case 6: /* DLM6 -> QLM7 */
+ internal_qlm = 7;
+ break;
+ default:
+ bdk_error("Invalid external QLM%d from MCU\n", qlm);
+ return -1;
+ }
+ }
+ if (qlm_flags & BDK_QLM_MODE_FLAG_ENDPOINT)
+ {
+ BDK_TRACE(QLM, "Skipping N%d.QLM%d mode %s(%d), speed %d, flags 0x%x (EP should already be setup)\n",
+ node, internal_qlm, bdk_qlm_mode_tostring(qlm_mode), qlm_mode, qlm_speed, qlm_flags);
+ }
+ else
+ {
+ BDK_TRACE(QLM, "Setting N%d.QLM%d mode %s(%d), speed %d, flags 0x%x\n",
+ node, internal_qlm, bdk_qlm_mode_tostring(qlm_mode), qlm_mode, qlm_speed, qlm_flags);
+ /* Set the reference clock for this QLM */
+ __bdk_qlm_set_reference(node, internal_qlm, use_ref);
+ if (bdk_qlm_set_mode(node, internal_qlm, qlm_mode, qlm_speed, qlm_flags))
+ return -1;
+ }
+ int num_lanes = bdk_qlm_get_lanes(node, internal_qlm);
+ /* CN86XX looks like two lanes each for DLM4-7 */
+ if (cavium_is_altpkg(CAVIUM_CN88XX) && (qlm >= 4))
+ num_lanes = 2;
+ if (qlm_mode == BDK_QLM_MODE_PCIE_1X8)
+ {
+ /* PCIe x8 is a special case as the QLM config function
+ actually configures both QLMs in one go */
+ qlm++;
+ width -= 8;
+ }
+ else if ((qlm_mode == BDK_QLM_MODE_PCIE_1X4) && (width > num_lanes))
+ {
+ /* PCIe x4 is a special case as the QLM config function
+ actually configures both QLMs in one go */
+ qlm++;
+ width -= 4;
+ }
+ else if (width >= num_lanes)
+ {
+ if (num_lanes == 1)
+ width -= 2; /* Special case for CN80XX */
+ else
+ width -= num_lanes;
+ }
+ else
+ width = 0;
+ qlm++;
+ } while (width > 0);
+ }
+ return 0;
+}
+
+/**
+ * Display the current settings of a QLM lane
+ *
+ * @param node Node the QLM is on
+ * @param qlm QLM to display
+ * @param qlm_lane Lane to use
+ * @param show_tx Display TX parameters
+ * @param show_rx Display RX parameters
+ */
+void bdk_qlm_display_settings(bdk_node_t node, int qlm, int qlm_lane, bool show_tx, bool show_rx)
+{
+ const char *dir_label[] = {"Hold", "Inc", "Dec", "Hold"};
+
+ uint64_t rx_aeq_out_0 = BDK_CSR_READ(node, BDK_GSERX_LANEX_RX_AEQ_OUT_0(qlm, qlm_lane));
+ uint64_t rx_aeq_out_1 = BDK_CSR_READ(node, BDK_GSERX_LANEX_RX_AEQ_OUT_1(qlm, qlm_lane));
+ uint64_t rx_aeq_out_2 = BDK_CSR_READ(node, BDK_GSERX_LANEX_RX_AEQ_OUT_2(qlm, qlm_lane));
+ uint64_t rx_vma_status_0 = BDK_CSR_READ(node, BDK_GSERX_LANEX_RX_VMA_STATUS_0(qlm, qlm_lane));
+ uint64_t rx_vma_status_1 = BDK_CSR_READ(node, BDK_GSERX_LANEX_RX_VMA_STATUS_1(qlm, qlm_lane));
+ uint64_t sds_pin_mon_1 = BDK_CSR_READ(node, BDK_GSERX_LANEX_SDS_PIN_MON_1(qlm, qlm_lane));
+ uint64_t sds_pin_mon_2 = BDK_CSR_READ(node, BDK_GSERX_LANEX_SDS_PIN_MON_2(qlm, qlm_lane));
+ uint64_t br_rxx_eer = BDK_CSR_READ(node, BDK_GSERX_BR_RXX_EER(qlm, qlm_lane));
+
+ printf("N%d.QLM%d Lane %d:\n", node, qlm, qlm_lane);
+ if (show_rx)
+ {
+ printf(" DFE Tap 1: %llu, Tap 2: %lld, Tap 3: %lld, Tap 4: %lld, Tap 5: %lld\n",
+ bdk_extract(rx_aeq_out_1, 0, 5),
+ bdk_extract_smag(rx_aeq_out_1, 5, 9),
+ bdk_extract_smag(rx_aeq_out_1, 10, 14),
+ bdk_extract_smag(rx_aeq_out_0, 0, 4),
+ bdk_extract_smag(rx_aeq_out_0, 5, 9));
+ printf(" Pre-CTLE Gain: %llu, Post-CTLE Gain: %llu, CTLE Peak: %llu, CTLE Pole: %llu\n",
+ bdk_extract(rx_aeq_out_2, 4, 4),
+ bdk_extract(rx_aeq_out_2, 0, 4),
+ bdk_extract(rx_vma_status_0, 2, 4),
+ bdk_extract(rx_vma_status_0, 0, 2));
+ printf(" RX Equalization Tx Directions Hints TXPRE: %s, TXMAIN: %s, TXPOST: %s, Figure of Merit: %llu\n",
+ dir_label[bdk_extract(br_rxx_eer, 0, 2)],
+ dir_label[bdk_extract(br_rxx_eer, 2, 2)],
+ dir_label[bdk_extract(br_rxx_eer, 4, 2)],
+ bdk_extract(br_rxx_eer, 6, 8));
+ }
+ if (show_tx)
+ {
+ printf(" TX Swing: %llu, Pre-emphasis Pre-cursor: %llu, Post-cursor: %llu\n",
+ bdk_extract(sds_pin_mon_1, 1, 5),
+ bdk_extract(sds_pin_mon_2, 0, 4),
+ bdk_extract(sds_pin_mon_2, 4, 5));
+ printf(" TX Boost Enable: %llu, TX Turbo Mode: %llu\n",
+ bdk_extract(sds_pin_mon_2, 10, 1),
+ bdk_extract(sds_pin_mon_2, 9, 1));
+ }
+ printf(" Training-done: %llu\n",
+ bdk_extract(rx_vma_status_1, 7, 1));
+}
+
+/**
+ * Perform RX equalization on a QLM
+ *
+ * @param node Node the QLM is on
+ * @param qlm QLM to perform RX equalization on
+ * @param qlm_lane Lane to use, or -1 for all lanes
+ *
+ * @return Zero on success, negative if any lane failed RX equalization
+ */
+int __bdk_qlm_rx_equalization(bdk_node_t node, int qlm, int qlm_lane)
+{
+ /* Don't touch QLMs is reset or powered down */
+ BDK_CSR_INIT(phy_ctl, node, BDK_GSERX_PHY_CTL(qlm));
+ if (phy_ctl.s.phy_pd || phy_ctl.s.phy_reset)
+ return -1;
+ /* Don't run on PCIe links */
+ if (bdk_qlm_get_mode(node, qlm) <= BDK_QLM_MODE_PCIE_1X8)
+ return -1;
+
+ int fail = 0; /* Bitmask of lanes that failed CDR Lock or Eltrical Idle check */
+ int pending = 0; /* Bitmask of lanes that we're waiting for */
+ int MAX_LANES = bdk_qlm_get_lanes(node, qlm);
+
+ BDK_TRACE(QLM, "N%d.QLM%d: Starting RX equalization on lane %d\n", node, qlm, qlm_lane);
+ for (int lane = 0; lane < MAX_LANES; lane++)
+ {
+ /* Skip lanes we don't care about */
+ if ((qlm_lane != -1) && (qlm_lane != lane))
+ continue;
+ /* Check that the lane has completed CDR lock */
+ BDK_CSR_INIT(eie_detsts, node, BDK_GSERX_RX_EIE_DETSTS(qlm));
+ if (((1 << lane) & eie_detsts.s.cdrlock) == 0)
+ {
+ /* Mark bad so we skip this lane below */
+ fail |= 1 << lane;
+ continue;
+ }
+ /* Enable software control */
+ BDK_CSR_MODIFY(c, node, BDK_GSERX_BR_RXX_CTL(qlm, lane),
+ c.s.rxt_swm = 1);
+ /* Clear the completion flag and initiate a new request */
+ BDK_CSR_MODIFY(c, node, BDK_GSERX_BR_RXX_EER(qlm, lane),
+ c.s.rxt_esv = 0;
+ c.s.rxt_eer = 1);
+ /* Remember that we have to wait for this lane */
+ pending |= 1 << lane;
+ }
+
+ /* Timing a few of these over XFI on CN73XX, each takes 21-23ms. XLAUI
+ was about the same time. DXAUI and RXAUI both took 2-3ms. Put the
+ timeout at 250ms, which is roughly 10x my measurements. */
+ uint64_t timeout = bdk_clock_get_count(BDK_CLOCK_TIME) + bdk_clock_get_rate(node, BDK_CLOCK_TIME) / 4;
+ while (pending)
+ {
+ for (int lane = 0; lane < MAX_LANES; lane++)
+ {
+ int lane_mask = 1 << lane;
+ /* Only check lanes that are pending */
+ if (!(pending & lane_mask))
+ continue;
+ /* Read the registers for checking Electrical Idle / CDR lock and
+ the status of the RX equalization */
+ BDK_CSR_INIT(eie_detsts, node, BDK_GSERX_RX_EIE_DETSTS(qlm));
+ BDK_CSR_INIT(gserx_br_rxx_eer, node, BDK_GSERX_BR_RXX_EER(qlm, lane));
+ /* Mark failure if lane entered Electrical Idle or lost CDR Lock. The
+ bit for the lane will have cleared in either EIESTS or CDRLOCK */
+ if (!(eie_detsts.s.eiests & eie_detsts.s.cdrlock & lane_mask))
+ {
+ fail |= lane_mask;
+ pending &= ~lane_mask;
+ }
+ else if (gserx_br_rxx_eer.s.rxt_esv)
+ {
+ /* Clear pending if RX equalization finished */
+ pending &= ~lane_mask;
+ }
+ }
+ /* Break out of the loop on timeout */
+ if (bdk_clock_get_count(BDK_CLOCK_TIME) > timeout)
+ break;
+ }
+
+ /* Cleanup and report status */
+ for (int lane = 0; lane < MAX_LANES; lane++)
+ {
+ /* Skip lanes we don't care about */
+ if ((qlm_lane != -1) && (qlm_lane != lane))
+ continue;
+ int lane_mask = 1 << lane;
+ /* Get the final RX equalization status */
+ BDK_CSR_INIT(gserx_br_rxx_eer, node, BDK_GSERX_BR_RXX_EER(qlm, lane));
+ /* Disable software control */
+ BDK_CSR_MODIFY(c, node, BDK_GSERX_BR_RXX_CTL(qlm, lane),
+ c.s.rxt_swm = 0);
+ /* Report status */
+ if (fail & lane_mask)
+ {
+ BDK_TRACE(QLM, "N%d.QLM%d: Lane %d RX equalization lost CDR Lock or entered Electrical Idle\n", node, qlm, lane);
+ }
+ else if ((pending & lane_mask) || !gserx_br_rxx_eer.s.rxt_esv)
+ {
+ BDK_TRACE(QLM, "N%d.QLM%d: Lane %d RX equalization timeout\n", node, qlm, lane);
+ fail |= 1 << lane;
+ }
+ else
+ {
+ bdk_qlm_display_settings(node, qlm, lane, false, true);
+ }
+ }
+
+ return (fail) ? -1 : 0;
+}
+
+/**
+ * Configure the TX tuning parameters for a QLM lane. The tuning parameters can
+ * be specified as -1 to maintain their current value
+ *
+ * @param node Node to configure
+ * @param qlm QLM to configure
+ * @param lane Lane to configure
+ * @param tx_swing Transmit swing (coef 0) Range 0-31
+ * @param tx_pre Pre cursor emphasis (Coef -1). Range 0-15
+ * @param tx_post Post cursor emphasis (Coef +1). Range 0-31
+ * @param tx_gain Transmit gain. Range 0-7
+ * @param tx_vboost Transmit voltage boost. Range 0-1
+ *
+ * @return Zero on success, negative on failure
+ */
+int __bdk_qlm_tune_lane_tx(bdk_node_t node, int qlm, int lane, int tx_swing, int tx_pre, int tx_post, int tx_gain, int tx_vboost)
+{
+ /* Check tuning constraints */
+ if ((tx_swing < -1) || (tx_swing > 25))
+ {
+ bdk_error("N%d.QLM%d: Lane %d: Invalid TX_SWING(%d)\n", node, qlm, lane, tx_swing);
+ return -1;
+ }
+ if ((tx_pre < -1) || (tx_pre > 10))
+ {
+ bdk_error("N%d.QLM%d: Lane %d: Invalid TX_PRE(%d)\n", node, qlm, lane, tx_pre);
+ return -1;
+ }
+ if ((tx_post < -1) || (tx_post > 15))
+ {
+ bdk_error("N%d.QLM%d: Lane %d: Invalid TX_POST(%d)\n", node, qlm, lane, tx_post);
+ return -1;
+ }
+ if ((tx_pre >= 0) && (tx_post >= 0) && (tx_swing >= 0) && (tx_pre + tx_post - tx_swing > 2))
+ {
+ bdk_error("N%d.QLM%d: Lane %d: TX_PRE(%d) + TX_POST(%d) - TX_SWING(%d) must be less than or equal to 2\n", node, qlm, lane, tx_pre, tx_post, tx_swing);
+ return -1;
+ }
+ if ((tx_pre >= 0) && (tx_post >= 0) && (tx_swing >= 0) && (tx_pre + tx_post + tx_swing > 35))
+ {
+ bdk_error("N%d.QLM%d: Lane %d: TX_PRE(%d) + TX_POST(%d) + TX_SWING(%d) must be less than or equal to 35\n", node, qlm, lane, tx_pre, tx_post, tx_swing);
+ return -1;
+ }
+
+ if ((tx_gain < -1) || (tx_gain > 7))
+ {
+ bdk_error("N%d.QLM%d: Lane %d: Invalid TX_GAIN(%d). TX_GAIN must be between 0 and 7\n", node, qlm, lane, tx_gain);
+ return -1;
+ }
+
+ if ((tx_vboost < -1) || (tx_vboost > 1))
+ {
+ bdk_error("N%d.QLM%d: Lane %d: Invalid TX_VBOOST(%d). TX_VBOOST must be 0 or 1.\n", node, qlm, lane, tx_vboost);
+ return -1;
+ }
+
+ if ((tx_pre != -1) && (tx_post == -1))
+ {
+ BDK_CSR_INIT(emphasis, node, BDK_GSERX_LANEX_TX_PRE_EMPHASIS(qlm, lane));
+ tx_post = emphasis.s.cfg_tx_premptap >> 4;
+ }
+
+ if ((tx_post != -1) && (tx_pre == -1))
+ {
+ BDK_CSR_INIT(emphasis, node, BDK_GSERX_LANEX_TX_PRE_EMPHASIS(qlm, lane));
+ tx_pre = emphasis.s.cfg_tx_premptap & 0xf;
+ }
+
+ BDK_TRACE(QLM, "N%d.QLM%d: Lane %d: TX_SWING=%d, TX_PRE=%d, TX_POST=%d, TX_GAIN=%d, TX_VBOOST=%d\n",
+ node, qlm, lane, tx_swing, tx_pre, tx_post, tx_gain, tx_vboost);
+
+ /* Manual Tx Swing and Tx Equalization Programming Steps */
+
+ /* 1) Enable Tx swing and Tx emphasis overrides */
+ BDK_CSR_MODIFY(c, node, BDK_GSERX_LANEX_TX_CFG_1(qlm, lane),
+ c.s.tx_swing_ovrrd_en = (tx_swing != -1);
+ c.s.tx_premptap_ovrrd_val = (tx_pre != -1) && (tx_post != -1);
+ c.s.tx_vboost_en_ovrrd_en = (tx_vboost != -1)); /* Vboost override */
+ /* 2) Program the Tx swing and Tx emphasis Pre-cursor and Post-cursor values */
+ if (tx_swing != -1)
+ BDK_CSR_MODIFY(c, node, BDK_GSERX_LANEX_TX_CFG_0(qlm, lane),
+ c.s.cfg_tx_swing = tx_swing);
+ if ((tx_pre != -1) && (tx_post != -1))
+ BDK_CSR_MODIFY(c, node, BDK_GSERX_LANEX_TX_PRE_EMPHASIS(qlm, lane),
+ c.s.cfg_tx_premptap = (tx_post << 4) | tx_pre);
+ /* Apply TX gain settings */
+ if (tx_gain != -1)
+ BDK_CSR_MODIFY(c, node, BDK_GSERX_LANEX_TX_CFG_3(qlm, lane),
+ c.s.pcs_sds_tx_gain = tx_gain);
+ /* Apply TX vboost settings */
+ if (tx_vboost != -1)
+ BDK_CSR_MODIFY(c, node, BDK_GSERX_LANEX_TX_CFG_3(qlm, lane),
+ c.s.cfg_tx_vboost_en = tx_vboost);
+ /* 3) Program override for the Tx coefficient request */
+ BDK_CSR_MODIFY(c, node, BDK_GSERX_LANEX_PCS_CTLIFC_0(qlm, lane),
+ if (((tx_pre != -1) && (tx_post != -1)) || (tx_swing != -1))
+ c.s.cfg_tx_coeff_req_ovrrd_val = 1;
+ if (tx_vboost != -1)
+ c.s.cfg_tx_vboost_en_ovrrd_val = 1;
+ );
+ /* 4) Enable the Tx coefficient request override enable */
+ BDK_CSR_MODIFY(c, node, BDK_GSERX_LANEX_PCS_CTLIFC_2(qlm, lane),
+ if (((tx_pre != -1) && (tx_post != -1)) || (tx_swing != -1))
+ c.s.cfg_tx_coeff_req_ovrrd_en = 1;
+ if (tx_vboost != -1)
+ c.s.cfg_tx_vboost_en_ovrrd_en = 1
+ );
+ /* 5) Issue a Control Interface Configuration Override request to start
+ the Tx equalizer Optimization cycle which applies the new Tx swing
+ and equalization settings */
+ BDK_CSR_MODIFY(c, node, BDK_GSERX_LANEX_PCS_CTLIFC_2(qlm, lane),
+ c.s.ctlifc_ovrrd_req = 1);
+
+ /* 6) Prepare for a subsequent Tx swing and Tx equalization adjustment:
+ a) Disable the Tx coefficient request override enable */
+ BDK_CSR_MODIFY(c, node, BDK_GSERX_LANEX_PCS_CTLIFC_2(qlm, lane),
+ c.s.cfg_tx_coeff_req_ovrrd_en = 0);
+ /* b) Issue a Control Interface Configuration Override request */
+ BDK_CSR_MODIFY(c, node, BDK_GSERX_LANEX_PCS_CTLIFC_2(qlm, lane),
+ c.s.ctlifc_ovrrd_req = 1);
+ /* The new Tx swing and Pre-cursor and Post-cursor settings will now take
+ effect. */
+ return 0;
+}
+
+/**
+ * Some QLM speeds need to override the default tuning parameters
+ *
+ * @param node Node to use in a Numa setup
+ * @param qlm QLM to configure
+ * @param mode Desired mode
+ * @param baud_mhz Desired speed
+ */
+void __bdk_qlm_tune(bdk_node_t node, int qlm, bdk_qlm_modes_t mode, int baud_mhz)
+{
+ /* Note: This function is not called for CCPI. For CCPI tuning, see
+ bdk-init-nz-node.c */
+ /* Tuning parameters override the KR training. Don't apply them for KR links */
+ switch (mode)
+ {
+ case BDK_QLM_MODE_10G_KR_1X1:
+ case BDK_QLM_MODE_10G_KR_2X1:
+ case BDK_QLM_MODE_10G_KR_4X1:
+ case BDK_QLM_MODE_40G_KR4_1X4:
+ return;
+ case BDK_QLM_MODE_PCIE_1X1:
+ case BDK_QLM_MODE_PCIE_2X1:
+ case BDK_QLM_MODE_PCIE_1X2:
+ case BDK_QLM_MODE_PCIE_1X4:
+ case BDK_QLM_MODE_PCIE_1X8:
+ /* Don't tune PCIe Gen3 as it has its own builtin, similar to KR */
+ if (baud_mhz > 5000)
+ return;
+ break;
+ default:
+ break;
+ }
+
+ /* We're apply tuning for all lanes on this QLM */
+ int num_lanes = bdk_qlm_get_lanes(node, qlm);
+ for (int lane = 0; lane < num_lanes; lane++)
+ {
+ /* TX Swing: First read any board specific setting from the environment */
+ int swing = bdk_config_get_int(BDK_CONFIG_QLM_TUNING_TX_SWING, node, qlm, lane);
+ /* If no setting, use hard coded generic defaults */
+ if (swing == -1)
+ {
+ if (baud_mhz == 6250)
+ {
+ /* Email from Brendan Metzner about RXAUI around 2/7/2016 */
+ swing = 0x12;
+ }
+ else if (baud_mhz == 10312)
+ {
+ /* From lab measurements of EBB8800 at 10.3125G */
+ swing = 0xd;
+ }
+ }
+
+ /* TX Premptap: First read any board specific setting from the environment */
+ int premptap = bdk_config_get_int(BDK_CONFIG_QLM_TUNING_TX_PREMPTAP, node, qlm, lane);
+ /* If no setting, use hard coded generic defaults */
+ if (premptap == -1)
+ {
+ if (baud_mhz == 6250)
+ {
+ /* From lab measurements of EBB8800 at 6.25G */
+ premptap = 0xa0;
+ }
+ else if (baud_mhz == 10312)
+ {
+ /* From lab measurements of EBB8800 at 10.3125G */
+ premptap = 0xd0;
+ }
+ }
+
+ int tx_pre = (premptap == -1) ? -1 : premptap & 0xf;
+ int tx_post = (premptap == -1) ? -1 : premptap >> 4;
+ int gain = bdk_config_get_int(BDK_CONFIG_QLM_TUNING_TX_GAIN, node, qlm, lane);
+ int vboost = bdk_config_get_int(BDK_CONFIG_QLM_TUNING_TX_VBOOST, node, qlm, lane);
+
+ __bdk_qlm_tune_lane_tx(node, qlm, lane, swing, tx_pre, tx_post, gain, vboost);
+
+ /* Email from Brendan Metzner about RXAUI around 2/7/2016 suggested the
+ following setting for RXAUI at 6.25G with both PHY or cable. I'm
+ applying it to all lanes running at 6.25G */
+ if (baud_mhz == 6250)
+ {
+ /* This is changing the Q/QB error sampler 0 threshold from 0xD
+ to 0xF */
+ BDK_CSR_MODIFY(c, node, BDK_GSERX_LANEX_RX_CFG_4(qlm, lane),
+ c.s.cfg_rx_errdet_ctrl = 0xcf6f);
+ }
+ }
+}
+
+/**
+ * Disables DFE for the specified QLM lane(s).
+ * This function should only be called for low-loss channels.
+ *
+ * @param node Node to configure
+ * @param qlm QLM to configure
+ * @param lane Lane to configure, or -1 for all lanes
+ */
+void __bdk_qlm_dfe_disable(int node, int qlm, int lane)
+{
+ int num_lanes = bdk_qlm_get_lanes(node, qlm);
+ int l;
+
+ for (l = 0; l < num_lanes; l++) {
+ if ((lane != -1) && (lane != l))
+ continue;
+ /* 1. Write GSERX_LANEx_RX_LOOP_CTRL = 0x0270 (var "loop_ctrl" with bits 8 & 1 cleared).
+ * bit<1> dfe_en_byp = 1'b0 */
+ BDK_CSR_MODIFY(c, node, BDK_GSERX_LANEX_RX_LOOP_CTRL(qlm, l),
+ c.s.cfg_rx_lctrl = c.s.cfg_rx_lctrl & 0x3fd);
+
+ /* 2. Write GSERX_LANEx_RX_VALBBD_CTRL_1 = 0x0000 (var "ctrl1" with all bits cleared)
+ * bits<14:11> CFG_RX_DFE_C3_MVAL = 4'b0000
+ * bit<10> CFG_RX_DFE_C3_MSGN = 1'b0
+ * bits<9:6> CFG_RX_DFE_C2_MVAL = 4'b0000
+ * bit<5> CFG_RX_DFE_C2_MSGN = 1'b0
+ * bits<4:1> CFG_RX_DFE_C1_MVAL = 5'b0000
+ * bits<0> CFG_RX_DFE_C1_MSGN = 1'b0 */
+ BDK_CSR_MODIFY(c, node, BDK_GSERX_LANEX_RX_VALBBD_CTRL_1(qlm, l),
+ c.s.dfe_c3_mval = 0;
+ c.s.dfe_c3_msgn = 0;
+ c.s.dfe_c2_mval = 0;
+ c.s.dfe_c2_msgn = 0;
+ c.s.dfe_c1_mval = 0;
+ c.s.dfe_c1_msgn = 0);
+
+ /* 3. Write GSERX_LANEx_RX_VALBBD_CTRL_0 = 0x2400 (var "ctrl0" with following bits set/cleared)
+ * bits<11:10> CFG_RX_DFE_GAIN = 0x1
+ * bits<9:6> CFG_RX_DFE_C5_MVAL = 4'b0000
+ * bit<5> CFG_RX_DFE_C5_MSGN = 1'b0
+ * bits<4:1> CFG_RX_DFE_C4_MVAL = 4'b0000
+ * bit<0> CFG_RX_DFE_C4_MSGN = 1'b0 */
+ BDK_CSR_MODIFY(c, node, BDK_GSERX_LANEX_RX_VALBBD_CTRL_0(qlm, l),
+ c.s.dfe_gain = 0x1;
+ c.s.dfe_c5_mval = 0;
+ c.s.dfe_c5_msgn = 0;
+ c.s.dfe_c4_mval = 0;
+ c.s.dfe_c4_msgn = 0);
+
+ /* 4. Write GSER(0..13)_LANE(0..3)_RX_VALBBD_CTRL_2 = 0x003F //enable DFE tap overrides
+ * bit<5> dfe_ovrd_en = 1
+ * bit<4> dfe_c5_ovrd_val = 1
+ * bit<3> dfe_c4_ovrd_val = 1
+ * bit<2> dfe_c3_ovrd_val = 1
+ * bit<1> dfe_c2_ovrd_val = 1
+ * bit<0> dfe_c1_ovrd_val = 1
+ */
+ BDK_CSR_MODIFY(c, node, BDK_GSERX_LANEX_RX_VALBBD_CTRL_2(qlm, l),
+ c.s.dfe_ovrd_en = 0x1;
+ c.s.dfe_c5_ovrd_val = 0x1;
+ c.s.dfe_c4_ovrd_val = 0x1;
+ c.s.dfe_c3_ovrd_val = 0x1;
+ c.s.dfe_c2_ovrd_val = 0x1;
+ c.s.dfe_c1_ovrd_val = 0x1);
+
+ }
+}
+
+/**
+ * Check if a specific lane is using KR training. This is used by low level GSER
+ * code to remember which QLMs and lanes need to support KR training for BGX. The
+ * hardware doesn't have a bit set aside to record this, so we repurpose the
+ * register GSERX_SCRATCH.
+ *
+ * @param node Node to check
+ * @param qlm QLM to check
+ * @param lane Lane to check
+ *
+ * @return True if this lane uses KR with BGX, false otherwise
+ */
+bool __bdk_qlm_is_lane_kr(bdk_node_t node, int qlm, int lane)
+{
+ uint64_t mask = BDK_CSR_READ(node, BDK_GSERX_SCRATCH(qlm));
+ return 1 & (mask >> lane);
+}
+
+/**
+ * Set if a specific lane is using KR training. This is used by low level GSER
+ * code to remember which QLMs and lanes need to support KR training for BGX. The
+ * hardware doesn't have a bit set aside to record this, so we repurpose the
+ * register GSERX_SCRATCH.
+ *
+ * @param node Node to set
+ * @param qlm QLM to set
+ * @param lane Lane to set
+ * @param is_kr KR (true) or XFI/XLAUI (false)
+ */
+void __bdk_qlm_set_lane_kr(bdk_node_t node, int qlm, int lane, bool is_kr)
+{
+ uint64_t mask = BDK_CSR_READ(node, BDK_GSERX_SCRATCH(qlm));
+ if (is_kr)
+ mask |= 1 << lane;
+ else
+ mask &= ~(1 << lane);
+ BDK_CSR_WRITE(node, BDK_GSERX_SCRATCH(qlm), mask);
+}
diff --git a/src/vendorcode/cavium/bdk/libbdk-hal/qlm/bdk-qlm-errata-cn8xxx.c b/src/vendorcode/cavium/bdk/libbdk-hal/qlm/bdk-qlm-errata-cn8xxx.c
new file mode 100644
index 0000000000..a7602de758
--- /dev/null
+++ b/src/vendorcode/cavium/bdk/libbdk-hal/qlm/bdk-qlm-errata-cn8xxx.c
@@ -0,0 +1,398 @@
+/***********************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-gser.h"
+#include "libbdk-arch/bdk-csrs-rst.h"
+#include "libbdk-hal/qlm/bdk-qlm-errata-cn8xxx.h"
+
+/**
+ * Delay for the specified microseconds. When this code runs on secondary nodes
+ * before full init, the normal bdk-clock functions do not work. This function
+ * serves as a replacement that runs everywhere.
+ *
+ * @param usec Microseconds to wait
+ */
+static void wait_usec(bdk_node_t node, uint64_t usec)
+{
+ const uint64_t REF_CLOCK = 50000000; /* This is currently defined to be 50Mhz */
+ uint64_t refclock = BDK_CSR_READ(node, BDK_RST_REF_CNTR);
+ uint64_t timeout = refclock + REF_CLOCK * usec / 1000000;
+ while (refclock < timeout)
+ {
+ refclock = BDK_CSR_READ(node, BDK_RST_REF_CNTR);
+ }
+}
+
+/**
+ * Errata GSER-25992 - RX EQ Default Settings Update<p>
+ * For all GSER and all lanes when not PCIe EP:
+ * set GSER()_LANE()_RX_CFG_4[CFG_RX_ERRDET_CTRL<13:8>] = 13 (decimal)
+ * set GSER()_LANE()_RX_CTLE_CTRL[PCS_SDS_RX_CTLE_BIAS_CTRL] = 3
+ * Applied when SERDES are configured for 8G and 10G.<p>
+ * Applies to:
+ * CN88XX pass 1.x
+ * Fixed in hardware:
+ * CN88XX pass 2.x
+ * CN81XX
+ * CN83XX
+ *
+ * @param node Node to apply errata fix for
+ * @param qlm QLM to apply errata fix to
+ * @param baud_mhz QLM speed in Mhz
+ *
+ * @return Zero on success, negative on failure
+ */
+int __bdk_qlm_errata_gser_25992(bdk_node_t node, int qlm, int baud_mhz)
+{
+ if (!CAVIUM_IS_MODEL(CAVIUM_CN88XX_PASS1_X))
+ return 0;
+ if (baud_mhz < 8000)
+ return 0;
+
+ int num_lanes = 4; /* Only applies to CN88XX, where always 4 lanes */
+ for (int lane = 0; lane < num_lanes; lane++)
+ {
+ BDK_CSR_MODIFY(c, node, BDK_GSERX_LANEX_RX_CTLE_CTRL(qlm, lane),
+ c.s.pcs_sds_rx_ctle_bias_ctrl = 3);
+ BDK_CSR_MODIFY(c, node, BDK_GSERX_LANEX_RX_CFG_4(qlm, lane),
+ c.s.cfg_rx_errdet_ctrl = 0xcd6f);
+ }
+ return 0;
+}
+
+/**
+ * (GSER-26150) 10G PHY PLL Temperature Failure
+ *
+ * 10 Gb temperature excursions can cause lock failure. Change
+ * the calibration point of the VCO at start up to shift some
+ * available range of the VCO from -deltaT direction to the
+ * +deltaT ramp direction allowing a greater range of VCO
+ * temperatures before experiencing the failure.
+ *
+ * Applies to:
+ * CN88XX pass 1.x
+ * Fix in hardware:
+ * CN88XX pass 2.x
+ * CN81XX
+ * CN83XX
+ *
+ * Only applies to QLMs running 8G and 10G
+ *
+ * @param node Node to apply errata to
+ * @param qlm QLM to apply errata fix to
+ *
+ * @return Zero on success, negative on failure
+ */
+int __bdk_qlm_errata_gser_26150(bdk_node_t node, int qlm, int baud_mhz)
+{
+ if (!CAVIUM_IS_MODEL(CAVIUM_CN88XX_PASS1_X))
+ return 0;
+ if (baud_mhz < 8000)
+ return 0;
+
+ int num_lanes = 4; /* Only applies to CN88XX, where always 4 lanes */
+
+ BDK_CSR_INIT(gserx_cfg, node, BDK_GSERX_CFG(qlm));
+ if (gserx_cfg.s.pcie)
+ {
+ /* Update PLL parameters */
+ /* Step 1: Set GSER()_GLBL_PLL_CFG_3[PLL_VCTRL_SEL_LCVCO_VAL] = 0x2, and
+ GSER()_GLBL_PLL_CFG_3[PCS_SDS_PLL_VCO_AMP] = 0 */
+ BDK_CSR_MODIFY(c, node, BDK_GSERX_GLBL_PLL_CFG_3(qlm),
+ c.s.pll_vctrl_sel_lcvco_val = 0x2;
+ c.s.pcs_sds_pll_vco_amp = 0);
+ /* Step 2: Set GSER()_GLBL_MISC_CONFIG_1[PCS_SDS_TRIM_CHP_REG] = 0x2. */
+ BDK_CSR_MODIFY(c, node, BDK_GSERX_GLBL_MISC_CONFIG_1(qlm),
+ c.s.pcs_sds_trim_chp_reg = 0x2);
+ return 0;
+ }
+
+ /* Applying this errata twice causes problems */
+ BDK_CSR_INIT(pll_cfg_3, node, BDK_GSERX_GLBL_PLL_CFG_3(qlm));
+ if (pll_cfg_3.s.pll_vctrl_sel_lcvco_val == 0x2)
+ return 0;
+
+ /* Put PHY in P2 Power-down state Need to Power down all lanes in a
+ QLM/DLM to force PHY to P2 state */
+ for (int i=0; i<num_lanes; i++)
+ {
+ /* Step 1: Set GSER()_LANE(lane_n)_PCS_CTLIFC_0[CFG_TX_PSTATE_REQ_OVERRD_VAL] = 0x3
+ Select P2 power state for Tx lane */
+ BDK_CSR_MODIFY(c, node, BDK_GSERX_LANEX_PCS_CTLIFC_0(qlm, i),
+ c.s.cfg_tx_pstate_req_ovrrd_val = 0x3);
+ /* Step 2: Set GSER()_LANE(lane_n)_PCS_CTLIFC_1[CFG_RX_PSTATE_REQ_OVERRD_VAL] = 0x3
+ Select P2 power state for Rx lane */
+ BDK_CSR_MODIFY(c, node, BDK_GSERX_LANEX_PCS_CTLIFC_1(qlm, i),
+ c.s.cfg_rx_pstate_req_ovrrd_val = 0x3);
+ /* Step 3: Set GSER()_LANE(lane_n)_PCS_CTLIFC_2[CFG_TX_PSTATE_REQ_OVRRD_EN] = 1
+ Enable Tx power state override and Set
+ GSER()_LANE(lane_n)_PCS_CTLIFC_2[CFG_RX_PSTATE_REQ_OVRRD_EN] = 1
+ Enable Rx power state override */
+ BDK_CSR_MODIFY(c, node, BDK_GSERX_LANEX_PCS_CTLIFC_2(qlm, i),
+ c.s.cfg_tx_pstate_req_ovrrd_en = 0x1;
+ c.s.cfg_rx_pstate_req_ovrrd_en = 0X1);
+ /* Step 4: Set GSER()_LANE(lane_n)_PCS_CTLIFC_2[CTLIFC_OVRRD_REQ] = 1
+ Start the CTLIFC override state machine */
+ BDK_CSR_MODIFY(c, node, BDK_GSERX_LANEX_PCS_CTLIFC_2(qlm, i),
+ c.s.ctlifc_ovrrd_req = 0x1);
+ }
+
+ /* Update PLL parameters */
+ /* Step 5: Set GSER()_GLBL_PLL_CFG_3[PLL_VCTRL_SEL_LCVCO_VAL] = 0x2, and
+ GSER()_GLBL_PLL_CFG_3[PCS_SDS_PLL_VCO_AMP] = 0 */
+ BDK_CSR_MODIFY(c, node, BDK_GSERX_GLBL_PLL_CFG_3(qlm),
+ c.s.pll_vctrl_sel_lcvco_val = 0x2;
+ c.s.pcs_sds_pll_vco_amp = 0);
+ /* Step 6: Set GSER()_GLBL_MISC_CONFIG_1[PCS_SDS_TRIM_CHP_REG] = 0x2. */
+ BDK_CSR_MODIFY(c, node, BDK_GSERX_GLBL_MISC_CONFIG_1(qlm),
+ c.s.pcs_sds_trim_chp_reg = 0x2);
+ /* Wake up PHY and transition to P0 Power-up state to bring-up the lanes,
+ need to wake up all PHY lanes */
+ for (int i=0; i<num_lanes; i++)
+ {
+ /* Step 7: Set GSER()_LANE(lane_n)_PCS_CTLIFC_0[CFG_TX_PSTATE_REQ_OVERRD_VAL] = 0x0
+ Select P0 power state for Tx lane */
+ BDK_CSR_MODIFY(c, node, BDK_GSERX_LANEX_PCS_CTLIFC_0(qlm, i),
+ c.s.cfg_tx_pstate_req_ovrrd_val = 0x0);
+ /* Step 8: Set GSER()_LANE(lane_n)_PCS_CTLIFC_1[CFG_RX_PSTATE_REQ_OVERRD_VAL] = 0x0
+ Select P0 power state for Rx lane */
+ BDK_CSR_MODIFY(c, node, BDK_GSERX_LANEX_PCS_CTLIFC_1(qlm, i),
+ c.s.cfg_rx_pstate_req_ovrrd_val = 0x0);
+ /* Step 9: Set GSER()_LANE(lane_n)_PCS_CTLIFC_2[CFG_TX_PSTATE_REQ_OVRRD_EN] = 1
+ Enable Tx power state override and Set
+ GSER()_LANE(lane_n)_PCS_CTLIFC_2[CFG_RX_PSTATE_REQ_OVRRD_EN] = 1
+ Enable Rx power state override */
+ BDK_CSR_MODIFY(c, node, BDK_GSERX_LANEX_PCS_CTLIFC_2(qlm, i),
+ c.s.cfg_tx_pstate_req_ovrrd_en = 0x1;
+ c.s.cfg_rx_pstate_req_ovrrd_en = 0X1);
+ /* Step 10: Set GSER()_LANE(lane_n)_PCS_CTLIFC_2[CTLIFC_OVRRD_REQ] = 1
+ Start the CTLIFC override state machine */
+ BDK_CSR_MODIFY(c, node, BDK_GSERX_LANEX_PCS_CTLIFC_2(qlm, i),
+ c.s.ctlifc_ovrrd_req = 0x1);
+ }
+
+ /* Step 11: Wait 10 msec */
+ wait_usec(node, 10000);
+
+ /* Release Lane Tx/Rx Power state override enables. */
+ for (int i=0; i<num_lanes; i++)
+ {
+ /* Step 12: Set GSER()_LANE(lane_n)_PCS_CTLIFC_2[CFG_TX_PSTATE_REQ_OVRRD_EN] = 0
+ Disable Tx power state override and Set
+ GSER()_LANE(lane_n)_PCS_CTLIFC_2[CFG_RX_PSTATE_REQ_OVRRD_EN] = 0
+ Disable Rx power state override */
+ BDK_CSR_MODIFY(c, node, BDK_GSERX_LANEX_PCS_CTLIFC_2(qlm, i),
+ c.s.cfg_tx_pstate_req_ovrrd_en = 0x0;
+ c.s.cfg_rx_pstate_req_ovrrd_en = 0X0);
+ }
+ /* Step 13: Poll GSER()_PLL_STAT.[PLL_LOCK] = 1
+ Poll and check that PLL is locked */
+ if (BDK_CSR_WAIT_FOR_FIELD(node, BDK_GSERX_PLL_STAT(qlm), pll_lock, ==, 1, 10000))
+ {
+ bdk_error("QLM%d: Timeout waiting for GSERX_PLL_STAT[pll_lock]\n", qlm);
+ return -1;
+ }
+
+ /* Step 14: Poll GSER()_QLM_STAT.[RST_RDY] = 1
+ Poll and check that QLM/DLM is Ready */
+ if (BDK_CSR_WAIT_FOR_FIELD(node, BDK_GSERX_QLM_STAT(qlm), rst_rdy, ==, 1, 10000))
+ {
+ bdk_error("QLM%d: Timeout waiting for GSERX_QLM_STAT[rst_rdy]\n", qlm);
+ return -1;
+ }
+ return 0;
+}
+
+/**
+ * Errata (GSER-26636) 10G-KR/40G-KR - Inverted Tx Coefficient Direction Change
+ * Applied to all 10G standards (required for KR) but also applied to other
+ * standards in case software training is used.
+ * Applies to:
+ * CN88XX pass 1.x
+ * Fixed in hardware:
+ * CN88XX pass 2.x
+ * CN81XX
+ * CN83XX
+ *
+ * @param node Node to apply errata fix for
+ * @param qlm QLM to apply errata fix to
+ * @param baud_mhz QLM speed in Mhz
+ *
+ * @return Zero on success, negative on failure
+ */
+int __bdk_qlm_errata_gser_26636(bdk_node_t node, int qlm, int baud_mhz)
+{
+ if (!CAVIUM_IS_MODEL(CAVIUM_CN88XX_PASS1_X))
+ return 0;
+
+ BDK_CSR_MODIFY(c, node, BDK_GSERX_RX_TXDIR_CTRL_1(qlm),
+ c.s.rx_precorr_chg_dir = 1;
+ c.s.rx_tap1_chg_dir = 1);
+ return 0;
+}
+
+/**
+ * (GSER-27140) SERDES has temperature drift sensitivity in the RX EQ<p>
+ * SERDES temperature drift sensitivity in receiver. Issues have
+ * been found with the Bit Error Rate (BER) reliability of
+ * 10GBASE-KR links over the commercial temperature range (0 to 100C),
+ * especially when subjected to rapid thermal ramp stress testing.
+ * (See HRM for corresponding case temperature requirements for each speed grade.)<p>
+ * Applies to:
+ * CN88XX pass 1.x
+ * CN88XX pass 2.x
+ * CN83XX pass 1.x
+ * CN81XX pass 1.x
+ * Fixed in hardware:
+ * TBD<p>
+ * Only applies to QLMs running 10G
+ *
+ * @param node Note to apply errata fix to
+ * @param qlm QLM to apply errata fix to
+ * @param baud_mhz QLM baud rate in Mhz
+ * @param channel_loss
+ * Insertion loss at Nyquist rate (e.g. 5.125Ghz for XFI/XLAUI) in dB
+ *
+ * @return Zero on success, negative on failure
+ */
+int __bdk_qlm_errata_gser_27140(bdk_node_t node, int qlm, int baud_mhz, int channel_loss)
+{
+ if (baud_mhz != 10312)
+ return 0;
+
+ /* A channel loss of -1 means the loss is unknown. A short channel is
+ considered to have loss between 0 and 10 dB */
+ bool short_channel = (channel_loss >= 0) && (channel_loss <= 10);
+
+ /* I. For each GSER QLM: */
+ /* Workaround GSER-27140: */
+ /* (1) GSER-26150 = Applied by the caller */
+ /* (2) Write GSER()_LANE_VMA_FINE_CTRL_0[RX_SDLL_IQ_MAX_FINE] = 0xE */
+ /* (3) Write GSER()_LANE_VMA_FINE_CTRL_0[RX_SDLL_IQ_MIN_FINE] = 0x8 */
+ /* (4) Write GSER()_LANE_VMA_FINE_CTRL_0[RX_SDLL_IQ_STEP_FINE] = 0x2 */
+ /* (5) Write GSER()_LANE_VMA_FINE_CTRL_0[VMA_WINDOW_WAIT_FINE] = 0x5 */
+ /* (6) Write GSER()_LANE_VMA_FINE_CTRL_0[LMS_WAIT_TIME_FINE] = 0x5 */
+ BDK_CSR_MODIFY(c, node, BDK_GSERX_LANE_VMA_FINE_CTRL_0(qlm),
+ c.s.rx_sdll_iq_max_fine = 0xE;
+ c.s.rx_sdll_iq_min_fine = 0x8;
+ c.s.rx_sdll_iq_step_fine = 0x2;
+ c.s.vma_window_wait_fine = 0x5;
+ c.s.lms_wait_time_fine = 0x5);
+ /* (7) Write GSER()_LANE_VMA_FINE_CTRL_2[RX_PRECTLE_GAIN_MAX_FINE] = 0xB */
+ /* (8) Write GSER()_LANE_VMA_FINE_CTRL_2[RX_PRECTLE_GAIN_MIN_FINE] = 0x6(long) or 0x0(short) */
+ BDK_CSR_MODIFY(c, node, BDK_GSERX_LANE_VMA_FINE_CTRL_2(qlm),
+ c.s.rx_prectle_gain_max_fine = 0xB;
+ c.s.rx_prectle_gain_min_fine = short_channel ? 0x0 : 0x6);
+ /* (9) Write GSER()_RX_TXDIR_CTRL_0[RX_BOOST_LO_THRES] = 0x4 */
+ /* (10) Write GSER()_RX_TXDIR_CTRL_0[RX_BOOST_HI_THRES] = 0xB */
+ /* (11) Write GSER()_RX_TXDIR_CTRL_0[RX_BOOST_HI_VAL] = 0xF */
+ BDK_CSR_MODIFY(c, node, BDK_GSERX_RX_TXDIR_CTRL_0(qlm),
+ c.s.rx_boost_lo_thrs = 0x4;
+ c.s.rx_boost_hi_thrs = 0xB;
+ c.s.rx_boost_hi_val = 0xF);
+ /* (12) Write GSER()_RX_TXDIR_CTRL_1[RX_TAP1_LO_THRS] = 0x8 */
+ /* (13) Write GSER()_RX_TXDIR_CTRL_1[RX_TAP1_HI_THRS] = 0x17 */
+ BDK_CSR_MODIFY(c, node, BDK_GSERX_RX_TXDIR_CTRL_1(qlm),
+ c.s.rx_tap1_lo_thrs = 0x8;
+ c.s.rx_tap1_hi_thrs = 0x17);
+
+ /* (14) Write GSER()_EQ_WAIT_TIME[RXEQ_WAIT_CNT] = 0x6 */
+ BDK_CSR_MODIFY(c, node, BDK_GSERX_EQ_WAIT_TIME(qlm),
+ c.s.rxeq_wait_cnt = 0x6);
+ /* (15) Write GSER()_RX_TXDIR_CTRL_2[RX_PRECORR_HI_THRS] = 0xC0 */
+ /* (16) Write GSER()_RX_TXDIR_CTRL_2[RX_PRECORR_LO_THRS] = 0x40 */
+ BDK_CSR_MODIFY(c, node, BDK_GSERX_RX_TXDIR_CTRL_2(qlm),
+ c.s.rx_precorr_hi_thrs = 0xc0;
+ c.s.rx_precorr_lo_thrs = 0x40);
+
+ /* We can't call the normal bdk-qlm function as it uses pointers that
+ don't work when running in secondary nodes before CCPI is up */
+ int num_lanes = 4;
+ if (CAVIUM_IS_MODEL(CAVIUM_CN81XX) || (CAVIUM_IS_MODEL(CAVIUM_CN83XX) && (qlm >= 4)))
+ num_lanes = 2;
+
+ /* II. For each GSER QLM SerDes lane: */
+ /* Establish typical values, which are already reset values in pass 2: */
+ for (int lane = 0; lane < num_lanes; lane++)
+ {
+ /* (17) For each GSER lane in the 10GBASE-KR link: */
+ /* (a) Write GSER()_LANE()_RX_VALBBD_CTRL_0[AGC_GAIN] = 0x3 */
+ /* (b) Write GSER()_LANE()_RX_VALBBD_CTRL_0[DFE_GAIN] = 0x2 */
+ BDK_CSR_MODIFY(c, node, BDK_GSERX_LANEX_RX_VALBBD_CTRL_0(qlm, lane),
+ c.s.agc_gain = 0x3;
+ c.s.dfe_gain = 0x2);
+ }
+
+ /* III. The GSER QLM SerDes Lanes are now ready. */
+ return 0;
+}
+
+/**
+ * Errata GSER-27882 -GSER 10GBASE-KR Transmit Equalizer
+ * Training may not update PHY Tx Taps. This function is not static
+ * so we can share it with BGX KR
+ * Applies to:
+ * CN88XX pass 1.x, 2.0, 2.1
+ * Fixed in hardware:
+ * CN88XX pass 2.2 and higher
+ * CN81XX
+ * CN83XX
+ *
+ * @param node Node to apply errata fix for
+ * @param qlm QLM to apply errata fix to
+ * @param lane
+ *
+ * @return Zero on success, negative on failure
+ */
+int __bdk_qlm_errata_gser_27882(bdk_node_t node, int qlm, int lane)
+{
+ /* Toggle Toggle Tx Coeff Req override to force an update */
+ BDK_CSR_MODIFY(c, node, BDK_GSERX_LANEX_PCS_CTLIFC_0(qlm, lane),
+ c.s.cfg_tx_coeff_req_ovrrd_val = 1);
+ BDK_CSR_MODIFY(c, node, BDK_GSERX_LANEX_PCS_CTLIFC_2(qlm, lane),
+ c.s.cfg_tx_coeff_req_ovrrd_en = 1);
+ BDK_CSR_MODIFY(c, node, BDK_GSERX_LANEX_PCS_CTLIFC_2(qlm, lane),
+ c.s.ctlifc_ovrrd_req = 1);
+ BDK_CSR_MODIFY(c, node, BDK_GSERX_LANEX_PCS_CTLIFC_2(qlm, lane),
+ c.s.cfg_tx_coeff_req_ovrrd_en = 0);
+ BDK_CSR_MODIFY(c, node, BDK_GSERX_LANEX_PCS_CTLIFC_2(qlm, lane),
+ c.s.ctlifc_ovrrd_req = 1);
+ return 0;
+}
+
diff --git a/src/vendorcode/cavium/bdk/libbdk-hal/qlm/bdk-qlm-margin-cn8xxx.c b/src/vendorcode/cavium/bdk/libbdk-hal/qlm/bdk-qlm-margin-cn8xxx.c
new file mode 100644
index 0000000000..c970f2189e
--- /dev/null
+++ b/src/vendorcode/cavium/bdk/libbdk-hal/qlm/bdk-qlm-margin-cn8xxx.c
@@ -0,0 +1,271 @@
+/***********************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-gser.h"
+#include "libbdk-hal/if/bdk-if.h"
+#include "libbdk-hal/bdk-qlm.h"
+#include "libbdk-hal/bdk-utils.h"
+
+/* This code is an optional part of the BDK. It is only linked in
+ if BDK_REQUIRE() needs it */
+BDK_REQUIRE_DEFINE(QLM_MARGIN);
+
+typedef union
+{
+ struct
+ {
+ uint64_t rx_os_mvalbbd_2 :16;
+ uint64_t rx_os_mvalbbd_1 :16;
+ uint64_t reserved_63_32 :32;
+
+ } s;
+ struct
+ {
+ uint64_t Qb :6;
+ uint64_t Q :6;
+ uint64_t Lb :6; // Spans the two registers
+ uint64_t L :6;
+ uint64_t qerr0 :6;
+ int64_t reserved_63_30 :34;
+ } f;
+ uint64_t u;
+} rx_os_mvalbbd_t;
+
+int __bdk_disable_ccpi_error_report = 0;
+
+static int convert_to_signed_mag(int source)
+{
+ /* Synopsis encoded sign in an unexpected way. 0=negative and 1=positive
+ So bit 5 should be 0 for negative numbers, 1 for positive numbers */
+ if (source < 0)
+ source = -source;
+ else
+ source |= 0x20;
+ return source;
+}
+
+static rx_os_mvalbbd_t get_current_settings(bdk_node_t node, int qlm, int qlm_lane)
+{
+ rx_os_mvalbbd_t mvalbbd;
+ mvalbbd.u = 0;
+
+ BDK_CSR_INIT(rx_cfg_1, node, BDK_GSERX_LANEX_RX_CFG_1(qlm, qlm_lane));
+ if (!rx_cfg_1.s.pcs_sds_rx_os_men)
+ {
+ /* Get the current settings */
+ BDK_CSR_INIT(rx_os_out_1, node, BDK_GSERX_LANEX_RX_OS_OUT_1(qlm, qlm_lane));
+ BDK_CSR_INIT(rx_os_out_2, node, BDK_GSERX_LANEX_RX_OS_OUT_2(qlm, qlm_lane));
+ BDK_CSR_INIT(rx_os_out_3, node, BDK_GSERX_LANEX_RX_OS_OUT_3(qlm, qlm_lane));
+ int qerr0 = bdk_extracts(rx_os_out_1.u, 0, 6);
+ int lb = bdk_extracts(rx_os_out_2.u, 0, 6);
+ int l = bdk_extracts(rx_os_out_2.u, 6, 6);
+ int qb = bdk_extracts(rx_os_out_3.u, 0, 6);
+ int q = bdk_extracts(rx_os_out_3.u, 6, 6);
+ /* Enable the override with the current values */
+ mvalbbd.f.Qb = convert_to_signed_mag(qb);
+ mvalbbd.f.Q = convert_to_signed_mag(q);
+ mvalbbd.f.Lb = convert_to_signed_mag(lb);
+ mvalbbd.f.L = convert_to_signed_mag(l);
+ mvalbbd.f.qerr0 = convert_to_signed_mag(qerr0);
+ }
+ else
+ {
+ BDK_CSR_INIT(mvalbbd_1, node, BDK_GSERX_LANEX_RX_OS_MVALBBD_1(qlm, qlm_lane));
+ mvalbbd.s.rx_os_mvalbbd_1 = mvalbbd_1.s.pcs_sds_rx_os_mval;
+ BDK_CSR_INIT(mvalbbd_2, node, BDK_GSERX_LANEX_RX_OS_MVALBBD_2(qlm, qlm_lane));
+ mvalbbd.s.rx_os_mvalbbd_2 = mvalbbd_2.s.pcs_sds_rx_os_mval;
+ }
+ //printf("qerr0=%d, lb=%d, l=%d, qb=%d, q=%d\n",
+ // mvalbbd.f.qerr0, mvalbbd.f.Lb, mvalbbd.f.L, mvalbbd.f.Qb, mvalbbd.f.Q);
+ return mvalbbd;
+}
+
+/**
+ * Get the current RX margining parameter
+ *
+ * @param node Node to read margin value from
+ * @param qlm QLM to read from
+ * @param qlm_lane Lane to read
+ * @param margin_type
+ * Type of margining parameter to read
+ *
+ * @return Current margining parameter value
+ */
+int64_t bdk_qlm_margin_rx_get(bdk_node_t node, int qlm, int qlm_lane, bdk_qlm_margin_t margin_type)
+{
+ rx_os_mvalbbd_t mvalbbd = get_current_settings(node, qlm, qlm_lane);
+
+ switch (margin_type)
+ {
+ case BDK_QLM_MARGIN_VERTICAL:
+ if (mvalbbd.f.Q & 0x20) /* Check if sign bit says positive */
+ return mvalbbd.f.Q & 0x1f; /* positive, strip off sign */
+ else
+ return -mvalbbd.f.Q; /* negative */
+ case BDK_QLM_MARGIN_HORIZONTAL:
+ return 0;
+ }
+ return 0;
+}
+
+/**
+ * Get the current RX margining parameter minimum value
+ *
+ * @param node Node to read margin value from
+ * @param qlm QLM to read from
+ * @param qlm_lane Lane to read
+ * @param margin_type
+ * Type of margining parameter to read
+ *
+ * @return Current margining parameter minimum value
+ */
+int64_t bdk_qlm_margin_rx_get_min(bdk_node_t node, int qlm, int qlm_lane, bdk_qlm_margin_t margin_type)
+{
+ switch (margin_type)
+ {
+ case BDK_QLM_MARGIN_VERTICAL:
+ return -31;
+ case BDK_QLM_MARGIN_HORIZONTAL:
+ return 0;
+ }
+ return 0;
+}
+
+/**
+ * Get the current RX margining parameter maximum value
+ *
+ * @param node Node to read margin value from
+ * @param qlm QLM to read from
+ * @param qlm_lane Lane to read
+ * @param margin_type
+ * Type of margining parameter to read
+ *
+ * @return Current margining parameter maximum value
+ */
+int64_t bdk_qlm_margin_rx_get_max(bdk_node_t node, int qlm, int qlm_lane, bdk_qlm_margin_t margin_type)
+{
+ switch (margin_type)
+ {
+ case BDK_QLM_MARGIN_VERTICAL:
+ return 31;
+ case BDK_QLM_MARGIN_HORIZONTAL:
+ return 0;
+ }
+ return 0;
+}
+
+/**
+ * Set the current RX margining parameter value
+ *
+ * @param node Node to set margin value on
+ * @param qlm QLM to set
+ * @param qlm_lane Lane to set
+ * @param margin_type
+ * Type of margining parameter to set
+ * @param value Value of margining parameter
+ *
+ * @return Zero on success, negative on failure
+ */
+int bdk_qlm_margin_rx_set(bdk_node_t node, int qlm, int qlm_lane, bdk_qlm_margin_t margin_type, int value)
+{
+ rx_os_mvalbbd_t mvalbbd = get_current_settings(node, qlm, qlm_lane);
+
+ switch (margin_type)
+ {
+ case BDK_QLM_MARGIN_VERTICAL:
+ if (value < 0)
+ mvalbbd.f.Q = -value; /* Sign bit is zero, weird Synopsys */
+ else
+ mvalbbd.f.Q = value | 0x20; /* Sign bit is one, weird Synopsys */
+ break;
+ case BDK_QLM_MARGIN_HORIZONTAL:
+ return -1;
+ }
+
+ BDK_CSR_MODIFY(c, node, BDK_GSERX_LANEX_RX_OS_MVALBBD_1(qlm, qlm_lane),
+ c.s.pcs_sds_rx_os_mval = mvalbbd.s.rx_os_mvalbbd_1);
+ BDK_CSR_MODIFY(c, node, BDK_GSERX_LANEX_RX_OS_MVALBBD_2(qlm, qlm_lane),
+ c.s.pcs_sds_rx_os_mval = mvalbbd.s.rx_os_mvalbbd_2);
+ BDK_CSR_MODIFY(c, node, BDK_GSERX_LANEX_RX_CFG_1(qlm, qlm_lane),
+ c.s.pcs_sds_rx_os_men = 1);
+
+ /* Disable the DFE(s), gives a better eye measurement */
+ BDK_CSR_INIT(pwr_ctrl, node, BDK_GSERX_LANEX_PWR_CTRL(qlm, qlm_lane));
+ if (!pwr_ctrl.s.rx_lctrl_ovrrd_en)
+ {
+ BDK_CSR_WRITE(node, BDK_GSERX_LANEX_RX_LOOP_CTRL(qlm, qlm_lane), 0xF1);
+ BDK_CSR_MODIFY(c, node, BDK_GSERX_LANEX_PWR_CTRL(qlm, qlm_lane),
+ c.s.rx_lctrl_ovrrd_en = 1);
+ }
+
+ if (qlm >= 8)
+ __bdk_disable_ccpi_error_report = 1;
+
+ return 0;
+}
+
+/**
+ * Restore the supplied RX margining parameter value as if it was never set. This
+ * disables any overrides in the SERDES need to perform margining
+ *
+ * @param node Node to restore margin value on
+ * @param qlm QLM to restore
+ * @param qlm_lane Lane to restore
+ * @param margin_type
+ * Type of margining parameter to restore
+ * @param value Value of margining parameter
+ *
+ * @return Zero on success, negative on failure
+ */
+int bdk_qlm_margin_rx_restore(bdk_node_t node, int qlm, int qlm_lane, bdk_qlm_margin_t margin_type, int value)
+{
+ BDK_CSR_INIT(rx_cfg_1, node, BDK_GSERX_LANEX_RX_CFG_1(qlm, qlm_lane));
+ /* Return if no overrides have been applied */
+ if (!rx_cfg_1.s.pcs_sds_rx_os_men)
+ return 0;
+ bdk_qlm_margin_rx_set(node, qlm, qlm_lane, margin_type, value);
+ BDK_CSR_MODIFY(c, node, BDK_GSERX_LANEX_RX_CFG_1(qlm, qlm_lane),
+ c.s.pcs_sds_rx_os_men = 0);
+ /* Enable the DFE(s) */
+ BDK_CSR_MODIFY(c, node, BDK_GSERX_LANEX_PWR_CTRL(qlm, qlm_lane),
+ c.s.rx_lctrl_ovrrd_en = 0);
+ __bdk_disable_ccpi_error_report = 0;
+ return 0;
+}
+
diff --git a/src/vendorcode/cavium/bdk/libbdk-os/bdk-init.c b/src/vendorcode/cavium/bdk/libbdk-os/bdk-init.c
index 25d6b9eed3..1594beaf3b 100644
--- a/src/vendorcode/cavium/bdk/libbdk-os/bdk-init.c
+++ b/src/vendorcode/cavium/bdk/libbdk-os/bdk-init.c
@@ -37,501 +37,7 @@
* ARISING OUT OF USE OR PERFORMANCE OF THE SOFTWARE LIES WITH YOU.
***********************license end**************************************/
#include <bdk.h>
-#include <stdio.h>
-#include <unistd.h>
-#include "libbdk-arch/bdk-csrs-ap.h"
-#include "libbdk-arch/bdk-csrs-l2c.h"
-#include "libbdk-arch/bdk-csrs-l2c_tad.h"
-#include "libbdk-arch/bdk-csrs-mio_boot.h"
-#include "libbdk-arch/bdk-csrs-rom.h"
-#include "libbdk-arch/bdk-csrs-uaa.h"
-
-uint64_t __bdk_init_reg_x0; /* The contents of X0 when this image started */
-uint64_t __bdk_init_reg_x1; /* The contents of X1 when this image started */
-uint64_t __bdk_init_reg_pc; /* The contents of PC when this image started */
-static int64_t __bdk_alive_coremask[BDK_NUMA_MAX_NODES];
-
-/**
- * Set the baud rate on a UART
- *
- * @param uart uart to set
- * @param baudrate Baud rate (9600, 19200, 115200, etc)
- * @param use_flow_control
- * Non zero if hardware flow control should be enabled
- */
-void bdk_set_baudrate(bdk_node_t node, int uart, int baudrate, int use_flow_control)
-{
- /* 1.2.1 Initialization Sequence (Power-On/Hard/Cold Reset) */
- /* 1. Wait for IOI reset (srst_n) to deassert. */
- /* 2. Assert all resets:
- a. UAA reset: UCTL_CTL[UAA_RST] = 1
- b. UCTL reset: UCTL_CTL[UCTL_RST] = 1 */
- BDK_CSR_MODIFY(c, node, BDK_UAAX_UCTL_CTL(uart),
- c.s.uaa_rst = 1;
- c.s.uctl_rst = 1);
-
- /* 3. Configure the HCLK:
- a. Reset the clock dividers: UCTL_CTL[H_CLKDIV_RST] = 1.
- b. Select the HCLK frequency
- i. UCTL_CTL[H_CLKDIV] = desired value,
- ii. UCTL_CTL[H_CLKDIV_EN] = 1 to enable the HCLK.
- iii. Readback UCTL_CTL to ensure the values take effect.
- c. Deassert the HCLK clock divider reset: UCTL_CTL[H_CLKDIV_RST] = 0. */
- BDK_CSR_MODIFY(c, node, BDK_UAAX_UCTL_CTL(uart),
- c.s.h_clkdiv_sel = 3; /* Run at SCLK / 6, matches emulator */
- c.s.h_clk_byp_sel = 0;
- c.s.h_clk_en = 1);
- BDK_CSR_MODIFY(c, node, BDK_UAAX_UCTL_CTL(uart),
- c.s.h_clkdiv_rst = 0);
-
- /* 4. Wait 20 HCLK cycles from step 3 for HCLK to start and async fifo
- to properly reset. */
- bdk_wait(200); /* Overkill */
-
- /* 5. Deassert UCTL and UAHC resets:
- a. UCTL_CTL[UCTL_RST] = 0
- b. Wait 10 HCLK cycles.
- c. UCTL_CTL[UAHC_RST] = 0
- d. You will have to wait 10 HCLK cycles before accessing any
- HCLK-only registers. */
- BDK_CSR_MODIFY(c, node, BDK_UAAX_UCTL_CTL(uart), c.s.uctl_rst = 0);
- bdk_wait(100); /* Overkill */
- BDK_CSR_MODIFY(c, node, BDK_UAAX_UCTL_CTL(uart), c.s.uaa_rst = 0);
- bdk_wait(100); /* Overkill */
-
- /* 6. Enable conditional SCLK of UCTL by writing UCTL_CTL[CSCLK_EN] = 1. */
- BDK_CSR_MODIFY(c, node, BDK_UAAX_UCTL_CTL(uart), c.s.csclk_en = 1);
-
- /* 7. Initialize the integer and fractional baud rate divider registers
- UARTIBRD and UARTFBRD as follows:
- a. Baud Rate Divisor = UARTCLK/(16xBaud Rate) = BRDI + BRDF
- b. The fractional register BRDF, m is calculated as integer(BRDF x 64 + 0.5)
- Example calculation:
- If the required baud rate is 230400 and hclk = 4MHz then:
- Baud Rate Divisor = (4x10^6)/(16x230400) = 1.085
- This means BRDI = 1 and BRDF = 0.085.
- Therefore, fractional part, BRDF = integer((0.085x64)+0.5) = 5
- Generated baud rate divider = 1+5/64 = 1.078 */
- uint64_t divisor_x_64 = bdk_clock_get_rate(node, BDK_CLOCK_SCLK) / (baudrate * 16 * 6 / 64);
- if (bdk_is_platform(BDK_PLATFORM_EMULATOR))
- {
- /* The hardware emulator currently fixes the uart at a fixed rate */
- divisor_x_64 = 64;
- }
- BDK_CSR_MODIFY(c, node, BDK_UAAX_IBRD(uart),
- c.s.baud_divint = divisor_x_64 >> 6);
- BDK_CSR_MODIFY(c, node, BDK_UAAX_FBRD(uart),
- c.s.baud_divfrac = divisor_x_64 & 0x3f);
-
- /* 8. Program the line control register UAA(0..1)_LCR_H and the control
- register UAA(0..1)_CR */
- BDK_CSR_MODIFY(c, node, BDK_UAAX_LCR_H(uart),
- c.s.sps = 0; /* No parity */
- c.s.wlen = 3; /* 8 bits */
- c.s.fen = 1; /* FIFOs enabled */
- c.s.stp2 = 0; /* Use one stop bit, not two */
- c.s.eps = 0; /* No parity */
- c.s.pen = 0; /* No parity */
- c.s.brk = 0); /* Don't send a break */
- BDK_CSR_MODIFY(c, node, BDK_UAAX_CR(uart),
- c.s.ctsen = use_flow_control;
- c.s.rtsen = use_flow_control;
- c.s.out1 = 1; /* Drive data carrier detect */
- c.s.rts = 0; /* Don't override RTS */
- c.s.dtr = 0; /* Don't override DTR */
- c.s.rxe = 1; /* Enable receive */
- c.s.txe = 1; /* Enable transmit */
- c.s.lbe = 0; /* Disable loopback */
- c.s.uarten = 1); /* Enable uart */
-}
-
-/**
- * First C code run when a BDK application starts. It is called by bdk-start.S.
- *
- * @param image_crc A CRC32 of the entire image before any variables might have been updated by C.
- * This should match the CRC32 in the image header.
- * @param reg_x0 The contents of the X0 register when the image started. In images loaded after
- * the boot stub, this contains a "environment" string containing "BOARD=xxx". The
- * use of this is deprecated as it has been replaced with a expandable device tree
- * in X1.
- * @param reg_x1 The contents of the X1 register when the image started. For all images after the
- * boot stub, this contains a physical address of a device tree in memory. This
- * should be used by all images to identify and configure the board we are running
- * on.
- * @param reg_pc This is the PC the code started at before relocation. This is useful for
- * the first stage to determine if it from trusted or non-trusted code.
- */
-void __bdk_init(uint32_t image_crc, uint64_t reg_x0, uint64_t reg_x1, uint64_t reg_pc) __attribute((noreturn));
-void __bdk_init(uint32_t image_crc, uint64_t reg_x0, uint64_t reg_x1, uint64_t reg_pc)
-{
- extern void __bdk_exception_current_el_sync_sp0();
- BDK_MSR(VBAR_EL3, __bdk_exception_current_el_sync_sp0);
- BDK_MSR(VBAR_EL2, __bdk_exception_current_el_sync_sp0);
- BDK_MSR(VBAR_EL1, __bdk_exception_current_el_sync_sp0);
-
- /* Use Cavium specific function to change memory to normal instead of
- device attributes. DCVA47=1 makes unmapped addresses behave as
- non-shared memory (not inner or outer shared in ARM speak) */
- bdk_ap_cvmmemctl0_el1_t cvmmemctl0_el1;
- BDK_MRS(s3_0_c11_c0_4, cvmmemctl0_el1.u);
- cvmmemctl0_el1.s.dcva47 = 1;
- BDK_MSR(s3_0_c11_c0_4, cvmmemctl0_el1.u);
-
-
- /* Setup running with no mmu */
- bdk_ap_sctlr_el3_t sctlr_el3;
- BDK_MRS(SCTLR_EL3, sctlr_el3.u);
- sctlr_el3.s.wxn = 0; /* No write perm changes */
- sctlr_el3.s.i = 1; /* Enable Icache */
- sctlr_el3.s.sa = 1; /* Enable stack alignment checking */
- sctlr_el3.s.cc = 1; /* Enable Dcache */
- sctlr_el3.s.aa = 0; /* Allow unaligned accesses */
- sctlr_el3.s.m = 0; /* Disable MMU */
- BDK_MSR(SCTLR_EL3, sctlr_el3.u);
-
- bdk_node_t node = bdk_numa_local();
- bdk_numa_set_exists(node);
-
- /* Default color, Reset scroll region and goto bottom */
- static const char BANNER_1[] = "\33[0m\33[1;r\33[100;1H"
- "\n\n\nCavium SOC\n";
- static const char BANNER_2[] = "Locking L2 cache\n";
- static const char BANNER_CRC_RIGHT[] = "PASS: CRC32 verification\n";
- static const char BANNER_CRC_WRONG[] = "FAIL: CRC32 verification\n";
- static const char BANNER_3[] = "Transferring to thread scheduler\n";
-
- BDK_MSR(TPIDR_EL3, 0);
-
- if (bdk_is_boot_core())
- {
- /* Initialize the platform */
- __bdk_platform_init();
- if (!bdk_is_platform(BDK_PLATFORM_EMULATOR) && CAVIUM_IS_MODEL(CAVIUM_CN88XX))
- {
- BDK_CSR_INIT(l2c_oci_ctl, node, BDK_L2C_OCI_CTL);
- if (l2c_oci_ctl.s.iofrcl)
- {
- /* CCPI isn't being used, so don't reset if the links change */
- BDK_CSR_WRITE(node, BDK_RST_OCX, 0);
- BDK_CSR_READ(node, BDK_RST_OCX);
- /* Force CCPI links down so they aren't trying to run while
- we're configuring the QLMs */
- __bdk_init_ccpi_early(1);
- }
- }
-
- /* AP-23192: The DAP in pass 1.0 has an issue where its state isn't cleared for
- cores in reset. Put the DAPs in reset as their associated cores are
- also in reset */
- if (!bdk_is_platform(BDK_PLATFORM_EMULATOR) && CAVIUM_IS_MODEL(CAVIUM_CN88XX_PASS1_0))
- BDK_CSR_WRITE(node, BDK_RST_DBG_RESET, BDK_CSR_READ(node, BDK_RST_PP_RESET));
-
- /* Enable the timer */
- BDK_MSR(CNTFRQ_EL0, BDK_GTI_RATE); /* Needed for Asim */
- bdk_clock_setup(node);
-
- /* Only setup the uarts if they haven't been already setup */
- BDK_CSR_INIT(uctl_ctl0, node, BDK_UAAX_UCTL_CTL(0));
- if (!uctl_ctl0.s.h_clk_en)
- bdk_set_baudrate(node, 0, BDK_UART_BAUDRATE, 0);
- BDK_CSR_INIT(uctl_ctl1, node, BDK_UAAX_UCTL_CTL(1));
- if (!uctl_ctl1.s.h_clk_en)
- bdk_set_baudrate(node, 1, BDK_UART_BAUDRATE, 0);
-
- __bdk_fs_init_early();
- if (BDK_SHOW_BOOT_BANNERS)
- write(1, BANNER_1, sizeof(BANNER_1)-1);
-
- /* Only lock L2 if DDR3 isn't initialized */
- if (bdk_is_platform(BDK_PLATFORM_HW) && !__bdk_is_dram_enabled(node))
- {
- if (BDK_TRACE_ENABLE_INIT)
- write(1, BANNER_2, sizeof(BANNER_2)-1);
- /* Lock the entire cache for chips with less than 4MB of
- L2/LLC. Larger chips can use the 1/4 of the cache to
- speed up DRAM init and testing */
- int lock_size = bdk_l2c_get_cache_size_bytes(node);
- if (lock_size >= (4 << 20))
- lock_size = lock_size * 3 / 4;
- bdk_l2c_lock_mem_region(node, bdk_numa_get_address(node, 0), lock_size);
- /* The locked region isn't considered dirty by L2. Do read
- read/write of each cache line to force each to be dirty. This
- is needed across the whole line to make sure the L2 dirty bits
- are all up to date */
- volatile uint64_t *ptr = bdk_phys_to_ptr(bdk_numa_get_address(node, 8));
- /* The above pointer got address 8 to avoid NULL pointer checking
- in bdk_phys_to_ptr(). Correct it here */
- ptr--;
- uint64_t *end = bdk_phys_to_ptr(bdk_numa_get_address(node, bdk_l2c_get_cache_size_bytes(node)));
- while (ptr < end)
- {
- *ptr = *ptr;
- ptr++;
- }
- /* The above locking will cause L2 to load zeros without DRAM setup.
- This will cause L2C_TADX_INT[rddislmc], which we suppress below */
- BDK_CSR_DEFINE(l2c_tadx_int, BDK_L2C_TADX_INT_W1C(0));
- l2c_tadx_int.u = 0;
- l2c_tadx_int.s.wrdislmc = 1;
- l2c_tadx_int.s.rddislmc = 1;
- l2c_tadx_int.s.rdnxm = 1;
-
- BDK_CSR_WRITE(node, BDK_L2C_TADX_INT_W1C(0), l2c_tadx_int.u);
- if (CAVIUM_IS_MODEL(CAVIUM_CN88XX) || CAVIUM_IS_MODEL(CAVIUM_CN83XX))
- {
- BDK_CSR_WRITE(node, BDK_L2C_TADX_INT_W1C(1), l2c_tadx_int.u);
- BDK_CSR_WRITE(node, BDK_L2C_TADX_INT_W1C(2), l2c_tadx_int.u);
- BDK_CSR_WRITE(node, BDK_L2C_TADX_INT_W1C(3), l2c_tadx_int.u);
- }
- if (CAVIUM_IS_MODEL(CAVIUM_CN88XX))
- {
- BDK_CSR_WRITE(node, BDK_L2C_TADX_INT_W1C(4), l2c_tadx_int.u);
- BDK_CSR_WRITE(node, BDK_L2C_TADX_INT_W1C(5), l2c_tadx_int.u);
- BDK_CSR_WRITE(node, BDK_L2C_TADX_INT_W1C(6), l2c_tadx_int.u);
- BDK_CSR_WRITE(node, BDK_L2C_TADX_INT_W1C(7), l2c_tadx_int.u);
- }
- }
-
- /* Validate the image CRC */
- extern void _start();
- uint32_t *ptr_crc32 = (uint32_t *)(_start + 16);
- uint32_t correct_crc = bdk_le32_to_cpu(*ptr_crc32);
- if (correct_crc == image_crc)
- write(1, BANNER_CRC_RIGHT, sizeof(BANNER_CRC_RIGHT) - 1);
- else
- write(1, BANNER_CRC_WRONG, sizeof(BANNER_CRC_WRONG) - 1);
-
- if (BDK_TRACE_ENABLE_INIT)
- write(1, BANNER_3, sizeof(BANNER_3)-1);
- bdk_thread_initialize();
- }
-
- /* Enable the core timer */
- BDK_MSR(CNTFRQ_EL0, BDK_GTI_RATE); /* Needed for Asim */
- bdk_ap_cntps_ctl_el1_t cntps_ctl_el1;
- cntps_ctl_el1.u = 0;
- cntps_ctl_el1.s.imask = 1;
- cntps_ctl_el1.s.enable = 1;
- BDK_MSR(CNTPS_CTL_EL1, cntps_ctl_el1.u);
-
- /* Setup an exception stack in case we crash */
- int EX_STACK_SIZE = 16384;
- void *exception_stack = malloc(EX_STACK_SIZE);
- extern void __bdk_init_exception_stack(void *ptr);
- __bdk_init_exception_stack(exception_stack + EX_STACK_SIZE);
-
- bdk_atomic_add64(&__bdk_alive_coremask[node], bdk_core_to_mask());
-
- /* Record our input registers for use later */
- __bdk_init_reg_x0 = reg_x0;
- __bdk_init_reg_x1 = reg_x1;
- __bdk_init_reg_pc = reg_pc;
- bdk_thread_first(__bdk_init_main, 0, NULL, 0);
-}
-
-/**
- * Call this function to take secondary cores out of reset and have
- * them start running threads
- *
- * @param node Node to use in a Numa setup. Can be an exact ID or a special
- * value.
- * @param coremask Cores to start. Zero is a shortcut for all.
- *
- * @return Zero on success, negative on failure.
- */
-int bdk_init_cores(bdk_node_t node, uint64_t coremask)
-{
- extern void __bdk_start_cores();
- if (CAVIUM_IS_MODEL(CAVIUM_CN8XXX))
- {
- /* Write the address of the main entry point */
- BDK_TRACE(INIT, "N%d: Setting address for boot jump\n", node);
- BDK_CSR_WRITE(node, BDK_MIO_BOOT_AP_JUMP, (uint64_t)__bdk_start_cores);
- }
- else
- {
- BDK_TRACE(INIT, "N%d: Setting ROM boot code\n", node);
- /* Assembly for ROM memory:
- d508711f ic ialluis
- d503201f nop
- 58000040 ldr x0, 328 <branch_addr>
- d61f0000 br x0
- branch_addr:
- Memory is little endain, so 64 bit constants have the first
- instruction in the low word */
- BDK_CSR_WRITE(node, BDK_ROM_MEMX(0), 0xd503201fd508711f);
- BDK_CSR_WRITE(node, BDK_ROM_MEMX(1), 0xd61f000058000040);
- BDK_CSR_WRITE(node, BDK_ROM_MEMX(2), (uint64_t)__bdk_start_cores);
- }
-
- /* Choose all cores by default */
- if (coremask == 0)
- coremask = -1;
-
- /* Limit to the cores that aren't already running */
- coremask &= ~__bdk_alive_coremask[node];
-
- /* Limit to the cores that are specified in configuration menu */
- uint64_t config_coremask = bdk_config_get_int(BDK_CONFIG_COREMASK);
- if (config_coremask)
- coremask &= config_coremask;
-
- /* Limit to the cores that exist */
- coremask &= (1ull<<bdk_get_num_cores(node)) - 1;
-
- uint64_t reset = BDK_CSR_READ(node, BDK_RST_PP_RESET);
- BDK_TRACE(INIT, "N%d: Cores currently in reset: 0x%lx\n", node, reset);
- uint64_t need_reset_off = reset & coremask;
- if (need_reset_off)
- {
- BDK_TRACE(INIT, "N%d: Taking cores out of reset (0x%lx)\n", node, need_reset_off);
- BDK_CSR_WRITE(node, BDK_RST_PP_RESET, reset & ~need_reset_off);
- /* Wait for cores to finish coming out of reset */
- bdk_wait_usec(1);
- if (BDK_CSR_WAIT_FOR_FIELD(node, BDK_RST_PP_PENDING, pend, ==, 0, 100000))
- bdk_error("Timeout wating for reset pending to clear");
- /* AP-23192: The DAP in pass 1.0 has an issue where its state isn't cleared for
- cores in reset. Put the DAPs in reset as their associated cores are
- also in reset */
- if (!bdk_is_platform(BDK_PLATFORM_EMULATOR) && CAVIUM_IS_MODEL(CAVIUM_CN88XX_PASS1_0))
- BDK_CSR_WRITE(node, BDK_RST_DBG_RESET, reset & ~need_reset_off);
- }
-
- BDK_TRACE(INIT, "N%d: Wait up to 1s for the cores to boot\n", node);
- uint64_t timeout = bdk_clock_get_rate(bdk_numa_local(), BDK_CLOCK_TIME) + bdk_clock_get_count(BDK_CLOCK_TIME);
- while ((bdk_clock_get_count(BDK_CLOCK_TIME) < timeout) && ((bdk_atomic_get64(&__bdk_alive_coremask[node]) & coremask) != coremask))
- {
- /* Tight spin, no thread schedules */
- }
-
- if ((bdk_atomic_get64(&__bdk_alive_coremask[node]) & coremask) != coremask)
- {
- bdk_error("Node %d: Some cores failed to start. Alive mask 0x%lx, requested 0x%lx\n",
- node, __bdk_alive_coremask[node], coremask);
- return -1;
- }
- BDK_TRACE(INIT, "N%d: All cores booted\n", node);
- return 0;
-}
-
-/**
- * Put cores back in reset and power them down
- *
- * @param node Node to update
- * @param coremask Each bit will be a core put in reset. Cores already in reset are unaffected
- *
- * @return Zero on success, negative on failure
- */
-int bdk_reset_cores(bdk_node_t node, uint64_t coremask)
-{
- extern void __bdk_reset_thread(int arg1, void *arg2);
-
- /* Limit to the cores that exist */
- coremask &= (1ull<<bdk_get_num_cores(node)) - 1;
-
- /* Update which cores are in reset */
- uint64_t reset = BDK_CSR_READ(node, BDK_RST_PP_RESET);
- BDK_TRACE(INIT, "N%d: Cores currently in reset: 0x%lx\n", node, reset);
- coremask &= ~reset;
- BDK_TRACE(INIT, "N%d: Cores to put into reset: 0x%lx\n", node, coremask);
-
- /* Check if everything is already done */
- if (coremask == 0)
- return 0;
-
- int num_cores = bdk_get_num_cores(node);
- for (int core = 0; core < num_cores; core++)
- {
- uint64_t my_mask = 1ull << core;
- /* Skip cores not in mask */
- if ((coremask & my_mask) == 0)
- continue;
- BDK_TRACE(INIT, "N%d: Telling core %d to go into reset\n", node, core);
- if (bdk_thread_create(node, my_mask, __bdk_reset_thread, 0, NULL, 0))
- {
- bdk_error("Failed to create thread for putting core in reset");
- continue;
- }
- /* Clear the core in the alive mask */
- bdk_atomic_fetch_and_bclr64_nosync((uint64_t*)&__bdk_alive_coremask[node], my_mask);
- }
-
- BDK_TRACE(INIT, "N%d: Waiting for all reset bits to be set\n", node);
- uint64_t timeout = bdk_clock_get_rate(bdk_numa_local(), BDK_CLOCK_TIME) + bdk_clock_get_count(BDK_CLOCK_TIME);
- while (bdk_clock_get_count(BDK_CLOCK_TIME) < timeout)
- {
- reset = BDK_CSR_READ(node, BDK_RST_PP_RESET);
- if ((reset & coremask) == coremask)
- break;
- bdk_thread_yield();
- }
- /* AP-23192: The DAP in pass 1.0 has an issue where its state isn't cleared for
- cores in reset. Put the DAPs in reset as their associated cores are
- also in reset */
- if (!bdk_is_platform(BDK_PLATFORM_EMULATOR) && CAVIUM_IS_MODEL(CAVIUM_CN88XX_PASS1_0))
- BDK_CSR_WRITE(node, BDK_RST_DBG_RESET, BDK_CSR_READ(node, BDK_RST_PP_RESET));
-
- BDK_TRACE(INIT, "N%d: Cores now in reset: 0x%lx\n", node, reset);
-
- return ((reset & coremask) == coremask) ? 0 : -1;
-}
-
-/**
- * Call this function to take secondary nodes and cores out of
- * reset and have them start running threads
- *
- * @param skip_cores If non-zero, cores are not started. Only the nodes are setup
- * @param ccpi_sw_gbaud
- * If CCPI is in software mode, this is the speed the CCPI QLMs will be configured
- * for
- *
- * @return Zero on success, negative on failure.
- */
-int bdk_init_nodes(int skip_cores, int ccpi_sw_gbaud)
-{
- int result = 0;
- int do_oci_init = (__bdk_init_ccpi_links != NULL);
-
- /* Only init OCI/CCPI on chips that support it */
- do_oci_init &= CAVIUM_IS_MODEL(CAVIUM_CN88XX);
-
- /* Check that the BDK config says multi-node is enabled */
- if (bdk_config_get_int(BDK_CONFIG_MULTI_NODE) == 0)
- do_oci_init = 0;
-
- /* Simulation under Asim is a special case. Multi-node is simulaoted, but
- not the details of the low level link */
- if (do_oci_init && bdk_is_platform(BDK_PLATFORM_ASIM))
- {
- bdk_numa_set_exists(0);
- bdk_numa_set_exists(1);
- /* Skip the rest in simulation */
- do_oci_init = 0;
- }
-
- if (do_oci_init)
- {
- if (__bdk_init_ccpi_links(ccpi_sw_gbaud) == 0)
- {
- /* Don't run node init if L2C_OCI_CTL shows that it has already
- been done */
- BDK_CSR_INIT(l2c_oci_ctl, bdk_numa_local(), BDK_L2C_OCI_CTL);
- if (l2c_oci_ctl.s.enaoci == 0)
- result |= __bdk_init_ccpi_multinode();
- }
- }
-
- /* Start cores on all node unless it was disabled */
- if (!skip_cores)
- {
- for (bdk_node_t node=0; node<BDK_NUMA_MAX_NODES; node++)
- {
- if (bdk_numa_exists(node))
- result |= bdk_init_cores(node, 0);
- }
- }
- return result;
-}
+#include <libbdk-os/bdk-init.h>
/**
* Get the coremask of the cores actively running the BDK. Doesn't count cores
@@ -543,7 +49,7 @@ int bdk_init_nodes(int skip_cores, int ccpi_sw_gbaud)
*/
uint64_t bdk_get_running_coremask(bdk_node_t node)
{
- return __bdk_alive_coremask[node];
+ return 0x1;
}
/**
@@ -556,6 +62,6 @@ uint64_t bdk_get_running_coremask(bdk_node_t node)
*/
int bdk_get_num_running_cores(bdk_node_t node)
{
- return __builtin_popcountl(bdk_get_running_coremask(node));
+ return bdk_pop(bdk_get_running_coremask(node));
}
diff --git a/src/vendorcode/cavium/bdk/libbdk-os/bdk-thread.c b/src/vendorcode/cavium/bdk/libbdk-os/bdk-thread.c
deleted file mode 100644
index df1d02864b..0000000000
--- a/src/vendorcode/cavium/bdk/libbdk-os/bdk-thread.c
+++ /dev/null
@@ -1,384 +0,0 @@
-/***********************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 <stdio.h>
-#include <malloc.h>
-
-#define STACK_CANARY 0x0BADBADBADBADBADull
-
-typedef struct bdk_thread
-{
- struct bdk_thread *next;
- uint64_t coremask;
- uint64_t gpr[32]; /* Reg 31 is SP */
- struct _reent lib_state;
- uint64_t stack_canary;
- uint64_t stack[0];
-} bdk_thread_t;
-
-typedef struct
-{
- bdk_thread_t* head;
- bdk_thread_t* tail;
- bdk_spinlock_t lock;
- int64_t __padding1[16-3]; /* Stats in different cache line for speed */
- int64_t stat_num_threads;
- int64_t stat_no_schedulable_threads;
- int64_t stat_next_calls;
- int64_t stat_next_walks;
- int64_t __padding2[16-4];
-} bdk_thread_node_t;
-
-static bdk_thread_node_t bdk_thread_node[BDK_NUMA_MAX_NODES];
-
-extern void __bdk_thread_switch(bdk_thread_t* next_context, int delete_old);
-
-/**
- * Main thread body for all threads
- *
- * @param func User function to call
- * @param arg0 First argument to the user function
- * @param arg1 Second argument to the user function
- */
-static void __bdk_thread_body(bdk_thread_func_t func, int arg0, void *arg1)
-{
- func(arg0, arg1);
- bdk_thread_destroy();
-}
-
-
-/**
- * Initialize the BDK thread library
- *
- * @return Zero on success, negative on failure
- */
-int bdk_thread_initialize(void)
-{
- bdk_zero_memory(bdk_thread_node, sizeof(bdk_thread_node));
- _REENT_INIT_PTR(&__bdk_thread_global_reent);
- return 0;
-}
-
-static bdk_thread_t *__bdk_thread_next(void)
-{
- bdk_thread_node_t *t_node = &bdk_thread_node[bdk_numa_local()];
- uint64_t coremask = bdk_core_to_mask();
-
- bdk_atomic_add64_nosync(&t_node->stat_next_calls, 1);
- bdk_thread_t *prev = NULL;
- bdk_thread_t *next = t_node->head;
- int walks = 0;
- while (next && !(next->coremask & coremask))
- {
- prev = next;
- next = next->next;
- walks++;
- }
- if (walks)
- bdk_atomic_add64_nosync(&t_node->stat_next_walks, walks);
-
- if (next)
- {
- if (t_node->tail == next)
- t_node->tail = prev;
- if (prev)
- prev->next = next->next;
- else
- t_node->head = next->next;
- next->next = NULL;
- }
- else
- bdk_atomic_add64_nosync(&t_node->stat_no_schedulable_threads, 1);
-
- return next;
-}
-
-/**
- * Yield the current thread and run a new one
- */
-void bdk_thread_yield(void)
-{
- if (BDK_DBG_MAGIC_ENABLE && (bdk_numa_local() == bdk_numa_master()))
- bdk_dbg_check_magic();
- bdk_thread_node_t *t_node = &bdk_thread_node[bdk_numa_local()];
- bdk_thread_t *current;
- BDK_MRS_NV(TPIDR_EL3, current);
-
- /* Yield can be called without a thread context during core init. The
- cores call bdk_wait_usec(), which yields. In this case yielding
- does nothing */
- if (bdk_unlikely(!current))
- return;
-
- if (bdk_unlikely(current->stack_canary != STACK_CANARY))
- bdk_fatal("bdk_thread_yield() detected a stack overflow\n");
-
- if (CAVIUM_IS_MODEL(CAVIUM_CN83XX))
- bdk_sso_process_work();
-
- if (t_node->head == NULL)
- return;
-
- bdk_spinlock_lock(&t_node->lock);
-
- /* Find the first thread that can run on this core */
- bdk_thread_t *next = __bdk_thread_next();
-
- /* If next is NULL then there are no other threads ready to run and we
- will continue without doing anything */
- if (next)
- {
- __bdk_thread_switch(next, 0);
- /* Unlock performed in __bdk_thread_switch_complete */
- return;
- }
- bdk_spinlock_unlock(&t_node->lock);
-}
-
-
-/**
- * Create a new thread and return it. The thread will not be scheduled
- * as it isn't put in the thread list.
- *
- * @param coremask Mask of cores the thread can run on. Each set bit is an allowed
- * core. Zero and -1 are both shortcuts for all cores.
- * @param func Function to run as a thread
- * @param arg0 First argument to the function
- * @param arg1 Second argument to the function
- * @param stack_size Stack size for the new thread. Set to zero for the system default.
- *
- * @return Thread or NULL on failure
- */
-static void *__bdk_thread_create(uint64_t coremask, bdk_thread_func_t func, int arg0, void *arg1, int stack_size)
-{
- bdk_thread_t *thread;
- if (!stack_size)
- stack_size = BDK_THREAD_DEFAULT_STACK_SIZE;
-
- thread = memalign(16, sizeof(bdk_thread_t) + stack_size);
- if (thread == NULL)
- {
- bdk_error("Unable to allocate memory for new thread\n");
- return NULL;
- }
- memset(thread, 0, sizeof(bdk_thread_t) + stack_size);
- if (coremask == 0)
- coremask = -1;
- thread->coremask = coremask;
- thread->gpr[0] = (uint64_t)func; /* x0 = Argument 0 to __bdk_thread_body */
- thread->gpr[1] = arg0; /* x1 = Argument 1 to __bdk_thread_body */
- thread->gpr[2] = (uint64_t)arg1; /* x2 = Argument 2 to __bdk_thread_body */
- thread->gpr[29] = 0; /* x29 = Frame pointer */
- thread->gpr[30] = (uint64_t)__bdk_thread_body; /* x30 = Link register */
- thread->gpr[31] = (uint64_t)thread->stack + stack_size; /* x31 = Stack pointer */
- if (thread->gpr[31] & 0xf)
- bdk_fatal("Stack not aligned 0x%lx\n", thread->gpr[31]);
- _REENT_INIT_PTR(&thread->lib_state);
- extern void __sinit(struct _reent *);
- __sinit(&thread->lib_state);
- thread->stack_canary = STACK_CANARY;
- thread->next = NULL;
- return thread;
-}
-
-
-/**
- * Create a new thread. The thread may be scheduled to any of the
- * cores supplied in the coremask. Note that a single thread is
- * created and may only run on one core at a time. The thread may
- * not start executing until the next yield call if all cores in
- * the coremask are currently busy.
- *
- * @param node Node to use in a Numa setup. Can be an exact ID or a
- * special value.
- * @param coremask Mask of cores the thread can run on. Each set bit is an allowed
- * core. Zero and -1 are both shortcuts for all cores.
- * @param func Function to run as a thread
- * @param arg0 First argument to the function
- * @param arg1 Second argument to the function
- * @param stack_size Stack size for the new thread. Set to zero for the system default.
- *
- * @return Zero on success, negative on failure
- */
-int bdk_thread_create(bdk_node_t node, uint64_t coremask, bdk_thread_func_t func, int arg0, void *arg1, int stack_size)
-{
- bdk_thread_node_t *t_node = &bdk_thread_node[node];
- bdk_thread_t *thread = __bdk_thread_create(coremask, func, arg0, arg1, stack_size);
- if (thread == NULL)
- return -1;
-
- bdk_atomic_add64_nosync(&t_node->stat_num_threads, 1);
- bdk_spinlock_lock(&t_node->lock);
- if (t_node->tail)
- t_node->tail->next = thread;
- else
- t_node->head = thread;
- t_node->tail = thread;
- bdk_spinlock_unlock(&t_node->lock);
- BDK_SEV;
- return 0;
-}
-
-
-/**
- * Destroy the currently running thread. This never returns.
- */
-void bdk_thread_destroy(void)
-{
- bdk_thread_node_t *t_node = &bdk_thread_node[bdk_numa_local()];
- bdk_thread_t *current;
- BDK_MRS_NV(TPIDR_EL3, current);
- if (bdk_unlikely(!current))
- bdk_fatal("bdk_thread_destroy() called without thread context\n");
- if (bdk_unlikely(current->stack_canary != STACK_CANARY))
- bdk_fatal("bdk_thread_destroy() detected a stack overflow\n");
-
- fflush(NULL);
- bdk_atomic_add64_nosync(&t_node->stat_num_threads, -1);
-
- while (1)
- {
- if (BDK_DBG_MAGIC_ENABLE && (bdk_numa_local() == bdk_numa_master()))
- bdk_dbg_check_magic();
- if (t_node->head)
- {
- bdk_spinlock_lock(&t_node->lock);
- /* Find the first thread that can run on this core */
- bdk_thread_t *next = __bdk_thread_next();
-
- /* If next is NULL then there are no other threads ready to run and we
- will continue without doing anything */
- if (next)
- {
- __bdk_thread_switch(next, 1);
- bdk_fatal("bdk_thread_destroy() should never get here\n");
- }
- bdk_spinlock_unlock(&t_node->lock);
- }
- if (CAVIUM_IS_MODEL(CAVIUM_CN83XX))
- bdk_sso_process_work();
- BDK_WFE;
- }
-}
-
-struct _reent __bdk_thread_global_reent;
-struct _reent *__bdk_thread_getreent(void)
-{
- bdk_thread_t *current;
- BDK_MRS_NV(TPIDR_EL3, current);
- if (current)
- return &current->lib_state;
- else
- return &__bdk_thread_global_reent;
-}
-
-void __bdk_thread_switch_complete(bdk_thread_t* old_context, int delete_old)
-{
- bdk_thread_node_t *t_node = &bdk_thread_node[bdk_numa_local()];
- if (bdk_unlikely(delete_old))
- {
- bdk_spinlock_unlock(&t_node->lock);
- free(old_context);
- }
- else
- {
- if (bdk_likely(old_context))
- {
- if (t_node->tail)
- t_node->tail->next = old_context;
- else
- t_node->head = old_context;
- t_node->tail = old_context;
- }
- bdk_spinlock_unlock(&t_node->lock);
- if (bdk_likely(old_context))
- BDK_SEV;
- }
-}
-
-
-/**
- * Called to create the initial thread for a CPU. Must be called
- * once for each CPU.
- *
- * @param func Function to run as new thread. It is guaranteed that this will
- * be the next thread run by the core.
- * @param arg0 First thread argument
- * @param arg1 Second thread argument
- * @param stack_size Initial stack size, or zero for the default
- */
-void bdk_thread_first(bdk_thread_func_t func, int arg0, void *arg1, int stack_size)
-{
- bdk_thread_node_t *t_node = &bdk_thread_node[bdk_numa_local()];
- void *thread = __bdk_thread_create(bdk_core_to_mask(), func, arg0, arg1, stack_size);
- if (thread)
- {
- bdk_atomic_add64_nosync(&t_node->stat_num_threads, 1);
- bdk_spinlock_lock(&t_node->lock);
- __bdk_thread_switch(thread, 0);
- }
- bdk_fatal("Create of __bdk_init_main thread failed\n");
-}
-
-/**
- * Display statistics about the number of threads and scheduling
- */
-void bdk_thread_show_stats()
-{
- for (bdk_node_t node = BDK_NODE_0; node < BDK_NUMA_MAX_NODES; node++)
- {
- if (!bdk_numa_exists(node))
- continue;
- bdk_thread_node_t *t_node = &bdk_thread_node[node];
- printf("Node %d\n", node);
- printf(" Active threads: %ld\n", t_node->stat_num_threads);
- printf(" Schedule checks: %ld\n", t_node->stat_next_calls);
- int64_t div = t_node->stat_next_calls;
- if (!div)
- div = 1;
- printf(" Average walk depth: %ld\n",
- t_node->stat_next_walks / div);
- printf(" Not switching: %ld (%ld%%)\n",
- t_node->stat_no_schedulable_threads,
- t_node->stat_no_schedulable_threads * 100 / div);
- bdk_atomic_set64(&t_node->stat_next_calls, 0);
- bdk_atomic_set64(&t_node->stat_next_walks, 0);
- bdk_atomic_set64(&t_node->stat_no_schedulable_threads, 0);
- }
-}
diff --git a/src/vendorcode/cavium/bdk/libbdk-trust/bdk-trust.c b/src/vendorcode/cavium/bdk/libbdk-trust/bdk-trust.c
index 27c3294479..52dd702e3b 100644
--- a/src/vendorcode/cavium/bdk/libbdk-trust/bdk-trust.c
+++ b/src/vendorcode/cavium/bdk/libbdk-trust/bdk-trust.c
@@ -37,225 +37,8 @@
* ARISING OUT OF USE OR PERFORMANCE OF THE SOFTWARE LIES WITH YOU.
***********************license end**************************************/
#include <bdk.h>
-#include "libbdk-arch/bdk-csrs-fusf.h"
-#include "libbdk-arch/bdk-csrs-rom.h"
-/* The define BDK_TRUST_HARD_BLOW_NV controls whether the BDK will
- hard blow the secure NV counter on boot. This is needed for a
- production system, but can be dangerous in a development
- environment. The default value of 0 is to prevent bricking of
- chips due to CSIB[NVCOUNT] mistakes. BDK_TRUST_HARD_BLOW_NV must
- be changed to a 1 for production. The code below will display a
- warning if BDK_TRUST_HARD_BLOW_NV=0 in a trusted boot to remind
- you */
-#define BDK_TRUST_HARD_BLOW_NV 0
-
-/* The CSIB used to boot will be stored here by bsk-start.S */
-union bdk_rom_csib_s __bdk_trust_csib __attribute__((section("init")));
-static bdk_trust_level_t __bdk_trust_level = BDK_TRUST_LEVEL_BROKEN;
-
-/**
- * Update the fused secure NV counter to reflect the CSIB[NVCOUNT] value. In
- * production systems, be sure to set BDK_TRUST_HARD_BLOW_NV=1.
- */
-static void __bdk_program_nv_counter(void)
-{
- int hw_nv = bdk_trust_get_nv_counter();
- int csib_nv = __bdk_trust_csib.s.nvcnt;
-
- if (!BDK_TRUST_HARD_BLOW_NV)
- {
- printf("\33[1m"); /* Bold */
- bdk_warn("\n");
- bdk_warn("********************************************************\n");
- bdk_warn("* Configured for soft blow of secure NV counter. This\n");
- bdk_warn("* build is not suitable for production trusted boot.\n");
- bdk_warn("********************************************************\n");
- bdk_warn("\n");
- printf("\33[0m"); /* Normal */
- }
-
- /* Check if the CSIB NV counter is less than the HW fused values.
- This means the image is an old rollback. Refuse to run */
- if (csib_nv < hw_nv)
- bdk_fatal("CSIB[NVCOUNT] is less than FUSF_CTL[ROM_T_CNT]. Image rollback not allowed\n");
- /* If the CSIB NV counter matches the HW fuses, everything is
- good */
- if (csib_nv == hw_nv)
- return;
- /* CSIB NV counter is larger than the HW fuses. We must blow
- fuses to move the hardware counter forward, protecting from
- image rollback */
- if (BDK_TRUST_HARD_BLOW_NV)
- {
- BDK_TRACE(INIT, "Trust: Hard blow secure NV counter to %d\n", csib_nv);
- uint64_t v = 1ull << BDK_FUSF_FUSE_NUM_E_ROM_T_CNTX(csib_nv - 1);
- bdk_fuse_field_hard_blow(bdk_numa_master(), BDK_FUSF_FUSE_NUM_E_FUSF_LCK, v, 0);
- }
- else
- {
- BDK_TRACE(INIT, "Trust: Soft blow secure NV counter to %d\n", csib_nv);
- bdk_fuse_field_soft_blow(bdk_numa_master(), BDK_FUSF_FUSE_NUM_E_ROM_T_CNTX(csib_nv - 1));
- }
-}
-
-/**
- * Called by boot stub (TBL1FW) to initialize the state of trust
- */
-void __bdk_trust_init(void)
-{
- extern uint64_t __bdk_init_reg_pc; /* The contents of PC when this image started */
- const bdk_node_t node = bdk_numa_local();
- volatile uint64_t *huk = bdk_phys_to_ptr(bdk_numa_get_address(node, BDK_FUSF_HUKX(0)));
-
- /* Non-trusted boot address */
- if (__bdk_init_reg_pc == 0x120000)
- {
- __bdk_trust_level = BDK_TRUST_LEVEL_NONE;
- if (huk[0] | huk[1])
- {
- BDK_TRACE(INIT, "Trust: Initial image, Non-trusted boot with HUK\n");
- goto fail_trust;
- }
- else
- {
- BDK_TRACE(INIT, "Trust: Initial image, Non-trusted boot without HUK\n");
- goto skip_trust;
- }
- }
-
- if (__bdk_init_reg_pc != 0x150000)
- {
- /* Not the first image */
- BDK_CSR_INIT(rst_boot, node, BDK_RST_BOOT);
- if (!rst_boot.s.trusted_mode)
- {
- __bdk_trust_level = BDK_TRUST_LEVEL_NONE;
- BDK_TRACE(INIT, "Trust: Secondary image, non-trusted boot\n");
- goto skip_trust;
- }
- int csibsize = 0;
- const union bdk_rom_csib_s *csib = bdk_config_get_blob(&csibsize, BDK_CONFIG_TRUST_CSIB);
- if (!csib)
- {
- __bdk_trust_level = BDK_TRUST_LEVEL_NONE;
- BDK_TRACE(INIT, "Trust: Secondary image, non-trusted boot\n");
- goto skip_trust;
- }
- if (csibsize != sizeof(__bdk_trust_csib))
- {
- BDK_TRACE(INIT, "Trust: Secondary image, Trusted boot with corrupt CSIB, trust broken\n");
- goto fail_trust;
- }
- /* Record our trust level */
- switch (csib->s.crypt)
- {
- case 0:
- __bdk_trust_level = BDK_TRUST_LEVEL_SIGNED;
- BDK_TRACE(INIT, "Trust: Secondary image, Trused boot, no encryption\n");
- goto success_trust;
- case 1:
- __bdk_trust_level = BDK_TRUST_LEVEL_SIGNED_SSK;
- BDK_TRACE(INIT, "Trust: Secondary image, Trused boot, SSK encryption\n");
- goto success_trust;
- case 2:
- __bdk_trust_level = BDK_TRUST_LEVEL_SIGNED_BSSK;
- BDK_TRACE(INIT, "Trust: Secondary image, Trused boot, BSSK encryption\n");
- goto success_trust;
- default:
- __bdk_trust_level = BDK_TRUST_LEVEL_BROKEN;
- BDK_TRACE(INIT, "Trust: Secondary image, Trusted boot, Corrupt CSIB[crypt], trust broken\n");
- goto fail_trust;
- }
- }
-
- /* Copy the Root of Trust public key out of the CSIB */
- volatile uint64_t *rot_pub_key = bdk_key_alloc(node, 64);
- if (!rot_pub_key)
- {
- __bdk_trust_level = BDK_TRUST_LEVEL_BROKEN;
- BDK_TRACE(INIT, "Trust: Failed to allocate ROT memory, trust broken\n");
- goto fail_trust;
- }
- rot_pub_key[0] = bdk_le64_to_cpu(__bdk_trust_csib.s.rotpk0);
- rot_pub_key[1] = bdk_le64_to_cpu(__bdk_trust_csib.s.rotpk1);
- rot_pub_key[2] = bdk_le64_to_cpu(__bdk_trust_csib.s.rotpk2);
- rot_pub_key[3] = bdk_le64_to_cpu(__bdk_trust_csib.s.rotpk3);
- rot_pub_key[4] = bdk_le64_to_cpu(__bdk_trust_csib.s.rotpk4);
- rot_pub_key[5] = bdk_le64_to_cpu(__bdk_trust_csib.s.rotpk5);
- rot_pub_key[6] = bdk_le64_to_cpu(__bdk_trust_csib.s.rotpk6);
- rot_pub_key[7] = bdk_le64_to_cpu(__bdk_trust_csib.s.rotpk7);
- bdk_config_set_int(bdk_ptr_to_phys((void*)rot_pub_key), BDK_CONFIG_TRUST_ROT_ADDR);
- BDK_TRACE(INIT, "Trust: ROT %016lx %016lx %016lx %016lx %016lx %016lx %016lx %016lx\n",
- bdk_cpu_to_be64(rot_pub_key[0]), bdk_cpu_to_be64(rot_pub_key[1]),
- bdk_cpu_to_be64(rot_pub_key[2]), bdk_cpu_to_be64(rot_pub_key[3]),
- bdk_cpu_to_be64(rot_pub_key[4]), bdk_cpu_to_be64(rot_pub_key[5]),
- bdk_cpu_to_be64(rot_pub_key[6]), bdk_cpu_to_be64(rot_pub_key[7]));
-
- /* Update the secure NV counter with the value in the CSIB */
- __bdk_program_nv_counter();
-
- /* Create the BSSK */
- if (huk[0] | huk[1])
- {
- uint64_t iv[2] = {0, 0};
- volatile uint64_t *bssk = bdk_key_alloc(node, 16);
- if (!bssk)
- {
- __bdk_trust_level = BDK_TRUST_LEVEL_BROKEN;
- BDK_TRACE(INIT, "Trust: Failed to allocate BSSK memory, trust broken\n");
- goto fail_trust;
- }
- BDK_TRACE(INIT, "Trust: Calculating BSSK\n");
- uint64_t tmp_bssk[2];
- tmp_bssk[0] = __bdk_trust_csib.s.fs0;
- tmp_bssk[1] = __bdk_trust_csib.s.fs1;
- bdk_aes128cbc_decrypt((void*)huk, (void*)tmp_bssk, 16, iv);
- bssk[0] = tmp_bssk[0];
- bssk[1] = tmp_bssk[1];
- tmp_bssk[0] = 0;
- tmp_bssk[1] = 0;
- bdk_config_set_int(bdk_ptr_to_phys((void*)bssk), BDK_CONFIG_TRUST_BSSK_ADDR);
- //BDK_TRACE(INIT, "Trust: BSSK %016lx %016lx\n", bdk_cpu_to_be64(bssk[0]), bdk_cpu_to_be64(bssk[1]));
- }
-
- /* Record our trust level */
- switch (__bdk_trust_csib.s.crypt)
- {
- case 0:
- __bdk_trust_level = BDK_TRUST_LEVEL_SIGNED;
- BDK_TRACE(INIT, "Trust: Trused boot, no encryption\n");
- break;
- case 1:
- __bdk_trust_level = BDK_TRUST_LEVEL_SIGNED_SSK;
- BDK_TRACE(INIT, "Trust: Trused boot, SSK encryption\n");
- break;
- case 2:
- __bdk_trust_level = BDK_TRUST_LEVEL_SIGNED_BSSK;
- BDK_TRACE(INIT, "Trust: Trused boot, BSSK encryption\n");
- break;
- default:
- __bdk_trust_level = BDK_TRUST_LEVEL_BROKEN;
- goto fail_trust;
- }
-
- /* We started at the trusted boot address, CSIB should be
- valid */
- bdk_config_set_blob(sizeof(__bdk_trust_csib), &__bdk_trust_csib, BDK_CONFIG_TRUST_CSIB);
-success_trust:
- bdk_signed_load_public();
- return;
-
-fail_trust:
- /* Hide secrets */
- BDK_CSR_MODIFY(c, node, BDK_RST_BOOT,
- c.s.dis_huk = 1);
- BDK_TRACE(INIT, "Trust: Secrets Hidden\n");
-skip_trust:
- /* Erase CSIB as it is invalid */
- memset(&__bdk_trust_csib, 0, sizeof(__bdk_trust_csib));
- bdk_config_set_blob(0, NULL, BDK_CONFIG_TRUST_CSIB);
-}
+#include <libbdk-trust/bdk-trust.h>
/**
* Returns the current level of trust. Must be called after
@@ -265,22 +48,7 @@ skip_trust:
*/
bdk_trust_level_t bdk_trust_get_level(void)
{
- return __bdk_trust_level;
-}
-
-/**
- * Return the current secure NV counter stored in the fuses
- *
- * @return NV counter (0-31)
- */
-int bdk_trust_get_nv_counter(void)
-{
- /* Count leading zeros in FUSF_CTL[ROM_T_CNT] to dermine the
- hardware NV value */
- BDK_CSR_INIT(fusf_ctl, bdk_numa_master(), BDK_FUSF_CTL);
- int hw_nv = 0;
- if (fusf_ctl.s.rom_t_cnt)
- hw_nv = 32 - __builtin_clz(fusf_ctl.s.rom_t_cnt);
- return hw_nv;
+ // FIXME
+ return BDK_TRUST_LEVEL_NONE;
}
diff --git a/src/vendorcode/cavium/bdk/libdram/dram-env.c b/src/vendorcode/cavium/bdk/libdram/dram-env.c
index f25e6bdb26..61cce78d3c 100644
--- a/src/vendorcode/cavium/bdk/libdram/dram-env.c
+++ b/src/vendorcode/cavium/bdk/libdram/dram-env.c
@@ -39,6 +39,9 @@
#include <bdk.h>
#include "dram-internal.h"
+#include <string.h>
+#include <lame_string.h>
+
const char* lookup_env_parameter(const char *format, ...)
{
const char *s;
@@ -55,7 +58,7 @@ const char* lookup_env_parameter(const char *format, ...)
{
value = strtoul(s, NULL, 0);
error_print("Parameter found in environment: %s = \"%s\" 0x%lx (%ld)\n",
- buffer, s, value, value);
+ buffer, s, value, value);
}
return s;
}
@@ -76,7 +79,7 @@ const char* lookup_env_parameter_ull(const char *format, ...)
{
value = strtoull(s, NULL, 0);
error_print("Parameter found in environment: %s = 0x%016llx\n",
- buffer, value);
+ buffer, value);
}
return s;
}
diff --git a/src/vendorcode/cavium/bdk/libdram/dram-env.h b/src/vendorcode/cavium/bdk/libdram/dram-env.h
index 0f100e1b25..f190c29290 100644
--- a/src/vendorcode/cavium/bdk/libdram/dram-env.h
+++ b/src/vendorcode/cavium/bdk/libdram/dram-env.h
@@ -42,7 +42,9 @@
* Intenral use only.
*/
-
+#ifndef __DRAM_ENV_H_
+#define __DRAM_ENV_H_
extern const char *lookup_env_parameter(const char *format, ...) __attribute__ ((format(printf, 1, 2)));
extern const char *lookup_env_parameter_ull(const char *format, ...) __attribute__ ((format(printf, 1, 2)));
+#endif
diff --git a/src/vendorcode/cavium/bdk/libdram/dram-init-ddr3.c b/src/vendorcode/cavium/bdk/libdram/dram-init-ddr3.c
index edb42312f1..1c988088e9 100644
--- a/src/vendorcode/cavium/bdk/libdram/dram-init-ddr3.c
+++ b/src/vendorcode/cavium/bdk/libdram/dram-init-ddr3.c
@@ -41,6 +41,14 @@
#include "libbdk-arch/bdk-csrs-mio_fus.h"
#include "dram-internal.h"
+#include <stdlib.h>
+#include <string.h>
+#include <libbdk-hal/bdk-config.h>
+#include <libbdk-hal/bdk-l2c.h>
+#include <libbdk-hal/bdk-rng.h>
+#include <libbdk-trust/bdk-trust.h>
+#include <lame_string.h>
+
#define WODT_MASK_2R_1S 1 // FIXME: did not seem to make much difference with #152 1-slot?
#define DESKEW_RODT_CTL 1
@@ -130,37 +138,37 @@ Get_Deskew_Settings(bdk_node_t node, int ddr_interface_num, deskew_data_t *dskda
memset(dskdat, 0, sizeof(*dskdat));
- BDK_CSR_MODIFY(phy_ctl, node, BDK_LMCX_PHY_CTL(ddr_interface_num),
- phy_ctl.s.dsk_dbg_clk_scaler = 3);
+ BDK_CSR_MODIFY(_phy_ctl, node, BDK_LMCX_PHY_CTL(ddr_interface_num),
+ _phy_ctl.s.dsk_dbg_clk_scaler = 3);
for (byte_lane = 0; byte_lane < byte_limit; byte_lane++) {
bit_index = 0;
- for (bit_num = 0; bit_num <= bit_end; ++bit_num) { // NOTE: this is for pass 2.x
+ for (bit_num = 0; bit_num <= bit_end; ++bit_num) { // NOTE: this is for pass 2.x
- if (bit_num == 4) continue;
- if ((bit_num == 5) && is_t88p2) continue; // NOTE: this is for pass 2.x
+ if (bit_num == 4) continue;
+ if ((bit_num == 5) && is_t88p2) continue; // NOTE: this is for pass 2.x
// set byte lane and bit to read
- BDK_CSR_MODIFY(phy_ctl, node, BDK_LMCX_PHY_CTL(ddr_interface_num),
- (phy_ctl.s.dsk_dbg_bit_sel = bit_num,
- phy_ctl.s.dsk_dbg_byte_sel = byte_lane));
+ BDK_CSR_MODIFY(_phy_ctl, node, BDK_LMCX_PHY_CTL(ddr_interface_num),
+ (_phy_ctl.s.dsk_dbg_bit_sel = bit_num,
+ _phy_ctl.s.dsk_dbg_byte_sel = byte_lane));
// start read sequence
- BDK_CSR_MODIFY(phy_ctl, node, BDK_LMCX_PHY_CTL(ddr_interface_num),
- phy_ctl.s.dsk_dbg_rd_start = 1);
+ BDK_CSR_MODIFY(_phy_ctl, node, BDK_LMCX_PHY_CTL(ddr_interface_num),
+ _phy_ctl.s.dsk_dbg_rd_start = 1);
// poll for read sequence to complete
do {
phy_ctl.u = BDK_CSR_READ(node, BDK_LMCX_PHY_CTL(ddr_interface_num));
} while (phy_ctl.s.dsk_dbg_rd_complete != 1);
-
+
// record the data
dskdat->bytes[byte_lane].bits[bit_index] = phy_ctl.s.dsk_dbg_rd_data & 0x3ff;
bit_index++;
} /* for (bit_num = 0; bit_num <= bit_end; ++bit_num) */
} /* for (byte_lane = 0; byte_lane < byte_limit; byte_lane++) */
-
+
return;
}
@@ -181,7 +189,7 @@ Display_Deskew_Data(bdk_node_t node, int ddr_interface_num,
if (print_enable) {
VB_PRT(print_enable, "N%d.LMC%d: Deskew Data: Bit => :",
node, ddr_interface_num);
- for (bit_num = 7; bit_num >= 0; --bit_num)
+ for (bit_num = 7; bit_num >= 0; --bit_num)
VB_PRT(print_enable, " %3d ", bit_num);
VB_PRT(print_enable, "\n");
}
@@ -194,8 +202,8 @@ Display_Deskew_Data(bdk_node_t node, int ddr_interface_num,
for (bit_num = 7; bit_num >= 0; --bit_num) {
- flags = dskdat->bytes[byte_lane].bits[bit_num] & 7;
- deskew = dskdat->bytes[byte_lane].bits[bit_num] >> 3;
+ flags = dskdat->bytes[byte_lane].bits[bit_num] & 7;
+ deskew = dskdat->bytes[byte_lane].bits[bit_num] >> 3;
if (print_enable)
VB_PRT(print_enable, " %3d %c", deskew, fc[flags^1]);
@@ -206,7 +214,7 @@ Display_Deskew_Data(bdk_node_t node, int ddr_interface_num,
VB_PRT(print_enable, "\n");
} /* for (byte_lane = 0; byte_lane < byte_limit; byte_lane++) */
-
+
return;
}
@@ -281,7 +289,7 @@ Validate_Read_Deskew_Training(bdk_node_t node, int rank_mask, int ddr_interface_
if (print_enable) {
VB_PRT(print_enable, "N%d.LMC%d: Deskew Settings: Bit => :",
node, ddr_interface_num);
- for (bit_num = 7; bit_num >= 0; --bit_num)
+ for (bit_num = 7; bit_num >= 0; --bit_num)
VB_PRT(print_enable, " %3d ", bit_num);
VB_PRT(print_enable, "\n");
}
@@ -292,10 +300,10 @@ Validate_Read_Deskew_Training(bdk_node_t node, int rank_mask, int ddr_interface_
node, ddr_interface_num, byte_lane,
(print_enable >= VBL_TME) ? "FINAL" : " ");
- nib_min[0] = 127; nib_min[1] = 127;
- nib_max[0] = 0; nib_max[1] = 0;
- nib_unl[0] = 0; nib_unl[1] = 0;
- //nib_sat[0] = 0; nib_sat[1] = 0;
+ nib_min[0] = 127; nib_min[1] = 127;
+ nib_max[0] = 0; nib_max[1] = 0;
+ nib_unl[0] = 0; nib_unl[1] = 0;
+ //nib_sat[0] = 0; nib_sat[1] = 0;
#if LOOK_FOR_STUCK_BYTE
bl_mask[0] = bl_mask[1] = 0;
@@ -311,14 +319,14 @@ Validate_Read_Deskew_Training(bdk_node_t node, int rank_mask, int ddr_interface_
bit_last = bit_start;
}
- for (bit_num = bit_last; bit_num >= 0; --bit_num) { // NOTE: this is for pass 2.x
- if (bit_num == 4) continue;
- if ((bit_num == 5) && is_t88p2) continue; // NOTE: this is for pass 2.x
+ for (bit_num = bit_last; bit_num >= 0; --bit_num) { // NOTE: this is for pass 2.x
+ if (bit_num == 4) continue;
+ if ((bit_num == 5) && is_t88p2) continue; // NOTE: this is for pass 2.x
- nib_num = (bit_num > 4) ? 1 : 0;
+ nib_num = (bit_num > 4) ? 1 : 0;
- flags = dskdat.bytes[byte_lane].bits[bit_index] & 7;
- deskew = dskdat.bytes[byte_lane].bits[bit_index] >> 3;
+ flags = dskdat.bytes[byte_lane].bits[bit_index] & 7;
+ deskew = dskdat.bytes[byte_lane].bits[bit_index] >> 3;
bit_index--;
counts->saturated += !!(flags & 6);
@@ -341,42 +349,42 @@ Validate_Read_Deskew_Training(bdk_node_t node, int rank_mask, int ddr_interface_
} /* for (bit_num = bit_last; bit_num >= 0; --bit_num) */
- /*
+ /*
Now look for nibble errors:
- For bit 55, it looks like a bit deskew problem. When the upper nibble of byte 6
- needs to go to saturation, bit 7 of byte 6 locks prematurely at 64.
- For DIMMs with raw card A and B, can we reset the deskew training when we encounter this case?
- The reset criteria should be looking at one nibble at a time for raw card A and B;
- if the bit-deskew setting within a nibble is different by > 33, we'll issue a reset
- to the bit deskew training.
-
- LMC0 Bit Deskew Byte(6): 64 0 - 0 - 0 - 26 61 35 64
- */
- // upper nibble range, then lower nibble range
- nibrng_errs = ((nib_max[1] - nib_min[1]) > 33) ? 1 : 0;
- nibrng_errs |= ((nib_max[0] - nib_min[0]) > 33) ? 1 : 0;
-
- // check for nibble all unlocked
- nibunl_errs = ((nib_unl[0] == 4) || (nib_unl[1] == 4)) ? 1 : 0;
-
- // check for nibble all saturated
- //nibsat_errs = ((nib_sat[0] == 4) || (nib_sat[1] == 4)) ? 1 : 0;
-
- // check for bit value errors, ie < 17 or > 110
+ For bit 55, it looks like a bit deskew problem. When the upper nibble of byte 6
+ needs to go to saturation, bit 7 of byte 6 locks prematurely at 64.
+ For DIMMs with raw card A and B, can we reset the deskew training when we encounter this case?
+ The reset criteria should be looking at one nibble at a time for raw card A and B;
+ if the bit-deskew setting within a nibble is different by > 33, we'll issue a reset
+ to the bit deskew training.
+
+ LMC0 Bit Deskew Byte(6): 64 0 - 0 - 0 - 26 61 35 64
+ */
+ // upper nibble range, then lower nibble range
+ nibrng_errs = ((nib_max[1] - nib_min[1]) > 33) ? 1 : 0;
+ nibrng_errs |= ((nib_max[0] - nib_min[0]) > 33) ? 1 : 0;
+
+ // check for nibble all unlocked
+ nibunl_errs = ((nib_unl[0] == 4) || (nib_unl[1] == 4)) ? 1 : 0;
+
+ // check for nibble all saturated
+ //nibsat_errs = ((nib_sat[0] == 4) || (nib_sat[1] == 4)) ? 1 : 0;
+
+ // check for bit value errors, ie < 17 or > 110
// FIXME? assume max always > MIN_BITVAL and min < MAX_BITVAL
- bitval_errs = ((nib_max[1] > MAX_BITVAL) || (nib_max[0] > MAX_BITVAL)) ? 1 : 0;
- bitval_errs |= ((nib_min[1] < MIN_BITVAL) || (nib_min[0] < MIN_BITVAL)) ? 1 : 0;
-
- if (((nibrng_errs != 0) || (nibunl_errs != 0) /*|| (nibsat_errs != 0)*/ || (bitval_errs != 0))
+ bitval_errs = ((nib_max[1] > MAX_BITVAL) || (nib_max[0] > MAX_BITVAL)) ? 1 : 0;
+ bitval_errs |= ((nib_min[1] < MIN_BITVAL) || (nib_min[0] < MIN_BITVAL)) ? 1 : 0;
+
+ if (((nibrng_errs != 0) || (nibunl_errs != 0) /*|| (nibsat_errs != 0)*/ || (bitval_errs != 0))
&& print_enable)
{
- VB_PRT(print_enable, " %c%c%c%c",
+ VB_PRT(print_enable, " %c%c%c%c",
(nibrng_errs)?'R':' ',
(nibunl_errs)?'U':' ',
(bitval_errs)?'V':' ',
/*(nibsat_errs)?'S':*/' ');
- }
+ }
#if LOOK_FOR_STUCK_BYTE
bit_values = __builtin_popcountl(bl_mask[0]) + __builtin_popcountl(bl_mask[1]);
@@ -389,10 +397,10 @@ Validate_Read_Deskew_Training(bdk_node_t node, int rank_mask, int ddr_interface_
if (print_enable)
VB_PRT(print_enable, "\n");
- counts->nibrng_errs |= (nibrng_errs << byte_lane);
- counts->nibunl_errs |= (nibunl_errs << byte_lane);
- //counts->nibsat_errs |= (nibsat_errs << byte_lane);
- counts->bitval_errs |= (bitval_errs << byte_lane);
+ counts->nibrng_errs |= (nibrng_errs << byte_lane);
+ counts->nibunl_errs |= (nibunl_errs << byte_lane);
+ //counts->nibsat_errs |= (nibsat_errs << byte_lane);
+ counts->bitval_errs |= (bitval_errs << byte_lane);
#if LOOK_FOR_STUCK_BYTE
// just for completeness, allow print of the stuck values bitmask after the bytelane print
@@ -404,7 +412,7 @@ Validate_Read_Deskew_Training(bdk_node_t node, int rank_mask, int ddr_interface_
#endif
} /* for (byte_lane = 0; byte_lane < byte_limit; byte_lane++) */
-
+
// restore original WR_DESKEW_ENA setting
change_wr_deskew_ena(node, ddr_interface_num, saved_wr_deskew_ena);
@@ -412,7 +420,7 @@ Validate_Read_Deskew_Training(bdk_node_t node, int rank_mask, int ddr_interface_
}
unsigned short load_dac_override(int node, int ddr_interface_num,
- int dac_value, int byte)
+ int dac_value, int byte)
{
bdk_lmcx_dll_ctl3_t ddr_dll_ctl3;
int bytex = (byte == 0x0A) ? byte : byte + 1; // single bytelanes incr by 1; A is for ALL
@@ -455,30 +463,30 @@ int read_DAC_DBI_settings(int node, int ddr_interface_num,
bit_num = (dac_or_dbi) ? 4 : 5;
if ((bit_num == 5) && !is_t88p2) { // NOTE: this is for pass 1.x
- return -1;
+ return -1;
}
for (byte_lane = 8; byte_lane >= 0 ; --byte_lane) { // FIXME: always assume ECC is available
- //set byte lane and bit to read
+ //set byte lane and bit to read
phy_ctl.s.dsk_dbg_bit_sel = bit_num;
phy_ctl.s.dsk_dbg_byte_sel = byte_lane;
DRAM_CSR_WRITE(node, BDK_LMCX_PHY_CTL(ddr_interface_num), phy_ctl.u);
- //start read sequence
+ //start read sequence
phy_ctl.u = BDK_CSR_READ(node, BDK_LMCX_PHY_CTL(ddr_interface_num));
phy_ctl.s.dsk_dbg_rd_start = 1;
DRAM_CSR_WRITE(node, BDK_LMCX_PHY_CTL(ddr_interface_num), phy_ctl.u);
- //poll for read sequence to complete
- do {
- phy_ctl.u = BDK_CSR_READ(node, BDK_LMCX_PHY_CTL(ddr_interface_num));
- } while (phy_ctl.s.dsk_dbg_rd_complete != 1);
-
- deskew = phy_ctl.s.dsk_dbg_rd_data /*>> 3*/; // leave the flag bits for DBI
- dac_value = phy_ctl.s.dsk_dbg_rd_data & 0xff;
+ //poll for read sequence to complete
+ do {
+ phy_ctl.u = BDK_CSR_READ(node, BDK_LMCX_PHY_CTL(ddr_interface_num));
+ } while (phy_ctl.s.dsk_dbg_rd_complete != 1);
- settings[byte_lane] = (dac_or_dbi) ? dac_value : deskew;
+ deskew = phy_ctl.s.dsk_dbg_rd_data /*>> 3*/; // leave the flag bits for DBI
+ dac_value = phy_ctl.s.dsk_dbg_rd_data & 0xff;
+
+ settings[byte_lane] = (dac_or_dbi) ? dac_value : deskew;
} /* for (byte_lane = 8; byte_lane >= 0 ; --byte_lane) { */
@@ -489,7 +497,7 @@ int read_DAC_DBI_settings(int node, int ddr_interface_num,
// arg dac_or_dbi is 1 for DAC, 0 for DBI
void
display_DAC_DBI_settings(int node, int lmc, int dac_or_dbi,
- int ecc_ena, int *settings, char *title)
+ int ecc_ena, int *settings, const char *title)
{
int byte;
int flags;
@@ -552,7 +560,7 @@ Perform_Offset_Training(bdk_node_t node, int rank_mask, int ddr_interface_num)
// do not print or write if CSR does not change...
if (lmc_phy_ctl.u != orig_phy_ctl) {
- ddr_print("PHY_CTL : 0x%016lx\n", lmc_phy_ctl.u);
+ ddr_print("PHY_CTL : 0x%016llx\n", lmc_phy_ctl.u);
DRAM_CSR_WRITE(node, BDK_LMCX_PHY_CTL(ddr_interface_num), lmc_phy_ctl.u);
}
@@ -680,14 +688,14 @@ Perform_Read_Deskew_Training(bdk_node_t node, int rank_mask, int ddr_interface_n
int loops, normal_loops = 1; // default to 1 NORMAL deskew training op...
const char *s;
if ((s = getenv("ddr_deskew_normal_loops")) != NULL) {
- normal_loops = strtoul(s, NULL, 0);
+ normal_loops = strtoul(s, NULL, 0);
}
#if LOOK_FOR_STUCK_BYTE
// provide override for STUCK BYTE RESETS
int do_stuck_reset = ENABLE_STUCK_BYTE_RESET;
if ((s = getenv("ddr_enable_stuck_byte_reset")) != NULL) {
- do_stuck_reset = !!strtoul(s, NULL, 0);
+ do_stuck_reset = !!strtoul(s, NULL, 0);
}
#endif
@@ -714,10 +722,10 @@ Perform_Read_Deskew_Training(bdk_node_t node, int rank_mask, int ddr_interface_n
*
* 1. Write LMC(0)_EXT_CONFIG[VREFINT_SEQ_DESKEW] = 1.
*/
- VB_PRT(VBL_SEQ, "N%d.LMC%d: Performing LMC sequence: Set vrefint_seq_deskew = 1\n",
+ VB_PRT(VBL_SEQ, "N%d.LMC%d: Performing LMC sequence: Set vrefint_seq_deskew = 1\n",
node, ddr_interface_num);
DRAM_CSR_MODIFY(ext_config, node, BDK_LMCX_EXT_CONFIG(ddr_interface_num),
- ext_config.s.vrefint_seq_deskew = 1); /* Set Deskew sequence */
+ ext_config.s.vrefint_seq_deskew = 1); /* Set Deskew sequence */
/*
* 2. Write LMC(0)_SEQ_CTL[SEQ_SEL] = 0x0A and
@@ -726,10 +734,10 @@ Perform_Read_Deskew_Training(bdk_node_t node, int rank_mask, int ddr_interface_n
* 3. Wait for LMC(0)_SEQ_CTL[SEQ_COMPLETE] to be set to 1.
*/
DRAM_CSR_MODIFY(phy_ctl, node, BDK_LMCX_PHY_CTL(ddr_interface_num),
- phy_ctl.s.phy_dsk_reset = 1); /* RESET Deskew sequence */
+ phy_ctl.s.phy_dsk_reset = 1); /* RESET Deskew sequence */
perform_octeon3_ddr3_sequence(node, rank_mask, ddr_interface_num, 0x0A); /* LMC Deskew Training */
- lock_retries = 0;
+ lock_retries = 0;
perform_read_deskew_training:
// maybe perform the NORMAL deskew training sequence multiple times before looking at lock status
@@ -744,30 +752,30 @@ Perform_Read_Deskew_Training(bdk_node_t node, int rank_mask, int ddr_interface_n
// Now go look at lock and saturation status...
Validate_Read_Deskew_Training(node, rank_mask, ddr_interface_num, &dsk_counts, print_first);
- if (print_first && !print_them_all) // after printing the first and not doing them all, no more
- print_first = 0;
+ if (print_first && !print_them_all) // after printing the first and not doing them all, no more
+ print_first = 0;
unsaturated = (dsk_counts.saturated == 0);
- locked = (dsk_counts.unlocked == 0);
+ locked = (dsk_counts.unlocked == 0);
//nibble_sat = (dsk_counts.nibsat_errs != 0);
- // only do locking retries if unsaturated or rawcard A or B, otherwise full SAT retry
- if (unsaturated || (spd_rawcard_AorB && !is_t88p2 /*&& !nibble_sat*/)) {
- if (!locked) { // and not locked
- lock_retries++;
- lock_retries_total++;
- if (lock_retries <= lock_retries_limit) {
- goto perform_read_deskew_training;
- } else {
- VB_PRT(VBL_TME, "N%d.LMC%d: LOCK RETRIES failed after %d retries\n",
+ // only do locking retries if unsaturated or rawcard A or B, otherwise full SAT retry
+ if (unsaturated || (spd_rawcard_AorB && !is_t88p2 /*&& !nibble_sat*/)) {
+ if (!locked) { // and not locked
+ lock_retries++;
+ lock_retries_total++;
+ if (lock_retries <= lock_retries_limit) {
+ goto perform_read_deskew_training;
+ } else {
+ VB_PRT(VBL_TME, "N%d.LMC%d: LOCK RETRIES failed after %d retries\n",
node, ddr_interface_num, lock_retries_limit);
- }
- } else {
- if (lock_retries_total > 0) // only print if we did try
- VB_PRT(VBL_TME, "N%d.LMC%d: LOCK RETRIES successful after %d retries\n",
+ }
+ } else {
+ if (lock_retries_total > 0) // only print if we did try
+ VB_PRT(VBL_TME, "N%d.LMC%d: LOCK RETRIES successful after %d retries\n",
node, ddr_interface_num, lock_retries);
- }
- } /* if (unsaturated || spd_rawcard_AorB) */
+ }
+ } /* if (unsaturated || spd_rawcard_AorB) */
++sat_retries;
@@ -789,14 +797,14 @@ Perform_Read_Deskew_Training(bdk_node_t node, int rank_mask, int ddr_interface_n
}
}
#endif
- /*
- * At this point, check for a DDR4 RDIMM that will not benefit from SAT retries; if so, no retries
- */
- if (spd_rawcard_AorB && !is_t88p2 /*&& !nibble_sat*/) {
- VB_PRT(VBL_TME, "N%d.LMC%d: Read Deskew Training Loop: Exiting for RAWCARD == A or B.\n",
+ /*
+ * At this point, check for a DDR4 RDIMM that will not benefit from SAT retries; if so, no retries
+ */
+ if (spd_rawcard_AorB && !is_t88p2 /*&& !nibble_sat*/) {
+ VB_PRT(VBL_TME, "N%d.LMC%d: Read Deskew Training Loop: Exiting for RAWCARD == A or B.\n",
node, ddr_interface_num);
- break; // no sat or lock retries
- }
+ break; // no sat or lock retries
+ }
} while (!unsaturated && (sat_retries < DEFAULT_SAT_RETRY_LIMIT));
@@ -817,9 +825,9 @@ Perform_Read_Deskew_Training(bdk_node_t node, int rank_mask, int ddr_interface_n
change_wr_deskew_ena(node, ddr_interface_num, saved_wr_deskew_ena);
if ((dsk_counts.nibrng_errs != 0) || (dsk_counts.nibunl_errs != 0)) {
- debug_print("N%d.LMC%d: NIBBLE ERROR(S) found, returning FAULT\n",
- node, ddr_interface_num);
- return -1; // we did retry locally, they did not help
+ debug_print("N%d.LMC%d: NIBBLE ERROR(S) found, returning FAULT\n",
+ node, ddr_interface_num);
+ return -1; // we did retry locally, they did not help
}
// NOTE: we (currently) always print one last training validation before starting Read Leveling...
@@ -837,7 +845,7 @@ do_write_deskew_op(bdk_node_t node, int ddr_interface_num,
SET_DDR_DLL_CTL3(bit_select, bit_sel);
SET_DDR_DLL_CTL3(byte_sel, byte_sel);
SET_DDR_DLL_CTL3(wr_deskew_ena, ena);
- DRAM_CSR_WRITE(node, BDK_LMCX_DLL_CTL3(ddr_interface_num), ddr_dll_ctl3.u);
+ DRAM_CSR_WRITE(node, BDK_LMCX_DLL_CTL3(ddr_interface_num), ddr_dll_ctl3.u);
ddr_dll_ctl3.u = BDK_CSR_READ(node, BDK_LMCX_DLL_CTL3(ddr_interface_num));
}
@@ -852,11 +860,11 @@ set_write_deskew_offset(bdk_node_t node, int ddr_interface_num,
SET_DDR_DLL_CTL3(bit_select, bit_sel);
SET_DDR_DLL_CTL3(byte_sel, byte_sel);
SET_DDR_DLL_CTL3(offset, offset);
- DRAM_CSR_WRITE(node, BDK_LMCX_DLL_CTL3(ddr_interface_num), ddr_dll_ctl3.u);
+ DRAM_CSR_WRITE(node, BDK_LMCX_DLL_CTL3(ddr_interface_num), ddr_dll_ctl3.u);
ddr_dll_ctl3.u = BDK_CSR_READ(node, BDK_LMCX_DLL_CTL3(ddr_interface_num));
SET_DDR_DLL_CTL3(wr_deskew_ld, 1);
- DRAM_CSR_WRITE(node, BDK_LMCX_DLL_CTL3(ddr_interface_num), ddr_dll_ctl3.u);
+ DRAM_CSR_WRITE(node, BDK_LMCX_DLL_CTL3(ddr_interface_num), ddr_dll_ctl3.u);
ddr_dll_ctl3.u = BDK_CSR_READ(node, BDK_LMCX_DLL_CTL3(ddr_interface_num));
}
@@ -872,14 +880,14 @@ Update_Write_Deskew_Settings(bdk_node_t node, int ddr_interface_num, deskew_data
byte_limit = ((lmc_config.s.mode32b) ? 4 : 8) + lmc_config.s.ecc_ena;
for (byte_lane = 0; byte_lane < byte_limit; byte_lane++) {
- for (bit_num = 0; bit_num <= 7; ++bit_num) {
+ for (bit_num = 0; bit_num <= 7; ++bit_num) {
set_write_deskew_offset(node, ddr_interface_num, bit_num, byte_lane + 1,
dskdat->bytes[byte_lane].bits[bit_num]);
} /* for (bit_num = 0; bit_num <= 7; ++bit_num) */
} /* for (byte_lane = 0; byte_lane < byte_limit; byte_lane++) */
-
+
return;
}
@@ -1014,7 +1022,7 @@ Perform_Write_Deskew_Training(bdk_node_t node, int ddr_interface_num)
if (errors & (1 << byte)) { // yes, error(s) in the byte lane in this rank
bit_errs = ((byte == 8) ? bad_bits[1] : bad_bits[0] >> (8 * byte)) & 0xFFULL;
- VB_PRT(VBL_DEV2, "N%d.LMC%d.R%d: Byte %d Value %d: Address 0x%012lx errors 0x%x/0x%x\n",
+ VB_PRT(VBL_DEV2, "N%d.LMC%d.R%d: Byte %d Value %d: Address 0x%012llx errors 0x%x/0x%x\n",
node, ddr_interface_num, rankx, byte,
dskval, phys_addr, errors, bit_errs);
@@ -1148,15 +1156,15 @@ static int compute_Vref_1slot_2rank(int rtt_wr, int rtt_park, int dqx_ctl, int r
Dprintf("Vrefpc = %d\n", Vrefpc);
if (Vrefpc < Rangepc) { // < range1 base, use range2
- Vref_range = 1 << 6; // set bit A6 for range2
- Rangepc = 4500; // range2 base is 45%
+ Vref_range = 1 << 6; // set bit A6 for range2
+ Rangepc = 4500; // range2 base is 45%
}
Vref_value = divide_nint(Vrefpc - Rangepc, 65);
if (Vref_value < 0)
- Vref_value = Vref_range; // set to base of range as lowest value
+ Vref_value = Vref_range; // set to base of range as lowest value
else
- Vref_value |= Vref_range;
+ Vref_value |= Vref_range;
Dprintf("Vref_value = %d (0x%02x)\n", Vref_value, Vref_value);
debug_print("rtt_wr:%d, rtt_park:%d, dqx_ctl:%d, Vref_value:%d (0x%x)\n",
@@ -1210,19 +1218,19 @@ static int compute_Vref_2slot_2rank(int rtt_wr, int rtt_park_00, int rtt_park_01
//printf("Vrefpc = %ld\n", Vrefpc);
if (Vrefpc < Rangepc) { // < range1 base, use range2
- Vref_range = 1 << 6; // set bit A6 for range2
- Rangepc = 4500; // range2 base is 45%
+ Vref_range = 1 << 6; // set bit A6 for range2
+ Rangepc = 4500; // range2 base is 45%
}
Vref_value = divide_nint(Vrefpc - Rangepc, 65);
if (Vref_value < 0)
- Vref_value = Vref_range; // set to base of range as lowest value
+ Vref_value = Vref_range; // set to base of range as lowest value
else
- Vref_value |= Vref_range;
+ Vref_value |= Vref_range;
//printf("Vref_value = %d (0x%02x)\n", Vref_value, Vref_value);
debug_print("rtt_wr:%d, rtt_park_00:%d, rtt_park_01:%d, dqx_ctl:%d, rtt_nom:%d, Vref_value:%d (0x%x)\n",
- rtt_wr, rtt_park_00, rtt_park_01, dqx_ctl, rtt_nom, Vref_value, Vref_value);
+ rtt_wr, rtt_park_00, rtt_park_01, dqx_ctl, rtt_nom, Vref_value, Vref_value);
return Vref_value;
}
@@ -1230,8 +1238,8 @@ static int compute_Vref_2slot_2rank(int rtt_wr, int rtt_park_00, int rtt_park_01
// NOTE: only call this for DIMMs with 1 or 2 ranks, not 4.
int
compute_vref_value(bdk_node_t node, int ddr_interface_num,
- int rankx, int dimm_count, int rank_count,
- impedence_values_t *imp_values, int is_stacked_die)
+ int rankx, int dimm_count, int rank_count,
+ impedence_values_t *imp_values, int is_stacked_die)
{
int computed_final_vref_value = 0;
@@ -1260,56 +1268,56 @@ compute_vref_value(bdk_node_t node, int ddr_interface_num,
// separate calculations for 1 vs 2 DIMMs per LMC
if (dimm_count == 1) {
- // PARK comes from this rank if 1-rank, otherwise other rank
- index = (lmc_modereg_params2.u >> ((rankx ^ (rank_count - 1)) * 10 + 0)) & 0x07;
- int rtt_park = imp_values->rtt_nom_ohms[index];
- computed_final_vref_value = compute_Vref_1slot_2rank(rtt_wr, rtt_park, dqx_ctl, rank_count);
+ // PARK comes from this rank if 1-rank, otherwise other rank
+ index = (lmc_modereg_params2.u >> ((rankx ^ (rank_count - 1)) * 10 + 0)) & 0x07;
+ int rtt_park = imp_values->rtt_nom_ohms[index];
+ computed_final_vref_value = compute_Vref_1slot_2rank(rtt_wr, rtt_park, dqx_ctl, rank_count);
} else {
- // get both PARK values from the other DIMM
- index = (lmc_modereg_params2.u >> ((rankx ^ 0x02) * 10 + 0)) & 0x07;
- int rtt_park_00 = imp_values->rtt_nom_ohms[index];
- index = (lmc_modereg_params2.u >> ((rankx ^ 0x03) * 10 + 0)) & 0x07;
- int rtt_park_01 = imp_values->rtt_nom_ohms[index];
- // NOM comes from this rank if 1-rank, otherwise other rank
- index = (lmc_modereg_params1.u >> ((rankx ^ (rank_count - 1)) * 12 + 9)) & 0x07;
- rtt_nom = imp_values->rtt_nom_ohms[index];
- computed_final_vref_value = compute_Vref_2slot_2rank(rtt_wr, rtt_park_00, rtt_park_01, dqx_ctl, rtt_nom);
+ // get both PARK values from the other DIMM
+ index = (lmc_modereg_params2.u >> ((rankx ^ 0x02) * 10 + 0)) & 0x07;
+ int rtt_park_00 = imp_values->rtt_nom_ohms[index];
+ index = (lmc_modereg_params2.u >> ((rankx ^ 0x03) * 10 + 0)) & 0x07;
+ int rtt_park_01 = imp_values->rtt_nom_ohms[index];
+ // NOM comes from this rank if 1-rank, otherwise other rank
+ index = (lmc_modereg_params1.u >> ((rankx ^ (rank_count - 1)) * 12 + 9)) & 0x07;
+ rtt_nom = imp_values->rtt_nom_ohms[index];
+ computed_final_vref_value = compute_Vref_2slot_2rank(rtt_wr, rtt_park_00, rtt_park_01, dqx_ctl, rtt_nom);
}
#if ENABLE_COMPUTED_VREF_ADJUSTMENT
{
int saved_final_vref_value = computed_final_vref_value;
- BDK_CSR_INIT(lmc_config, node, BDK_LMCX_CONFIG(ddr_interface_num));
- /*
- New computed Vref = existing computed Vref – X
+ BDK_CSR_INIT(lmc_config, node, BDK_LMCX_CONFIG(ddr_interface_num));
+ /*
+ New computed Vref = existing computed Vref – X
- The value of X is depending on different conditions. Both #122 and #139 are 2Rx4 RDIMM,
- while #124 is stacked die 2Rx4, so I conclude the results into two conditions:
+ The value of X is depending on different conditions. Both #122 and #139 are 2Rx4 RDIMM,
+ while #124 is stacked die 2Rx4, so I conclude the results into two conditions:
- 1. Stacked Die: 2Rx4
- 1-slot: offset = 7. i, e New computed Vref = existing computed Vref – 7
- 2-slot: offset = 6
+ 1. Stacked Die: 2Rx4
+ 1-slot: offset = 7. i, e New computed Vref = existing computed Vref – 7
+ 2-slot: offset = 6
2. Regular: 2Rx4
1-slot: offset = 3
- 2-slot: offset = 2
- */
- // we know we never get called unless DDR4, so test just the other conditions
- if((!!__bdk_dram_is_rdimm(node, 0)) &&
- (rank_count == 2) &&
- (lmc_config.s.mode_x4dev))
- { // it must first be RDIMM and 2-rank and x4
- if (is_stacked_die) { // now do according to stacked die or not...
- computed_final_vref_value -= (dimm_count == 1) ? 7 : 6;
- } else {
- computed_final_vref_value -= (dimm_count == 1) ? 3 : 2;
- }
+ 2-slot: offset = 2
+ */
+ // we know we never get called unless DDR4, so test just the other conditions
+ if((!!__bdk_dram_is_rdimm(node, 0)) &&
+ (rank_count == 2) &&
+ (lmc_config.s.mode_x4dev))
+ { // it must first be RDIMM and 2-rank and x4
+ if (is_stacked_die) { // now do according to stacked die or not...
+ computed_final_vref_value -= (dimm_count == 1) ? 7 : 6;
+ } else {
+ computed_final_vref_value -= (dimm_count == 1) ? 3 : 2;
+ }
// we have adjusted it, so print it out if verbosity is right
VB_PRT(VBL_TME, "N%d.LMC%d.R%d: adjusting computed vref from %2d (0x%02x) to %2d (0x%02x)\n",
node, ddr_interface_num, rankx,
saved_final_vref_value, saved_final_vref_value,
computed_final_vref_value, computed_final_vref_value);
- }
+ }
}
#endif
return computed_final_vref_value;
@@ -1376,7 +1384,7 @@ static int encode_pbank_lsb_ddr3(int pbank_lsb, int ddr_interface_wide)
static uint64_t octeon_read_lmcx_ddr3_rlevel_dbg(bdk_node_t node, int ddr_interface_num, int idx)
{
DRAM_CSR_MODIFY(c, node, BDK_LMCX_RLEVEL_CTL(ddr_interface_num),
- c.s.byte = idx);
+ c.s.byte = idx);
BDK_CSR_READ(node, BDK_LMCX_RLEVEL_CTL(ddr_interface_num));
BDK_CSR_INIT(rlevel_dbg, node, BDK_LMCX_RLEVEL_DBG(ddr_interface_num));
return rlevel_dbg.s.bitmask;
@@ -1463,29 +1471,29 @@ validate_ddr3_rlevel_bitmask(rlevel_bitmask_t *rlevel_bitmask_p, int ddr_type)
uint64_t temp;
if (bitmask == 0) {
- blank += RLEVEL_BITMASK_BLANK_ERROR;
+ blank += RLEVEL_BITMASK_BLANK_ERROR;
} else {
- /* Look for fb, the first bit */
+ /* Look for fb, the first bit */
temp = bitmask;
while (!(temp & 1)) {
firstbit++;
temp >>= 1;
}
- /* Look for lb, the last bit */
+ /* Look for lb, the last bit */
lastbit = firstbit;
while ((temp >>= 1))
lastbit++;
- /* Start with the max range to try to find the largest mask within the bitmask data */
+ /* Start with the max range to try to find the largest mask within the bitmask data */
width = MASKRANGE_BITS;
for (mask = MASKRANGE; mask > 0; mask >>= 1, --width) {
- for (mstart = lastbit - width + 1; mstart >= firstbit; --mstart) {
+ for (mstart = lastbit - width + 1; mstart >= firstbit; --mstart) {
temp = mask << mstart;
- if ((bitmask & temp) == temp)
+ if ((bitmask & temp) == temp)
goto done_now;
- }
+ }
}
done_now:
/* look for any more contiguous 1's to the right of mstart */
@@ -1501,16 +1509,16 @@ validate_ddr3_rlevel_bitmask(rlevel_bitmask_t *rlevel_bitmask_p, int ddr_type)
if (extras > 0)
toolong = RLEVEL_BITMASK_TOOLONG_ERROR * ((1 << extras) - 1);
- /* Detect if bitmask is too narrow. */
- if (width < 4)
- narrow = (4 - width) * RLEVEL_BITMASK_NARROW_ERROR;
+ /* Detect if bitmask is too narrow. */
+ if (width < 4)
+ narrow = (4 - width) * RLEVEL_BITMASK_NARROW_ERROR;
- /* detect leading bubble bits, that is, any 0's between first and mstart */
+ /* detect leading bubble bits, that is, any 0's between first and mstart */
temp = bitmask >> (firstbit + 1);
i = mstart - firstbit - 1;
while (--i >= 0) {
- if ((temp & 1) == 0)
- bubble += RLEVEL_BITMASK_BUBBLE_BITS_ERROR;
+ if ((temp & 1) == 0)
+ bubble += RLEVEL_BITMASK_BUBBLE_BITS_ERROR;
temp >>= 1;
}
@@ -1520,7 +1528,7 @@ validate_ddr3_rlevel_bitmask(rlevel_bitmask_t *rlevel_bitmask_p, int ddr_type)
if (temp & 1) { /* Detect 1 bits after the trailing end of the mask, including last. */
trailing += RLEVEL_BITMASK_TRAILING_BITS_ERROR;
} else { /* Detect trailing bubble bits, that is, any 0's between end-of-mask and last */
- tbubble += RLEVEL_BITMASK_BUBBLE_BITS_ERROR;
+ tbubble += RLEVEL_BITMASK_BUBBLE_BITS_ERROR;
}
temp >>= 1;
}
@@ -1532,7 +1540,7 @@ validate_ddr3_rlevel_bitmask(rlevel_bitmask_t *rlevel_bitmask_p, int ddr_type)
rlevel_bitmask_p->mstart = mstart;
rlevel_bitmask_p->width = width;
- VB_PRT(VBL_DEV2, "bm:%08lx mask:%02lx, width:%2u, mstart:%2d, fb:%2u, lb:%2u"
+ VB_PRT(VBL_DEV2, "bm:%08lx mask:%02llx, width:%2u, mstart:%2d, fb:%2u, lb:%2u"
" (bu:%2d, tb:%2d, bl:%2d, n:%2d, t:%2d, x:%2d) errors:%3d %s\n",
(unsigned long) bitmask, mask, width, mstart,
firstbit, lastbit, bubble, tbubble, blank, narrow,
@@ -1548,17 +1556,17 @@ static int compute_ddr3_rlevel_delay(uint8_t mstart, uint8_t width, bdk_lmcx_rle
debug_bitmask_print(" offset_en:%d", rlevel_ctl.cn8.offset_en);
if (rlevel_ctl.s.offset_en) {
- delay = max(mstart, mstart + width - 1 - rlevel_ctl.s.offset);
+ delay = max(mstart, mstart + width - 1 - rlevel_ctl.s.offset);
} else {
- /* if (rlevel_ctl.s.offset) { */ /* Experimental */
- if (0) {
- delay = max(mstart + rlevel_ctl.s.offset, mstart + 1);
- /* Insure that the offset delay falls within the bitmask */
- delay = min(delay, mstart + width-1);
- } else {
- delay = (width - 1) / 2 + mstart; /* Round down */
- /* delay = (width/2) + mstart; */ /* Round up */
- }
+ /* if (rlevel_ctl.s.offset) { */ /* Experimental */
+ if (0) {
+ delay = max(mstart + rlevel_ctl.s.offset, mstart + 1);
+ /* Insure that the offset delay falls within the bitmask */
+ delay = min(delay, mstart + width-1);
+ } else {
+ delay = (width - 1) / 2 + mstart; /* Round down */
+ /* delay = (width/2) + mstart; */ /* Round up */
+ }
}
return delay;
@@ -1568,23 +1576,23 @@ static int compute_ddr3_rlevel_delay(uint8_t mstart, uint8_t width, bdk_lmcx_rle
#define WLEVEL_BYTE_MSK ((1UL << 5) - 1)
static void update_wlevel_rank_struct(bdk_lmcx_wlevel_rankx_t *lmc_wlevel_rank,
- int byte, int delay)
+ int byte, int delay)
{
bdk_lmcx_wlevel_rankx_t temp_wlevel_rank;
if (byte >= 0 && byte <= 8) {
- temp_wlevel_rank.u = lmc_wlevel_rank->u;
- temp_wlevel_rank.u &= ~(WLEVEL_BYTE_MSK << (WLEVEL_BYTE_BITS * byte));
- temp_wlevel_rank.u |= ((delay & WLEVEL_BYTE_MSK) << (WLEVEL_BYTE_BITS * byte));
- lmc_wlevel_rank->u = temp_wlevel_rank.u;
+ temp_wlevel_rank.u = lmc_wlevel_rank->u;
+ temp_wlevel_rank.u &= ~(WLEVEL_BYTE_MSK << (WLEVEL_BYTE_BITS * byte));
+ temp_wlevel_rank.u |= ((delay & WLEVEL_BYTE_MSK) << (WLEVEL_BYTE_BITS * byte));
+ lmc_wlevel_rank->u = temp_wlevel_rank.u;
}
}
static int get_wlevel_rank_struct(bdk_lmcx_wlevel_rankx_t *lmc_wlevel_rank,
- int byte)
+ int byte)
{
int delay = 0;
if (byte >= 0 && byte <= 8) {
- delay = ((lmc_wlevel_rank->u) >> (WLEVEL_BYTE_BITS * byte)) & WLEVEL_BYTE_MSK;
+ delay = ((lmc_wlevel_rank->u) >> (WLEVEL_BYTE_BITS * byte)) & WLEVEL_BYTE_MSK;
}
return delay;
}
@@ -1593,9 +1601,9 @@ static int get_wlevel_rank_struct(bdk_lmcx_wlevel_rankx_t *lmc_wlevel_rank,
// entry = 1 is valid, entry = 0 is invalid
static int
validity_matrix[4][4] = {[0] {1,1,1,0}, // valid pairs when cv == 0: 0,0 + 0,1 + 0,2 == "7"
- [1] {0,1,1,1}, // valid pairs when cv == 1: 1,1 + 1,2 + 1,3 == "E"
- [2] {1,0,1,1}, // valid pairs when cv == 2: 2,2 + 2,3 + 2,0 == "D"
- [3] {1,1,0,1}}; // valid pairs when cv == 3: 3,3 + 3,0 + 3,1 == "B"
+ [1] {0,1,1,1}, // valid pairs when cv == 1: 1,1 + 1,2 + 1,3 == "E"
+ [2] {1,0,1,1}, // valid pairs when cv == 2: 2,2 + 2,3 + 2,0 == "D"
+ [3] {1,1,0,1}}; // valid pairs when cv == 3: 3,3 + 3,0 + 3,1 == "B"
#endif
static int
validate_seq(int *wl, int *seq)
@@ -1604,23 +1612,23 @@ validate_seq(int *wl, int *seq)
int bitnum;
seqx = 0;
while (seq[seqx+1] >= 0) { // stop on next seq entry == -1
- // but now, check current versus next
+ // but now, check current versus next
#if 0
- if ( !validity_matrix [wl[seq[seqx]]] [wl[seq[seqx+1]]] )
- return 1;
+ if ( !validity_matrix [wl[seq[seqx]]] [wl[seq[seqx+1]]] )
+ return 1;
#else
- bitnum = (wl[seq[seqx]] << 2) | wl[seq[seqx+1]];
- if (!((1 << bitnum) & 0xBDE7)) // magic validity number (see matrix above)
- return 1;
+ bitnum = (wl[seq[seqx]] << 2) | wl[seq[seqx+1]];
+ if (!((1 << bitnum) & 0xBDE7)) // magic validity number (see matrix above)
+ return 1;
#endif
- seqx++;
+ seqx++;
}
return 0;
}
static int
Validate_HW_WL_Settings(bdk_node_t node, int ddr_interface_num,
- bdk_lmcx_wlevel_rankx_t *lmc_wlevel_rank,
+ bdk_lmcx_wlevel_rankx_t *lmc_wlevel_rank,
int ecc_ena)
{
int wl[9], byte, errors;
@@ -1634,15 +1642,15 @@ Validate_HW_WL_Settings(bdk_node_t node, int ddr_interface_num,
// in the CSR, bytes 0-7 are always data, byte 8 is ECC
for (byte = 0; byte < 8+ecc_ena; byte++) {
- wl[byte] = (get_wlevel_rank_struct(lmc_wlevel_rank, byte) >> 1) & 3; // preprocess :-)
+ wl[byte] = (get_wlevel_rank_struct(lmc_wlevel_rank, byte) >> 1) & 3; // preprocess :-)
}
errors = 0;
if (__bdk_dram_is_rdimm(node, 0) != 0) { // RDIMM order
- errors = validate_seq(wl, (ecc_ena) ? rseq1 : rseq1no);
- errors += validate_seq(wl, rseq2);
+ errors = validate_seq(wl, (ecc_ena) ? rseq1 : rseq1no);
+ errors += validate_seq(wl, rseq2);
} else { // UDIMM order
- errors = validate_seq(wl, (ecc_ena) ? useq : useqno);
+ errors = validate_seq(wl, (ecc_ena) ? useq : useqno);
}
return errors;
@@ -1652,51 +1660,51 @@ Validate_HW_WL_Settings(bdk_node_t node, int ddr_interface_num,
#define RLEVEL_BYTE_MSK ((1UL << 6) - 1)
static void update_rlevel_rank_struct(bdk_lmcx_rlevel_rankx_t *lmc_rlevel_rank,
- int byte, int delay)
+ int byte, int delay)
{
bdk_lmcx_rlevel_rankx_t temp_rlevel_rank;
if (byte >= 0 && byte <= 8) {
- temp_rlevel_rank.u = lmc_rlevel_rank->u & ~(RLEVEL_BYTE_MSK << (RLEVEL_BYTE_BITS * byte));
- temp_rlevel_rank.u |= ((delay & RLEVEL_BYTE_MSK) << (RLEVEL_BYTE_BITS * byte));
- lmc_rlevel_rank->u = temp_rlevel_rank.u;
+ temp_rlevel_rank.u = lmc_rlevel_rank->u & ~(RLEVEL_BYTE_MSK << (RLEVEL_BYTE_BITS * byte));
+ temp_rlevel_rank.u |= ((delay & RLEVEL_BYTE_MSK) << (RLEVEL_BYTE_BITS * byte));
+ lmc_rlevel_rank->u = temp_rlevel_rank.u;
}
}
#if RLEXTRAS_PATCH || !DISABLE_SW_WL_PASS_2
static int get_rlevel_rank_struct(bdk_lmcx_rlevel_rankx_t *lmc_rlevel_rank,
- int byte)
+ int byte)
{
int delay = 0;
if (byte >= 0 && byte <= 8) {
- delay = ((lmc_rlevel_rank->u) >> (RLEVEL_BYTE_BITS * byte)) & RLEVEL_BYTE_MSK;
+ delay = ((lmc_rlevel_rank->u) >> (RLEVEL_BYTE_BITS * byte)) & RLEVEL_BYTE_MSK;
}
return delay;
}
#endif
static void unpack_rlevel_settings(int ddr_interface_bytemask, int ecc_ena,
- rlevel_byte_data_t *rlevel_byte,
- bdk_lmcx_rlevel_rankx_t lmc_rlevel_rank)
+ rlevel_byte_data_t *rlevel_byte,
+ bdk_lmcx_rlevel_rankx_t lmc_rlevel_rank)
{
if ((ddr_interface_bytemask & 0xff) == 0xff) {
- if (ecc_ena) {
- rlevel_byte[8].delay = lmc_rlevel_rank.cn83xx.byte7;
- rlevel_byte[7].delay = lmc_rlevel_rank.cn83xx.byte6;
- rlevel_byte[6].delay = lmc_rlevel_rank.cn83xx.byte5;
- rlevel_byte[5].delay = lmc_rlevel_rank.cn83xx.byte4;
- rlevel_byte[4].delay = lmc_rlevel_rank.cn83xx.byte8; /* ECC */
- } else {
- rlevel_byte[7].delay = lmc_rlevel_rank.cn83xx.byte7;
- rlevel_byte[6].delay = lmc_rlevel_rank.cn83xx.byte6;
- rlevel_byte[5].delay = lmc_rlevel_rank.cn83xx.byte5;
- rlevel_byte[4].delay = lmc_rlevel_rank.cn83xx.byte4;
- }
+ if (ecc_ena) {
+ rlevel_byte[8].delay = lmc_rlevel_rank.cn83xx.byte7;
+ rlevel_byte[7].delay = lmc_rlevel_rank.cn83xx.byte6;
+ rlevel_byte[6].delay = lmc_rlevel_rank.cn83xx.byte5;
+ rlevel_byte[5].delay = lmc_rlevel_rank.cn83xx.byte4;
+ rlevel_byte[4].delay = lmc_rlevel_rank.cn83xx.byte8; /* ECC */
+ } else {
+ rlevel_byte[7].delay = lmc_rlevel_rank.cn83xx.byte7;
+ rlevel_byte[6].delay = lmc_rlevel_rank.cn83xx.byte6;
+ rlevel_byte[5].delay = lmc_rlevel_rank.cn83xx.byte5;
+ rlevel_byte[4].delay = lmc_rlevel_rank.cn83xx.byte4;
+ }
} else {
- rlevel_byte[8].delay = lmc_rlevel_rank.cn83xx.byte8; /* unused */
- rlevel_byte[7].delay = lmc_rlevel_rank.cn83xx.byte7; /* unused */
- rlevel_byte[6].delay = lmc_rlevel_rank.cn83xx.byte6; /* unused */
- rlevel_byte[5].delay = lmc_rlevel_rank.cn83xx.byte5; /* unused */
- rlevel_byte[4].delay = lmc_rlevel_rank.cn83xx.byte4; /* ECC */
+ rlevel_byte[8].delay = lmc_rlevel_rank.cn83xx.byte8; /* unused */
+ rlevel_byte[7].delay = lmc_rlevel_rank.cn83xx.byte7; /* unused */
+ rlevel_byte[6].delay = lmc_rlevel_rank.cn83xx.byte6; /* unused */
+ rlevel_byte[5].delay = lmc_rlevel_rank.cn83xx.byte5; /* unused */
+ rlevel_byte[4].delay = lmc_rlevel_rank.cn83xx.byte4; /* ECC */
}
rlevel_byte[3].delay = lmc_rlevel_rank.cn83xx.byte3;
rlevel_byte[2].delay = lmc_rlevel_rank.cn83xx.byte2;
@@ -1705,30 +1713,30 @@ static void unpack_rlevel_settings(int ddr_interface_bytemask, int ecc_ena,
}
static void pack_rlevel_settings(int ddr_interface_bytemask, int ecc_ena,
- rlevel_byte_data_t *rlevel_byte,
- bdk_lmcx_rlevel_rankx_t *final_rlevel_rank)
+ rlevel_byte_data_t *rlevel_byte,
+ bdk_lmcx_rlevel_rankx_t *final_rlevel_rank)
{
bdk_lmcx_rlevel_rankx_t lmc_rlevel_rank = *final_rlevel_rank;
if ((ddr_interface_bytemask & 0xff) == 0xff) {
- if (ecc_ena) {
- lmc_rlevel_rank.cn83xx.byte7 = rlevel_byte[8].delay;
- lmc_rlevel_rank.cn83xx.byte6 = rlevel_byte[7].delay;
- lmc_rlevel_rank.cn83xx.byte5 = rlevel_byte[6].delay;
- lmc_rlevel_rank.cn83xx.byte4 = rlevel_byte[5].delay;
- lmc_rlevel_rank.cn83xx.byte8 = rlevel_byte[4].delay; /* ECC */
- } else {
- lmc_rlevel_rank.cn83xx.byte7 = rlevel_byte[7].delay;
- lmc_rlevel_rank.cn83xx.byte6 = rlevel_byte[6].delay;
- lmc_rlevel_rank.cn83xx.byte5 = rlevel_byte[5].delay;
- lmc_rlevel_rank.cn83xx.byte4 = rlevel_byte[4].delay;
- }
+ if (ecc_ena) {
+ lmc_rlevel_rank.cn83xx.byte7 = rlevel_byte[8].delay;
+ lmc_rlevel_rank.cn83xx.byte6 = rlevel_byte[7].delay;
+ lmc_rlevel_rank.cn83xx.byte5 = rlevel_byte[6].delay;
+ lmc_rlevel_rank.cn83xx.byte4 = rlevel_byte[5].delay;
+ lmc_rlevel_rank.cn83xx.byte8 = rlevel_byte[4].delay; /* ECC */
+ } else {
+ lmc_rlevel_rank.cn83xx.byte7 = rlevel_byte[7].delay;
+ lmc_rlevel_rank.cn83xx.byte6 = rlevel_byte[6].delay;
+ lmc_rlevel_rank.cn83xx.byte5 = rlevel_byte[5].delay;
+ lmc_rlevel_rank.cn83xx.byte4 = rlevel_byte[4].delay;
+ }
} else {
- lmc_rlevel_rank.cn83xx.byte8 = rlevel_byte[8].delay;
- lmc_rlevel_rank.cn83xx.byte7 = rlevel_byte[7].delay;
- lmc_rlevel_rank.cn83xx.byte6 = rlevel_byte[6].delay;
- lmc_rlevel_rank.cn83xx.byte5 = rlevel_byte[5].delay;
- lmc_rlevel_rank.cn83xx.byte4 = rlevel_byte[4].delay;
+ lmc_rlevel_rank.cn83xx.byte8 = rlevel_byte[8].delay;
+ lmc_rlevel_rank.cn83xx.byte7 = rlevel_byte[7].delay;
+ lmc_rlevel_rank.cn83xx.byte6 = rlevel_byte[6].delay;
+ lmc_rlevel_rank.cn83xx.byte5 = rlevel_byte[5].delay;
+ lmc_rlevel_rank.cn83xx.byte4 = rlevel_byte[4].delay;
}
lmc_rlevel_rank.cn83xx.byte3 = rlevel_byte[3].delay;
lmc_rlevel_rank.cn83xx.byte2 = rlevel_byte[2].delay;
@@ -1740,7 +1748,7 @@ static void pack_rlevel_settings(int ddr_interface_bytemask, int ecc_ena,
#if !DISABLE_SW_WL_PASS_2
static void rlevel_to_wlevel(bdk_lmcx_rlevel_rankx_t *lmc_rlevel_rank,
- bdk_lmcx_wlevel_rankx_t *lmc_wlevel_rank, int byte)
+ bdk_lmcx_wlevel_rankx_t *lmc_wlevel_rank, int byte)
{
int byte_delay = get_rlevel_rank_struct(lmc_rlevel_rank, byte);
@@ -1756,9 +1764,9 @@ static void rlevel_to_wlevel(bdk_lmcx_rlevel_rankx_t *lmc_rlevel_rank,
static int calc_delay_trend(int v)
{
if (v == 0)
- return (0);
+ return (0);
if (v < 0)
- return (-1);
+ return (-1);
return 1;
}
@@ -1770,7 +1778,7 @@ static int calc_delay_trend(int v)
// NOTE: "max_adj_delay_inc" argument is, by default, 1 for DDR3 and 2 for DDR4
static int nonsequential_delays(rlevel_byte_data_t *rlevel_byte,
- int start, int end, int max_adj_delay_inc)
+ int start, int end, int max_adj_delay_inc)
{
int error = 0;
int delay_trend, prev_trend = 0;
@@ -1782,36 +1790,36 @@ static int nonsequential_delays(rlevel_byte_data_t *rlevel_byte,
for (byte_idx = start; byte_idx < end; ++byte_idx) {
byte_err = 0;
- delay_diff = rlevel_byte[byte_idx+1].delay - rlevel_byte[byte_idx].delay;
- delay_trend = calc_delay_trend(delay_diff);
-
- debug_bitmask_print("Byte %d: %2d, Byte %d: %2d, delay_trend: %2d, prev_trend: %2d",
- byte_idx+0, rlevel_byte[byte_idx+0].delay,
- byte_idx+1, rlevel_byte[byte_idx+1].delay,
- delay_trend, prev_trend);
+ delay_diff = rlevel_byte[byte_idx+1].delay - rlevel_byte[byte_idx].delay;
+ delay_trend = calc_delay_trend(delay_diff);
+
+ debug_bitmask_print("Byte %d: %2d, Byte %d: %2d, delay_trend: %2d, prev_trend: %2d",
+ byte_idx+0, rlevel_byte[byte_idx+0].delay,
+ byte_idx+1, rlevel_byte[byte_idx+1].delay,
+ delay_trend, prev_trend);
/* Increment error each time the trend changes to the opposite direction.
*/
- if ((prev_trend != 0) && (delay_trend != 0) && (prev_trend != delay_trend)) {
- byte_err += RLEVEL_NONSEQUENTIAL_DELAY_ERROR;
- prev_trend = delay_trend;
- debug_bitmask_print(" => Nonsequential byte delay");
- }
+ if ((prev_trend != 0) && (delay_trend != 0) && (prev_trend != delay_trend)) {
+ byte_err += RLEVEL_NONSEQUENTIAL_DELAY_ERROR;
+ prev_trend = delay_trend;
+ debug_bitmask_print(" => Nonsequential byte delay");
+ }
- delay_inc = _abs(delay_diff); // how big was the delay change, if any
+ delay_inc = _abs(delay_diff); // how big was the delay change, if any
/* Even if the trend did not change to the opposite direction, check for
the magnitude of the change, and scale the penalty by the amount that
the size is larger than the provided limit.
*/
- if ((max_adj_delay_inc != 0) && (delay_inc > max_adj_delay_inc)) {
- byte_err += (delay_inc - max_adj_delay_inc) * RLEVEL_ADJACENT_DELAY_ERROR;
- debug_bitmask_print(" => Adjacent delay error");
- }
+ if ((max_adj_delay_inc != 0) && (delay_inc > max_adj_delay_inc)) {
+ byte_err += (delay_inc - max_adj_delay_inc) * RLEVEL_ADJACENT_DELAY_ERROR;
+ debug_bitmask_print(" => Adjacent delay error");
+ }
- debug_bitmask_print("\n");
- if (delay_trend != 0)
- prev_trend = delay_trend;
+ debug_bitmask_print("\n");
+ if (delay_trend != 0)
+ prev_trend = delay_trend;
rlevel_byte[byte_idx+1].sqerrs = byte_err;
error += byte_err;
@@ -1826,15 +1834,15 @@ static int roundup_ddr3_wlevel_bitmask(int bitmask)
int delay;
for (leader=0; leader<8; ++leader) {
- shifted_bitmask = (bitmask>>leader);
- if ((shifted_bitmask&1) == 0)
- break;
+ shifted_bitmask = (bitmask>>leader);
+ if ((shifted_bitmask&1) == 0)
+ break;
}
for (/*leader=leader*/; leader<16; ++leader) {
- shifted_bitmask = (bitmask>>(leader%8));
- if (shifted_bitmask&1)
- break;
+ shifted_bitmask = (bitmask>>(leader%8));
+ if (shifted_bitmask&1)
+ break;
}
delay = (leader & 1) ? leader + 1 : leader;
@@ -1848,10 +1856,10 @@ static int is_dll_offset_provided(const int8_t *dll_offset_table)
{
int i;
if (dll_offset_table != NULL) {
- for (i=0; i<9; ++i) {
- if (dll_offset_table[i] != 0)
- return (1);
- }
+ for (i=0; i<9; ++i) {
+ if (dll_offset_table[i] != 0)
+ return (1);
+ }
}
return (0);
}
@@ -1865,27 +1873,27 @@ static int is_dll_offset_provided(const int8_t *dll_offset_table)
#define WITH_FINAL 4
#define WITH_COMPUTE 8
static void do_display_RL(bdk_node_t node, int ddr_interface_num,
- bdk_lmcx_rlevel_rankx_t lmc_rlevel_rank,
- int rank, int flags, int score)
+ bdk_lmcx_rlevel_rankx_t lmc_rlevel_rank,
+ int rank, int flags, int score)
{
char score_buf[16];
if (flags & WITH_SCORE)
- snprintf(score_buf, sizeof(score_buf), "(%d)", score);
+ snprintf(score_buf, sizeof(score_buf), "(%d)", score);
else {
- score_buf[0] = ' '; score_buf[1] = 0;
+ score_buf[0] = ' '; score_buf[1] = 0;
}
- char *msg_buf;
+ const char *msg_buf;
char hex_buf[20];
if (flags & WITH_AVERAGE) {
- msg_buf = " DELAY AVERAGES ";
+ msg_buf = " DELAY AVERAGES ";
} else if (flags & WITH_FINAL) {
- msg_buf = " FINAL SETTINGS ";
+ msg_buf = " FINAL SETTINGS ";
} else if (flags & WITH_COMPUTE) {
- msg_buf = " COMPUTED DELAYS ";
+ msg_buf = " COMPUTED DELAYS ";
} else {
- snprintf(hex_buf, sizeof(hex_buf), "0x%016lX", lmc_rlevel_rank.u);
- msg_buf = hex_buf;
+ snprintf(hex_buf, sizeof(hex_buf), "0x%016lX", lmc_rlevel_rank.u);
+ msg_buf = hex_buf;
}
ddr_print("N%d.LMC%d.R%d: Rlevel Rank %#4x, %s : %5d %5d %5d %5d %5d %5d %5d %5d %5d %s\n",
@@ -1901,7 +1909,7 @@ static void do_display_RL(bdk_node_t node, int ddr_interface_num,
lmc_rlevel_rank.cn83xx.byte2,
lmc_rlevel_rank.cn83xx.byte1,
lmc_rlevel_rank.cn83xx.byte0,
- score_buf
+ score_buf
);
}
@@ -1948,8 +1956,8 @@ display_RL_with_computed(bdk_node_t node, int ddr_interface_num, bdk_lmcx_rlevel
static const char *with_rodt_canned_msgs[4] = { " ", "SKIPPING ", "BEST ROW ", "BEST SCORE" };
static void display_RL_with_RODT(bdk_node_t node, int ddr_interface_num,
- bdk_lmcx_rlevel_rankx_t lmc_rlevel_rank, int rank, int score,
- int nom_ohms, int rodt_ohms, int flag)
+ bdk_lmcx_rlevel_rankx_t lmc_rlevel_rank, int rank, int score,
+ int nom_ohms, int rodt_ohms, int flag)
{
const char *msg_buf;
char set_buf[20];
@@ -1987,15 +1995,15 @@ static void display_RL_with_RODT(bdk_node_t node, int ddr_interface_num,
static void
do_display_WL(bdk_node_t node, int ddr_interface_num, bdk_lmcx_wlevel_rankx_t lmc_wlevel_rank, int rank, int flags)
{
- char *msg_buf;
+ const char *msg_buf;
char hex_buf[20];
int vbl;
if (flags & WITH_FINAL) {
- msg_buf = " FINAL SETTINGS ";
+ msg_buf = " FINAL SETTINGS ";
vbl = VBL_NORM;
} else {
- snprintf(hex_buf, sizeof(hex_buf), "0x%016lX", lmc_wlevel_rank.u);
- msg_buf = hex_buf;
+ snprintf(hex_buf, sizeof(hex_buf), "0x%016lX", lmc_wlevel_rank.u);
+ msg_buf = hex_buf;
vbl = VBL_FAE;
}
@@ -2070,7 +2078,7 @@ do_display_BM(bdk_node_t node, int ddr_interface_num, int rank, void *bm, int fl
} else
if (flags == WITH_RL_BITMASKS) { // rlevel_bitmask array in PACKED index order, so just print them
rlevel_bitmask_t *rlevel_bitmask = (rlevel_bitmask_t *)bm;
- ddr_print("N%d.LMC%d.R%d: Rlevel Debug Bitmasks 8:0 : %05lx %05lx %05lx %05lx %05lx %05lx %05lx %05lx %05lx\n",
+ ddr_print("N%d.LMC%d.R%d: Rlevel Debug Bitmasks 8:0 : %05llx %05llx %05llx %05llx %05llx %05llx %05llx %05llx %05llx\n",
node, ddr_interface_num, rank,
PPBM(rlevel_bitmask[8].bm),
PPBM(rlevel_bitmask[7].bm),
@@ -2140,7 +2148,7 @@ display_RL_SEQ_scores(bdk_node_t node, int ddr_interface_num, int rank, rlevel_b
}
unsigned short load_dll_offset(bdk_node_t node, int ddr_interface_num,
- int dll_offset_mode, int byte_offset, int byte)
+ int dll_offset_mode, int byte_offset, int byte)
{
bdk_lmcx_dll_ctl3_t ddr_dll_ctl3;
/* byte_sel:
@@ -2150,17 +2158,17 @@ unsigned short load_dll_offset(bdk_node_t node, int ddr_interface_num,
ddr_dll_ctl3.u = BDK_CSR_READ(node, BDK_LMCX_DLL_CTL3(ddr_interface_num));
SET_DDR_DLL_CTL3(load_offset, 0);
- DRAM_CSR_WRITE(node, BDK_LMCX_DLL_CTL3(ddr_interface_num), ddr_dll_ctl3.u);
+ DRAM_CSR_WRITE(node, BDK_LMCX_DLL_CTL3(ddr_interface_num), ddr_dll_ctl3.u);
ddr_dll_ctl3.u = BDK_CSR_READ(node, BDK_LMCX_DLL_CTL3(ddr_interface_num));
SET_DDR_DLL_CTL3(mode_sel, dll_offset_mode);
SET_DDR_DLL_CTL3(offset, (_abs(byte_offset)&0x3f) | (_sign(byte_offset) << 6)); /* Always 6-bit field? */
SET_DDR_DLL_CTL3(byte_sel, byte_sel);
- DRAM_CSR_WRITE(node, BDK_LMCX_DLL_CTL3(ddr_interface_num), ddr_dll_ctl3.u);
+ DRAM_CSR_WRITE(node, BDK_LMCX_DLL_CTL3(ddr_interface_num), ddr_dll_ctl3.u);
ddr_dll_ctl3.u = BDK_CSR_READ(node, BDK_LMCX_DLL_CTL3(ddr_interface_num));
SET_DDR_DLL_CTL3(load_offset, 1);
- DRAM_CSR_WRITE(node, BDK_LMCX_DLL_CTL3(ddr_interface_num), ddr_dll_ctl3.u);
+ DRAM_CSR_WRITE(node, BDK_LMCX_DLL_CTL3(ddr_interface_num), ddr_dll_ctl3.u);
ddr_dll_ctl3.u = BDK_CSR_READ(node, BDK_LMCX_DLL_CTL3(ddr_interface_num));
return ((unsigned short) GET_DDR_DLL_CTL3(offset));
@@ -2172,33 +2180,33 @@ void change_dll_offset_enable(bdk_node_t node, int ddr_interface_num, int change
ddr_dll_ctl3.u = BDK_CSR_READ(node, BDK_LMCX_DLL_CTL3(ddr_interface_num));
SET_DDR_DLL_CTL3(offset_ena, !!change);
- DRAM_CSR_WRITE(node, BDK_LMCX_DLL_CTL3(ddr_interface_num), ddr_dll_ctl3.u);
+ DRAM_CSR_WRITE(node, BDK_LMCX_DLL_CTL3(ddr_interface_num), ddr_dll_ctl3.u);
ddr_dll_ctl3.u = BDK_CSR_READ(node, BDK_LMCX_DLL_CTL3(ddr_interface_num));
}
static void process_custom_dll_offsets(bdk_node_t node, int ddr_interface_num, const char *enable_str,
- const int8_t *offsets, const char *byte_str, int mode)
+ const int8_t *offsets, const char *byte_str, int mode)
{
const char *s;
int enabled;
int provided;
if ((s = lookup_env_parameter("%s", enable_str)) != NULL) {
- enabled = !!strtol(s, NULL, 0);
+ enabled = !!strtol(s, NULL, 0);
} else
- enabled = -1;
+ enabled = -1;
// enabled == -1: no override, do only configured offsets if provided
// enabled == 0: override OFF, do NOT do it even if configured offsets provided
// enabled == 1: override ON, do it for overrides plus configured offsets
if (enabled == 0)
- return;
+ return;
provided = is_dll_offset_provided(offsets);
if (enabled < 0 && !provided)
- return;
+ return;
int byte_offset;
unsigned short offset[9] = {0};
@@ -2209,27 +2217,27 @@ static void process_custom_dll_offsets(bdk_node_t node, int ddr_interface_num, c
for (byte = 0; byte < 9; ++byte) {
- // always take the provided, if available
- byte_offset = (provided) ? offsets[byte] : 0;
+ // always take the provided, if available
+ byte_offset = (provided) ? offsets[byte] : 0;
- // then, if enabled, use any overrides present
- if (enabled > 0) {
- if ((s = lookup_env_parameter(byte_str, ddr_interface_num, byte)) != NULL) {
+ // then, if enabled, use any overrides present
+ if (enabled > 0) {
+ if ((s = lookup_env_parameter(byte_str, ddr_interface_num, byte)) != NULL) {
byte_offset = strtol(s, NULL, 0);
}
- }
+ }
- offset[byte] = load_dll_offset(node, ddr_interface_num, mode, byte_offset, byte);
+ offset[byte] = load_dll_offset(node, ddr_interface_num, mode, byte_offset, byte);
}
// re-enable offsets after loading
change_dll_offset_enable(node, ddr_interface_num, 1);
ddr_print("N%d.LMC%d: DLL %s Offset 8:0 :"
- " 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x\n",
- node, ddr_interface_num, (mode == 2) ? "Read " : "Write",
- offset[8], offset[7], offset[6], offset[5], offset[4],
- offset[3], offset[2], offset[1], offset[0]);
+ " 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x\n",
+ node, ddr_interface_num, (mode == 2) ? "Read " : "Write",
+ offset[8], offset[7], offset[6], offset[5], offset[4],
+ offset[3], offset[2], offset[1], offset[0]);
}
void perform_octeon3_ddr3_sequence(bdk_node_t node, int rank_mask, int ddr_interface_num, int sequence)
@@ -2277,18 +2285,18 @@ void perform_octeon3_ddr3_sequence(bdk_node_t node, int rank_mask, int ddr_inter
const char *s;
static const char *sequence_str[] = {
- "Power-up/init",
- "Read-leveling",
- "Self-refresh entry",
- "Self-refresh exit",
- "Illegal",
- "Illegal",
- "Write-leveling",
- "Init Register Control Words",
- "Mode Register Write",
- "MPR Register Access",
- "LMC Deskew/Internal Vref training",
- "Offset Training"
+ "Power-up/init",
+ "Read-leveling",
+ "Self-refresh entry",
+ "Self-refresh exit",
+ "Illegal",
+ "Illegal",
+ "Write-leveling",
+ "Init Register Control Words",
+ "Mode Register Write",
+ "MPR Register Access",
+ "LMC Deskew/Internal Vref training",
+ "Offset Training"
};
bdk_lmcx_seq_ctl_t seq_ctl;
@@ -2307,9 +2315,13 @@ void perform_octeon3_ddr3_sequence(bdk_node_t node, int rank_mask, int ddr_inter
node, ddr_interface_num, sequence, rank_mask, sequence_str[sequence]);
if ((s = lookup_env_parameter("ddr_trigger_sequence%d", sequence)) != NULL) {
- int trigger = strtoul(s, NULL, 0);
- if (trigger)
- pulse_gpio_pin(node, 1, 2);
+ /* FIXME(dhendrix): this appears to be meant for the eval board */
+#if 0
+ int trigger = strtoul(s, NULL, 0);
+ if (trigger)
+ pulse_gpio_pin(node, 1, 2);
+#endif
+ error_print("env parameter ddr_trigger_sequence%d not found\n", sequence);
}
DRAM_CSR_WRITE(node, BDK_LMCX_SEQ_CTL(ddr_interface_num), seq_ctl.u);
@@ -2317,14 +2329,13 @@ void perform_octeon3_ddr3_sequence(bdk_node_t node, int rank_mask, int ddr_inter
/* Wait 100us minimum before checking for sequence complete */
bdk_wait_usec(100);
- if (!bdk_is_platform(BDK_PLATFORM_ASIM) &&
- BDK_CSR_WAIT_FOR_FIELD(node, BDK_LMCX_SEQ_CTL(ddr_interface_num), seq_complete, ==, 1, 1000000))
+ if (BDK_CSR_WAIT_FOR_FIELD(node, BDK_LMCX_SEQ_CTL(ddr_interface_num), seq_complete, ==, 1, 1000000))
{
- error_print("N%d.LMC%d: Timeout waiting for LMC sequence=%x, rank_mask=0x%02x, ignoring...\n",
- node, ddr_interface_num, sequence, rank_mask);
+ error_print("N%d.LMC%d: Timeout waiting for LMC sequence=%x, rank_mask=0x%02x, ignoring...\n",
+ node, ddr_interface_num, sequence, rank_mask);
}
else {
- VB_PRT(VBL_SEQ, "N%d.LMC%d: LMC sequence=%x: Completed.\n", node, ddr_interface_num, sequence);
+ VB_PRT(VBL_SEQ, "N%d.LMC%d: LMC sequence=%x: Completed.\n", node, ddr_interface_num, sequence);
}
}
@@ -2406,7 +2417,7 @@ static void do_ddr4_mpr_read(bdk_node_t node, int ddr_interface_num, int rank,
}
#endif
-int set_rdimm_mode(bdk_node_t node, int ddr_interface_num, int enable)
+static int set_rdimm_mode(bdk_node_t node, int ddr_interface_num, int enable)
{
bdk_lmcx_control_t lmc_control;
int save_rdimm_mode;
@@ -2422,7 +2433,7 @@ int set_rdimm_mode(bdk_node_t node, int ddr_interface_num, int enable)
#if ENABLE_DISPLAY_MPR_PAGE
static void ddr4_mpr_read(bdk_node_t node, int ddr_interface_num, int rank,
- int page, int location, uint64_t *mpr_data)
+ int page, int location, uint64_t *mpr_data)
{
do_ddr4_mpr_read(node, ddr_interface_num, rank, page, location);
@@ -2464,7 +2475,7 @@ static void Display_MPR_Page(bdk_node_t node, int rank_mask,
}
#endif
-void ddr4_mpr_write(bdk_node_t node, int ddr_interface_num, int rank,
+static void ddr4_mpr_write(bdk_node_t node, int ddr_interface_num, int rank,
int page, int location, uint8_t mpr_data)
{
bdk_lmcx_mr_mpr_ctl_t lmc_mr_mpr_ctl;
@@ -2495,7 +2506,7 @@ void ddr4_mpr_write(bdk_node_t node, int ddr_interface_num, int rank,
}
void set_vref(bdk_node_t node, int ddr_interface_num, int rank,
- int range, int value)
+ int range, int value)
{
bdk_lmcx_mr_mpr_ctl_t lmc_mr_mpr_ctl;
bdk_lmcx_modereg_params3_t lmc_modereg_params3;
@@ -2562,7 +2573,7 @@ static void set_DRAM_output_inversion (bdk_node_t node,
lmc_dimm_ctl.s.dimm0_wmask = 0x1;
lmc_dimm_ctl.s.dimm1_wmask = (dimm_count > 1) ? 0x0001 : 0x0000;
- ddr_print("LMC DIMM_CTL : 0x%016lx\n",
+ ddr_print("LMC DIMM_CTL : 0x%016llx\n",
lmc_dimm_ctl.u);
DRAM_CSR_WRITE(node, BDK_LMCX_DIMM_CTL(ddr_interface_num), lmc_dimm_ctl.u);
@@ -2984,8 +2995,8 @@ int init_octeon3_ddr3_interface(bdk_node_t node,
#if SWL_TRY_HWL_ALT
typedef struct {
- uint16_t hwl_alt_mask; // mask of bytelanes with alternate
- uint16_t hwl_alt_delay[9]; // bytelane alternate avail if mask=1
+ uint16_t hwl_alt_mask; // mask of bytelanes with alternate
+ uint16_t hwl_alt_delay[9]; // bytelane alternate avail if mask=1
} hwl_alt_by_rank_t;
hwl_alt_by_rank_t hwl_alts[4];
memset(hwl_alts, 0, sizeof(hwl_alts));
@@ -3065,12 +3076,12 @@ int init_octeon3_ddr3_interface(bdk_node_t node,
initialize_ddr_clock(node,
- ddr_configuration,
- cpu_hertz,
- ddr_hertz,
- ddr_ref_hertz,
- ddr_interface_num,
- ddr_interface_mask);
+ ddr_configuration,
+ cpu_hertz,
+ ddr_hertz,
+ ddr_ref_hertz,
+ ddr_interface_num,
+ ddr_interface_mask);
if (!odt_1rank_config)
odt_1rank_config = disable_odt_config;
@@ -3136,7 +3147,7 @@ int init_octeon3_ddr3_interface(bdk_node_t node,
bank_bits = (2 + ((spd_banks >> 4) & 0x3)) + ((spd_banks >> 6) & 0x3);
bank_bits = min((int)bank_bits, 4); /* Controller can only address 4 bits. */
- spd_package = 0XFF & read_spd(node, &dimm_config_table[0], DDR4_SPD_PACKAGE_TYPE);
+ spd_package = 0XFF & read_spd(node, &dimm_config_table[0], DDR4_SPD_PACKAGE_TYPE);
if (spd_package & 0x80) { // non-monolithic device
is_stacked_die = (!disable_stacked_die) ? ((spd_package & 0x73) == 0x11) : 0;
ddr_print("DDR4: Package Type 0x%x (%s), %d die\n", spd_package,
@@ -3174,7 +3185,7 @@ int init_octeon3_ddr3_interface(bdk_node_t node,
/* no. pkg ranks*/(1UL + ((spd_org >> 3) & 0x7));
if (is_3ds_dimm) // is it 3DS?
module_cap *= /* die_count */(uint64_t)(((spd_package >> 4) & 7) + 1);
- ddr_print("DDR4: Module Organization: SYMMETRICAL: capacity per module %ld GB\n",
+ ddr_print("DDR4: Module Organization: SYMMETRICAL: capacity per module %lld GB\n",
module_cap >> 30);
}
@@ -3189,16 +3200,16 @@ int init_octeon3_ddr3_interface(bdk_node_t node,
spd_dimm_type = spd_module_type & 0x0F;
spd_rdimm = (spd_dimm_type == 1) || (spd_dimm_type == 5) || (spd_dimm_type == 8);
- if (spd_rdimm) {
- int spd_mfgr_id = read_spd(node, &dimm_config_table[0], DDR4_SPD_REGISTER_MANUFACTURER_ID_LSB) |
- (read_spd(node, &dimm_config_table[0], DDR4_SPD_REGISTER_MANUFACTURER_ID_MSB) << 8);
- int spd_register_rev = read_spd(node, &dimm_config_table[0], DDR4_SPD_REGISTER_REVISION_NUMBER);
- ddr_print("DDR4: RDIMM Register Manufacturer ID 0x%x Revision 0x%x\n",
- spd_mfgr_id, spd_register_rev);
+ if (spd_rdimm) {
+ int spd_mfgr_id = read_spd(node, &dimm_config_table[0], DDR4_SPD_REGISTER_MANUFACTURER_ID_LSB) |
+ (read_spd(node, &dimm_config_table[0], DDR4_SPD_REGISTER_MANUFACTURER_ID_MSB) << 8);
+ int spd_register_rev = read_spd(node, &dimm_config_table[0], DDR4_SPD_REGISTER_REVISION_NUMBER);
+ ddr_print("DDR4: RDIMM Register Manufacturer ID 0x%x Revision 0x%x\n",
+ spd_mfgr_id, spd_register_rev);
// RAWCARD A or B must be bit 7=0 and bits 4-0 either 00000(A) or 00001(B)
- spd_rawcard_AorB = ((spd_rawcard & 0x9fUL) <= 1);
- }
+ spd_rawcard_AorB = ((spd_rawcard & 0x9fUL) <= 1);
+ }
} else {
imp_values = &ddr3_impedence_values;
dimm_type_name = ddr3_dimm_types[spd_dimm_type];
@@ -3254,17 +3265,13 @@ int init_octeon3_ddr3_interface(bdk_node_t node,
++fatal_error;
}
- if (bdk_is_platform(BDK_PLATFORM_ASIM))
- wlevel_loops = 0;
- else {
- wlevel_loops = WLEVEL_LOOPS_DEFAULT;
- // accept generic or interface-specific override but not for ASIM...
- if ((s = lookup_env_parameter("ddr_wlevel_loops")) == NULL)
- s = lookup_env_parameter("ddr%d_wlevel_loops", ddr_interface_num);
- if (s != NULL) {
- wlevel_loops = strtoul(s, NULL, 0);
- }
- }
+ wlevel_loops = WLEVEL_LOOPS_DEFAULT;
+ // accept generic or interface-specific override but not for ASIM...
+ if ((s = lookup_env_parameter("ddr_wlevel_loops")) == NULL)
+ s = lookup_env_parameter("ddr%d_wlevel_loops", ddr_interface_num);
+ if (s != NULL) {
+ wlevel_loops = strtoul(s, NULL, 0);
+ }
bunk_enable = (num_ranks > 1);
@@ -3360,13 +3367,13 @@ int init_octeon3_ddr3_interface(bdk_node_t node,
}
if (ddr_type == DDR4_DRAM) {
- spd_cas_latency = ((0xff & read_spd(node, &dimm_config_table[0], DDR4_SPD_CAS_LATENCIES_BYTE0)) << 0);
- spd_cas_latency |= ((0xff & read_spd(node, &dimm_config_table[0], DDR4_SPD_CAS_LATENCIES_BYTE1)) << 8);
- spd_cas_latency |= ((0xff & read_spd(node, &dimm_config_table[0], DDR4_SPD_CAS_LATENCIES_BYTE2)) << 16);
- spd_cas_latency |= ((0xff & read_spd(node, &dimm_config_table[0], DDR4_SPD_CAS_LATENCIES_BYTE3)) << 24);
+ spd_cas_latency = ((0xff & read_spd(node, &dimm_config_table[0], DDR4_SPD_CAS_LATENCIES_BYTE0)) << 0);
+ spd_cas_latency |= ((0xff & read_spd(node, &dimm_config_table[0], DDR4_SPD_CAS_LATENCIES_BYTE1)) << 8);
+ spd_cas_latency |= ((0xff & read_spd(node, &dimm_config_table[0], DDR4_SPD_CAS_LATENCIES_BYTE2)) << 16);
+ spd_cas_latency |= ((0xff & read_spd(node, &dimm_config_table[0], DDR4_SPD_CAS_LATENCIES_BYTE3)) << 24);
} else {
- spd_cas_latency = 0xff & read_spd(node, &dimm_config_table[0], DDR3_SPD_CAS_LATENCIES_LSB);
- spd_cas_latency |= ((0xff & read_spd(node, &dimm_config_table[0], DDR3_SPD_CAS_LATENCIES_MSB)) << 8);
+ spd_cas_latency = 0xff & read_spd(node, &dimm_config_table[0], DDR3_SPD_CAS_LATENCIES_LSB);
+ spd_cas_latency |= ((0xff & read_spd(node, &dimm_config_table[0], DDR3_SPD_CAS_LATENCIES_MSB)) << 8);
}
debug_print("spd_cas_latency : %#06x\n", spd_cas_latency );
@@ -3380,37 +3387,37 @@ int init_octeon3_ddr3_interface(bdk_node_t node,
int spdFTB = 1;
tAAmin
- = spdMTB * read_spd(node, &dimm_config_table[0], DDR4_SPD_MIN_CAS_LATENCY_TAAMIN)
- + spdFTB * (SC_t) read_spd(node, &dimm_config_table[0], DDR4_SPD_MIN_CAS_LATENCY_FINE_TAAMIN);
+ = spdMTB * read_spd(node, &dimm_config_table[0], DDR4_SPD_MIN_CAS_LATENCY_TAAMIN)
+ + spdFTB * (SC_t) read_spd(node, &dimm_config_table[0], DDR4_SPD_MIN_CAS_LATENCY_FINE_TAAMIN);
ddr4_tCKAVGmin
- = spdMTB * read_spd(node, &dimm_config_table[0], DDR4_SPD_MINIMUM_CYCLE_TIME_TCKAVGMIN)
- + spdFTB * (SC_t) read_spd(node, &dimm_config_table[0], DDR4_SPD_MIN_CYCLE_TIME_FINE_TCKAVGMIN);
+ = spdMTB * read_spd(node, &dimm_config_table[0], DDR4_SPD_MINIMUM_CYCLE_TIME_TCKAVGMIN)
+ + spdFTB * (SC_t) read_spd(node, &dimm_config_table[0], DDR4_SPD_MIN_CYCLE_TIME_FINE_TCKAVGMIN);
ddr4_tCKAVGmax
- = spdMTB * read_spd(node, &dimm_config_table[0], DDR4_SPD_MAXIMUM_CYCLE_TIME_TCKAVGMAX)
- + spdFTB * (SC_t) read_spd(node, &dimm_config_table[0], DDR4_SPD_MAX_CYCLE_TIME_FINE_TCKAVGMAX);
+ = spdMTB * read_spd(node, &dimm_config_table[0], DDR4_SPD_MAXIMUM_CYCLE_TIME_TCKAVGMAX)
+ + spdFTB * (SC_t) read_spd(node, &dimm_config_table[0], DDR4_SPD_MAX_CYCLE_TIME_FINE_TCKAVGMAX);
ddr4_tRCDmin
- = spdMTB * read_spd(node, &dimm_config_table[0], DDR4_SPD_MIN_RAS_CAS_DELAY_TRCDMIN)
- + spdFTB * (SC_t) read_spd(node, &dimm_config_table[0], DDR4_SPD_MIN_RAS_TO_CAS_DELAY_FINE_TRCDMIN);
+ = spdMTB * read_spd(node, &dimm_config_table[0], DDR4_SPD_MIN_RAS_CAS_DELAY_TRCDMIN)
+ + spdFTB * (SC_t) read_spd(node, &dimm_config_table[0], DDR4_SPD_MIN_RAS_TO_CAS_DELAY_FINE_TRCDMIN);
ddr4_tRPmin
- = spdMTB * read_spd(node, &dimm_config_table[0], DDR4_SPD_MIN_ROW_PRECHARGE_DELAY_TRPMIN)
- + spdFTB * (SC_t) read_spd(node, &dimm_config_table[0], DDR4_SPD_MIN_ROW_PRECHARGE_DELAY_FINE_TRPMIN);
+ = spdMTB * read_spd(node, &dimm_config_table[0], DDR4_SPD_MIN_ROW_PRECHARGE_DELAY_TRPMIN)
+ + spdFTB * (SC_t) read_spd(node, &dimm_config_table[0], DDR4_SPD_MIN_ROW_PRECHARGE_DELAY_FINE_TRPMIN);
ddr4_tRASmin
- = spdMTB * (((read_spd(node, &dimm_config_table[0], DDR4_SPD_UPPER_NIBBLES_TRAS_TRC) & 0xf) << 8) +
- ( read_spd(node, &dimm_config_table[0], DDR4_SPD_MIN_ACTIVE_PRECHARGE_LSB_TRASMIN) & 0xff));
+ = spdMTB * (((read_spd(node, &dimm_config_table[0], DDR4_SPD_UPPER_NIBBLES_TRAS_TRC) & 0xf) << 8) +
+ ( read_spd(node, &dimm_config_table[0], DDR4_SPD_MIN_ACTIVE_PRECHARGE_LSB_TRASMIN) & 0xff));
ddr4_tRCmin
- = spdMTB * ((((read_spd(node, &dimm_config_table[0], DDR4_SPD_UPPER_NIBBLES_TRAS_TRC) >> 4) & 0xf) << 8) +
- ( read_spd(node, &dimm_config_table[0], DDR4_SPD_MIN_ACTIVE_REFRESH_LSB_TRCMIN) & 0xff))
- + spdFTB * (SC_t) read_spd(node, &dimm_config_table[0], DDR4_SPD_MIN_ACT_TO_ACT_REFRESH_DELAY_FINE_TRCMIN);
+ = spdMTB * ((((read_spd(node, &dimm_config_table[0], DDR4_SPD_UPPER_NIBBLES_TRAS_TRC) >> 4) & 0xf) << 8) +
+ ( read_spd(node, &dimm_config_table[0], DDR4_SPD_MIN_ACTIVE_REFRESH_LSB_TRCMIN) & 0xff))
+ + spdFTB * (SC_t) read_spd(node, &dimm_config_table[0], DDR4_SPD_MIN_ACT_TO_ACT_REFRESH_DELAY_FINE_TRCMIN);
ddr4_tRFC1min
- = spdMTB * (((read_spd(node, &dimm_config_table[0], DDR4_SPD_MIN_REFRESH_RECOVERY_MSB_TRFC1MIN) & 0xff) << 8) +
- ( read_spd(node, &dimm_config_table[0], DDR4_SPD_MIN_REFRESH_RECOVERY_LSB_TRFC1MIN) & 0xff));
+ = spdMTB * (((read_spd(node, &dimm_config_table[0], DDR4_SPD_MIN_REFRESH_RECOVERY_MSB_TRFC1MIN) & 0xff) << 8) +
+ ( read_spd(node, &dimm_config_table[0], DDR4_SPD_MIN_REFRESH_RECOVERY_LSB_TRFC1MIN) & 0xff));
ddr4_tRFC2min
= spdMTB * (((read_spd(node, &dimm_config_table[0], DDR4_SPD_MIN_REFRESH_RECOVERY_MSB_TRFC2MIN) & 0xff) << 8) +
@@ -3436,14 +3443,14 @@ int init_octeon3_ddr3_interface(bdk_node_t node,
= spdMTB * read_spd(node, &dimm_config_table[0], DDR4_SPD_MIN_CAS_TO_CAS_DELAY_TCCD_LMIN)
+ spdFTB * (SC_t) read_spd(node, &dimm_config_table[0], DDR4_SPD_MIN_CAS_TO_CAS_DELAY_FINE_TCCD_LMIN);
- ddr_print("%-45s : %6d ps\n", "Medium Timebase (MTB)", spdMTB);
- ddr_print("%-45s : %6d ps\n", "Fine Timebase (FTB)", spdFTB);
+ ddr_print("%-45s : %6d ps\n", "Medium Timebase (MTB)", spdMTB);
+ ddr_print("%-45s : %6d ps\n", "Fine Timebase (FTB)", spdFTB);
#define DDR4_TWR 15000
#define DDR4_TWTR_S 2500
- tCKmin = ddr4_tCKAVGmin;
+ tCKmin = ddr4_tCKAVGmin;
twr = DDR4_TWR;
trcd = ddr4_tRCDmin;
trrd = ddr4_tRRD_Smin;
@@ -3455,9 +3462,9 @@ int init_octeon3_ddr3_interface(bdk_node_t node,
tfaw = ddr4_tFAWmin;
if (spd_rdimm) {
- spd_addr_mirror = read_spd(node, &dimm_config_table[0], DDR4_SPD_RDIMM_ADDR_MAPPING_FROM_REGISTER_TO_DRAM) & 0x1;
+ spd_addr_mirror = read_spd(node, &dimm_config_table[0], DDR4_SPD_RDIMM_ADDR_MAPPING_FROM_REGISTER_TO_DRAM) & 0x1;
} else {
- spd_addr_mirror = read_spd(node, &dimm_config_table[0], DDR4_SPD_UDIMM_ADDR_MAPPING_FROM_EDGE) & 0x1;
+ spd_addr_mirror = read_spd(node, &dimm_config_table[0], DDR4_SPD_UDIMM_ADDR_MAPPING_FROM_EDGE) & 0x1;
}
debug_print("spd_addr_mirror : %#06x\n", spd_addr_mirror );
@@ -3535,20 +3542,20 @@ int init_octeon3_ddr3_interface(bdk_node_t node,
ddr_print("%-45s : %6d ps\n", "Minimum Act. to Act. Delay (tRRD_Lmin)", ddr4_tRRD_Lmin);
ddr_print("%-45s : %6d ps\n", "Minimum CAS to CAS Delay Time (tCCD_Lmin)", ddr4_tCCD_Lmin);
} else {
- ddr_print("Medium Timebase (MTB) : %6d ps\n", mtb_psec);
- ddr_print("Minimum Cycle Time (tCKmin) : %6d ps (%ld MT/s)\n", tCKmin,
+ ddr_print("Medium Timebase (MTB) : %6d ps\n", mtb_psec);
+ ddr_print("Minimum Cycle Time (tCKmin) : %6d ps (%ld MT/s)\n", tCKmin,
pretty_psecs_to_mts(tCKmin));
- ddr_print("Minimum CAS Latency Time (tAAmin) : %6d ps\n", tAAmin);
- ddr_print("Write Recovery Time (tWR) : %6d ps\n", twr);
- ddr_print("Minimum RAS to CAS delay (tRCD) : %6d ps\n", trcd);
- ddr_print("Minimum Row Active to Row Active delay (tRRD) : %6d ps\n", trrd);
- ddr_print("Minimum Row Precharge Delay (tRP) : %6d ps\n", trp);
- ddr_print("Minimum Active to Precharge (tRAS) : %6d ps\n", tras);
- ddr_print("Minimum Active to Active/Refresh Delay (tRC) : %6d ps\n", trc);
- ddr_print("Minimum Refresh Recovery Delay (tRFC) : %6d ps\n", trfc);
- ddr_print("Internal write to read command delay (tWTR) : %6d ps\n", twtr);
- ddr_print("Min Internal Rd to Precharge Cmd Delay (tRTP) : %6d ps\n", trtp);
- ddr_print("Minimum Four Activate Window Delay (tFAW) : %6d ps\n", tfaw);
+ ddr_print("Minimum CAS Latency Time (tAAmin) : %6d ps\n", tAAmin);
+ ddr_print("Write Recovery Time (tWR) : %6d ps\n", twr);
+ ddr_print("Minimum RAS to CAS delay (tRCD) : %6d ps\n", trcd);
+ ddr_print("Minimum Row Active to Row Active delay (tRRD) : %6d ps\n", trrd);
+ ddr_print("Minimum Row Precharge Delay (tRP) : %6d ps\n", trp);
+ ddr_print("Minimum Active to Precharge (tRAS) : %6d ps\n", tras);
+ ddr_print("Minimum Active to Active/Refresh Delay (tRC) : %6d ps\n", trc);
+ ddr_print("Minimum Refresh Recovery Delay (tRFC) : %6d ps\n", trfc);
+ ddr_print("Internal write to read command delay (tWTR) : %6d ps\n", twtr);
+ ddr_print("Min Internal Rd to Precharge Cmd Delay (tRTP) : %6d ps\n", trtp);
+ ddr_print("Minimum Four Activate Window Delay (tFAW) : %6d ps\n", tfaw);
}
@@ -3559,13 +3566,13 @@ int init_octeon3_ddr3_interface(bdk_node_t node,
tclk_psecs = tCKmin;
if (tclk_psecs < (uint64_t)tCKmin) {
- ddr_print("WARNING!!!!: DDR Clock Rate (tCLK: %ld) exceeds DIMM specifications (tCKmin: %ld)!!!!\n",
+ ddr_print("WARNING!!!!: DDR Clock Rate (tCLK: %lld) exceeds DIMM specifications (tCKmin: %lld)!!!!\n",
tclk_psecs, (uint64_t)tCKmin);
}
- ddr_print("DDR Clock Rate (tCLK) : %6lu ps\n", tclk_psecs);
- ddr_print("Core Clock Rate (eCLK) : %6lu ps\n", eclk_psecs);
+ ddr_print("DDR Clock Rate (tCLK) : %6llu ps\n", tclk_psecs);
+ ddr_print("Core Clock Rate (eCLK) : %6llu ps\n", eclk_psecs);
if ((s = lookup_env_parameter("ddr_use_ecc")) != NULL) {
use_ecc = !!strtoul(s, NULL, 0);
@@ -3633,7 +3640,7 @@ int init_octeon3_ddr3_interface(bdk_node_t node,
if (CL < min_cas_latency) {
uint64_t adjusted_tclk = tAAmin / min_cas_latency;
CL = min_cas_latency;
- ddr_print("Slow clock speed. Adjusting timing: tClk = %lu, Adjusted tClk = %ld\n",
+ ddr_print("Slow clock speed. Adjusting timing: tClk = %llu, Adjusted tClk = %lld\n",
tclk_psecs, adjusted_tclk);
tclk_psecs = adjusted_tclk;
}
@@ -3832,12 +3839,12 @@ int init_octeon3_ddr3_interface(bdk_node_t node,
}
VB_PRT(VBL_DEV, "%-45s : %d\n", "MODE32B (init)", lmc_config.s.mode32b);
lmc_config.s.mode_x4dev = (dram_width == 4) ? 1 : 0;
- lmc_config.s.bg2_enable = ((ddr_type == DDR4_DRAM) && (dram_width == 16)) ? 0 : 1;
+ lmc_config.s.bg2_enable = ((ddr_type == DDR4_DRAM) && (dram_width == 16)) ? 0 : 1;
if ((s = lookup_env_parameter_ull("ddr_config")) != NULL) {
lmc_config.u = strtoull(s, NULL, 0);
}
- ddr_print("LMC_CONFIG : 0x%016lx\n", lmc_config.u);
+ ddr_print("LMC_CONFIG : 0x%016llx\n", lmc_config.u);
DRAM_CSR_WRITE(node, BDK_LMCX_CONFIG(ddr_interface_num), lmc_config.u);
}
@@ -3905,7 +3912,7 @@ int init_octeon3_ddr3_interface(bdk_node_t node,
if ((s = lookup_env_parameter_ull("ddr_control")) != NULL) {
lmc_control.u = strtoull(s, NULL, 0);
}
- ddr_print("LMC_CONTROL : 0x%016lx\n", lmc_control.u);
+ ddr_print("LMC_CONTROL : 0x%016llx\n", lmc_control.u);
DRAM_CSR_WRITE(node, BDK_LMCX_CONTROL(ddr_interface_num), lmc_control.u);
}
@@ -3934,23 +3941,23 @@ int init_octeon3_ddr3_interface(bdk_node_t node,
if (ddr_type == DDR4_DRAM) {
lmc_timing_params0.s.tzqcs = divide_roundup(128*tclk_psecs, (16*tclk_psecs)); /* Always 8. */
- lmc_timing_params0.s.tcke = divide_roundup(max(3*tclk_psecs, (uint64_t) DDR3_tCKE), tclk_psecs) - 1;
- lmc_timing_params0.s.tmrd = divide_roundup((DDR4_tMRD*tclk_psecs), tclk_psecs) - 1;
- //lmc_timing_params0.s.tmod = divide_roundup(max(24*tclk_psecs, 15000ull), tclk_psecs) - 1;
- lmc_timing_params0.s.tmod = 25; /* 25 is the max allowed */
- lmc_timing_params0.s.tdllk = divide_roundup(DDR4_tDLLK, 256);
+ lmc_timing_params0.s.tcke = divide_roundup(max(3*tclk_psecs, (uint64_t) DDR3_tCKE), tclk_psecs) - 1;
+ lmc_timing_params0.s.tmrd = divide_roundup((DDR4_tMRD*tclk_psecs), tclk_psecs) - 1;
+ //lmc_timing_params0.s.tmod = divide_roundup(max(24*tclk_psecs, 15000ull), tclk_psecs) - 1;
+ lmc_timing_params0.s.tmod = 25; /* 25 is the max allowed */
+ lmc_timing_params0.s.tdllk = divide_roundup(DDR4_tDLLK, 256);
} else {
lmc_timing_params0.s.tzqcs = divide_roundup(max(64*tclk_psecs, DDR3_ZQCS), (16*tclk_psecs));
- lmc_timing_params0.s.tcke = divide_roundup(DDR3_tCKE, tclk_psecs) - 1;
- lmc_timing_params0.s.tmrd = divide_roundup((DDR3_tMRD*tclk_psecs), tclk_psecs) - 1;
- lmc_timing_params0.s.tmod = divide_roundup(max(12*tclk_psecs, 15000ull), tclk_psecs) - 1;
- lmc_timing_params0.s.tdllk = divide_roundup(DDR3_tDLLK, 256);
+ lmc_timing_params0.s.tcke = divide_roundup(DDR3_tCKE, tclk_psecs) - 1;
+ lmc_timing_params0.s.tmrd = divide_roundup((DDR3_tMRD*tclk_psecs), tclk_psecs) - 1;
+ lmc_timing_params0.s.tmod = divide_roundup(max(12*tclk_psecs, 15000ull), tclk_psecs) - 1;
+ lmc_timing_params0.s.tdllk = divide_roundup(DDR3_tDLLK, 256);
}
if ((s = lookup_env_parameter_ull("ddr_timing_params0")) != NULL) {
lmc_timing_params0.u = strtoull(s, NULL, 0);
}
- ddr_print("TIMING_PARAMS0 : 0x%016lx\n", lmc_timing_params0.u);
+ ddr_print("TIMING_PARAMS0 : 0x%016llx\n", lmc_timing_params0.u);
DRAM_CSR_WRITE(node, BDK_LMCX_TIMING_PARAMS0(ddr_interface_num), lmc_timing_params0.u);
}
@@ -3964,26 +3971,26 @@ int init_octeon3_ddr3_interface(bdk_node_t node,
lmc_timing_params1.s.tras = divide_roundup(tras, tclk_psecs) - 1;
- // NOTE: this is reworked for pass 2.x
- temp_trcd = divide_roundup(trcd, tclk_psecs);
+ // NOTE: this is reworked for pass 2.x
+ temp_trcd = divide_roundup(trcd, tclk_psecs);
#if 1
if (temp_trcd > 15)
ddr_print("TIMING_PARAMS1[trcd]: need extension bit for 0x%x\n", temp_trcd);
#endif
- if (CAVIUM_IS_MODEL(CAVIUM_CN88XX_PASS1_X) && (temp_trcd > 15)) {
- /* Let .trcd=0 serve as a flag that the field has
- overflowed. Must use Additive Latency mode as a
- workaround. */
- temp_trcd = 0;
- }
- lmc_timing_params1.s.trcd = temp_trcd & 0x0f;
- lmc_timing_params1.s.trcd_ext = (temp_trcd >> 4) & 1;
+ if (CAVIUM_IS_MODEL(CAVIUM_CN88XX_PASS1_X) && (temp_trcd > 15)) {
+ /* Let .trcd=0 serve as a flag that the field has
+ overflowed. Must use Additive Latency mode as a
+ workaround. */
+ temp_trcd = 0;
+ }
+ lmc_timing_params1.s.trcd = temp_trcd & 0x0f;
+ lmc_timing_params1.s.trcd_ext = (temp_trcd >> 4) & 1;
lmc_timing_params1.s.twtr = divide_roundup(twtr, tclk_psecs) - 1;
lmc_timing_params1.s.trfc = divide_roundup(trfc, 8*tclk_psecs);
- // workaround needed for all THUNDER chips thru T88 Pass 2.0,
- // but not 81xx and 83xx...
+ // workaround needed for all THUNDER chips thru T88 Pass 2.0,
+ // but not 81xx and 83xx...
if ((ddr_type == DDR4_DRAM) && CAVIUM_IS_MODEL(CAVIUM_CN88XX)) {
/* Workaround bug 24006. Use Trrd_l. */
lmc_timing_params1.s.trrd = divide_roundup(ddr4_tRRD_Lmin, tclk_psecs) - 2;
@@ -3999,17 +4006,17 @@ int init_octeon3_ddr3_interface(bdk_node_t node,
** tXP = max( 3nCK, 6.0 ns) DDR3-2133 tCLK = 937 psec
*/
txp = (tclk_psecs < 1875) ? 6000 : 7500;
- // NOTE: this is reworked for pass 2.x
- int temp_txp = divide_roundup(max(3*tclk_psecs, (unsigned)txp), tclk_psecs) - 1;
+ // NOTE: this is reworked for pass 2.x
+ int temp_txp = divide_roundup(max(3*tclk_psecs, (unsigned)txp), tclk_psecs) - 1;
#if 1
if (temp_txp > 7)
ddr_print("TIMING_PARAMS1[txp]: need extension bit for 0x%x\n", temp_txp);
#endif
- if (CAVIUM_IS_MODEL(CAVIUM_CN88XX_PASS1_X) && (temp_txp > 7)) {
- temp_txp = 7; // max it out
- }
- lmc_timing_params1.s.txp = temp_txp & 7;
- lmc_timing_params1.s.txp_ext = (temp_txp >> 3) & 1;
+ if (CAVIUM_IS_MODEL(CAVIUM_CN88XX_PASS1_X) && (temp_txp > 7)) {
+ temp_txp = 7; // max it out
+ }
+ lmc_timing_params1.s.txp = temp_txp & 7;
+ lmc_timing_params1.s.txp_ext = (temp_txp >> 3) & 1;
lmc_timing_params1.s.twlmrd = divide_roundup(DDR3_tWLMRD*tclk_psecs, 4*tclk_psecs);
lmc_timing_params1.s.twldqsen = divide_roundup(DDR3_tWLDQSEN*tclk_psecs, 4*tclk_psecs);
@@ -4045,7 +4052,7 @@ int init_octeon3_ddr3_interface(bdk_node_t node,
if ((s = lookup_env_parameter_ull("ddr_timing_params1")) != NULL) {
lmc_timing_params1.u = strtoull(s, NULL, 0);
}
- ddr_print("TIMING_PARAMS1 : 0x%016lx\n", lmc_timing_params1.u);
+ ddr_print("TIMING_PARAMS1 : 0x%016llx\n", lmc_timing_params1.u);
DRAM_CSR_WRITE(node, BDK_LMCX_TIMING_PARAMS1(ddr_interface_num), lmc_timing_params1.u);
}
@@ -4055,34 +4062,34 @@ int init_octeon3_ddr3_interface(bdk_node_t node,
bdk_lmcx_timing_params2_t lmc_timing_params2;
lmc_timing_params1.u = BDK_CSR_READ(node, BDK_LMCX_TIMING_PARAMS1(ddr_interface_num));
lmc_timing_params2.u = BDK_CSR_READ(node, BDK_LMCX_TIMING_PARAMS2(ddr_interface_num));
- ddr_print("TIMING_PARAMS2 : 0x%016lx\n", lmc_timing_params2.u);
+ ddr_print("TIMING_PARAMS2 : 0x%016llx\n", lmc_timing_params2.u);
//lmc_timing_params2.s.trrd_l = divide_roundup(ddr4_tRRD_Lmin, tclk_psecs) - 1;
- // NOTE: this is reworked for pass 2.x
- int temp_trrd_l = divide_roundup(ddr4_tRRD_Lmin, tclk_psecs) - 2;
+ // NOTE: this is reworked for pass 2.x
+ int temp_trrd_l = divide_roundup(ddr4_tRRD_Lmin, tclk_psecs) - 2;
#if 1
if (temp_trrd_l > 7)
ddr_print("TIMING_PARAMS2[trrd_l]: need extension bit for 0x%x\n", temp_trrd_l);
#endif
- if (CAVIUM_IS_MODEL(CAVIUM_CN88XX_PASS1_X) && (temp_trrd_l > 7)) {
- temp_trrd_l = 7; // max it out
- }
- lmc_timing_params2.s.trrd_l = temp_trrd_l & 7;
- lmc_timing_params2.s.trrd_l_ext = (temp_trrd_l >> 3) & 1;
+ if (CAVIUM_IS_MODEL(CAVIUM_CN88XX_PASS1_X) && (temp_trrd_l > 7)) {
+ temp_trrd_l = 7; // max it out
+ }
+ lmc_timing_params2.s.trrd_l = temp_trrd_l & 7;
+ lmc_timing_params2.s.trrd_l_ext = (temp_trrd_l >> 3) & 1;
lmc_timing_params2.s.twtr_l = divide_nint(max(4*tclk_psecs, 7500ull), tclk_psecs) - 1; // correct for 1600-2400
lmc_timing_params2.s.t_rw_op_max = 7;
lmc_timing_params2.s.trtp = divide_roundup(max(4*tclk_psecs, 7500ull), tclk_psecs) - 1;
- ddr_print("TIMING_PARAMS2 : 0x%016lx\n", lmc_timing_params2.u);
+ ddr_print("TIMING_PARAMS2 : 0x%016llx\n", lmc_timing_params2.u);
DRAM_CSR_WRITE(node, BDK_LMCX_TIMING_PARAMS2(ddr_interface_num), lmc_timing_params2.u);
/* Workaround Errata 25823 - LMC: Possible DDR4 tWTR_L not met
for Write-to-Read operations to the same Bank Group */
if (lmc_timing_params1.s.twtr < (lmc_timing_params2.s.twtr_l - 4)) {
lmc_timing_params1.s.twtr = lmc_timing_params2.s.twtr_l - 4;
- ddr_print("ERRATA 25823: NEW: TWTR: %d, TWTR_L: %d\n", lmc_timing_params1.s.twtr, lmc_timing_params2.s.twtr_l);
- ddr_print("TIMING_PARAMS1 : 0x%016lx\n", lmc_timing_params1.u);
+ ddr_print("ERRATA 25823: NEW: TWTR: %d, TWTR_L: %d\n", lmc_timing_params1.s.twtr, lmc_timing_params2.s.twtr_l);
+ ddr_print("TIMING_PARAMS1 : 0x%016llx\n", lmc_timing_params1.u);
DRAM_CSR_WRITE(node, BDK_LMCX_TIMING_PARAMS1(ddr_interface_num), lmc_timing_params1.u);
}
}
@@ -4095,17 +4102,17 @@ int init_octeon3_ddr3_interface(bdk_node_t node,
lmc_modereg_params0.u = BDK_CSR_READ(node, BDK_LMCX_MODEREG_PARAMS0(ddr_interface_num));
if (ddr_type == DDR4_DRAM) {
- lmc_modereg_params0.s.cwl = 0; /* 1600 (1250ps) */
- if (tclk_psecs < 1250)
- lmc_modereg_params0.s.cwl = 1; /* 1866 (1072ps) */
- if (tclk_psecs < 1072)
- lmc_modereg_params0.s.cwl = 2; /* 2133 (938ps) */
- if (tclk_psecs < 938)
- lmc_modereg_params0.s.cwl = 3; /* 2400 (833ps) */
- if (tclk_psecs < 833)
- lmc_modereg_params0.s.cwl = 4; /* 2666 (750ps) */
- if (tclk_psecs < 750)
- lmc_modereg_params0.s.cwl = 5; /* 3200 (625ps) */
+ lmc_modereg_params0.s.cwl = 0; /* 1600 (1250ps) */
+ if (tclk_psecs < 1250)
+ lmc_modereg_params0.s.cwl = 1; /* 1866 (1072ps) */
+ if (tclk_psecs < 1072)
+ lmc_modereg_params0.s.cwl = 2; /* 2133 (938ps) */
+ if (tclk_psecs < 938)
+ lmc_modereg_params0.s.cwl = 3; /* 2400 (833ps) */
+ if (tclk_psecs < 833)
+ lmc_modereg_params0.s.cwl = 4; /* 2666 (750ps) */
+ if (tclk_psecs < 750)
+ lmc_modereg_params0.s.cwl = 5; /* 3200 (625ps) */
} else {
/*
** CSR CWL CAS write Latency
@@ -4135,7 +4142,7 @@ int init_octeon3_ddr3_interface(bdk_node_t node,
lmc_modereg_params0.s.cwl = 6;
if (tclk_psecs < 833)
lmc_modereg_params0.s.cwl = 7;
- }
+ }
if ((s = lookup_env_parameter("ddr_cwl")) != NULL) {
lmc_modereg_params0.s.cwl = strtoul(s, NULL, 0) - 5;
@@ -4167,54 +4174,54 @@ int init_octeon3_ddr3_interface(bdk_node_t node,
}
if (ddr_type == DDR4_DRAM) {
- lmc_modereg_params0.s.cl = 0x0;
- if (CL > 9)
- lmc_modereg_params0.s.cl = 0x1;
- if (CL > 10)
- lmc_modereg_params0.s.cl = 0x2;
- if (CL > 11)
- lmc_modereg_params0.s.cl = 0x3;
- if (CL > 12)
- lmc_modereg_params0.s.cl = 0x4;
- if (CL > 13)
- lmc_modereg_params0.s.cl = 0x5;
- if (CL > 14)
- lmc_modereg_params0.s.cl = 0x6;
- if (CL > 15)
- lmc_modereg_params0.s.cl = 0x7;
- if (CL > 16)
- lmc_modereg_params0.s.cl = 0x8;
- if (CL > 18)
- lmc_modereg_params0.s.cl = 0x9;
- if (CL > 20)
- lmc_modereg_params0.s.cl = 0xA;
- if (CL > 24)
- lmc_modereg_params0.s.cl = 0xB;
+ lmc_modereg_params0.s.cl = 0x0;
+ if (CL > 9)
+ lmc_modereg_params0.s.cl = 0x1;
+ if (CL > 10)
+ lmc_modereg_params0.s.cl = 0x2;
+ if (CL > 11)
+ lmc_modereg_params0.s.cl = 0x3;
+ if (CL > 12)
+ lmc_modereg_params0.s.cl = 0x4;
+ if (CL > 13)
+ lmc_modereg_params0.s.cl = 0x5;
+ if (CL > 14)
+ lmc_modereg_params0.s.cl = 0x6;
+ if (CL > 15)
+ lmc_modereg_params0.s.cl = 0x7;
+ if (CL > 16)
+ lmc_modereg_params0.s.cl = 0x8;
+ if (CL > 18)
+ lmc_modereg_params0.s.cl = 0x9;
+ if (CL > 20)
+ lmc_modereg_params0.s.cl = 0xA;
+ if (CL > 24)
+ lmc_modereg_params0.s.cl = 0xB;
} else {
- lmc_modereg_params0.s.cl = 0x2;
- if (CL > 5)
- lmc_modereg_params0.s.cl = 0x4;
- if (CL > 6)
- lmc_modereg_params0.s.cl = 0x6;
- if (CL > 7)
- lmc_modereg_params0.s.cl = 0x8;
- if (CL > 8)
- lmc_modereg_params0.s.cl = 0xA;
- if (CL > 9)
- lmc_modereg_params0.s.cl = 0xC;
- if (CL > 10)
- lmc_modereg_params0.s.cl = 0xE;
- if (CL > 11)
- lmc_modereg_params0.s.cl = 0x1;
- if (CL > 12)
- lmc_modereg_params0.s.cl = 0x3;
- if (CL > 13)
- lmc_modereg_params0.s.cl = 0x5;
- if (CL > 14)
- lmc_modereg_params0.s.cl = 0x7;
- if (CL > 15)
- lmc_modereg_params0.s.cl = 0x9;
- }
+ lmc_modereg_params0.s.cl = 0x2;
+ if (CL > 5)
+ lmc_modereg_params0.s.cl = 0x4;
+ if (CL > 6)
+ lmc_modereg_params0.s.cl = 0x6;
+ if (CL > 7)
+ lmc_modereg_params0.s.cl = 0x8;
+ if (CL > 8)
+ lmc_modereg_params0.s.cl = 0xA;
+ if (CL > 9)
+ lmc_modereg_params0.s.cl = 0xC;
+ if (CL > 10)
+ lmc_modereg_params0.s.cl = 0xE;
+ if (CL > 11)
+ lmc_modereg_params0.s.cl = 0x1;
+ if (CL > 12)
+ lmc_modereg_params0.s.cl = 0x3;
+ if (CL > 13)
+ lmc_modereg_params0.s.cl = 0x5;
+ if (CL > 14)
+ lmc_modereg_params0.s.cl = 0x7;
+ if (CL > 15)
+ lmc_modereg_params0.s.cl = 0x9;
+ }
lmc_modereg_params0.s.rbt = 0; /* Read Only. */
lmc_modereg_params0.s.tm = 0;
@@ -4223,34 +4230,34 @@ int init_octeon3_ddr3_interface(bdk_node_t node,
param = divide_roundup(twr, tclk_psecs);
if (ddr_type == DDR4_DRAM) { /* DDR4 */
- lmc_modereg_params0.s.wrp = 1;
- if (param > 12)
- lmc_modereg_params0.s.wrp = 2;
- if (param > 14)
- lmc_modereg_params0.s.wrp = 3;
- if (param > 16)
- lmc_modereg_params0.s.wrp = 4;
- if (param > 18)
- lmc_modereg_params0.s.wrp = 5;
- if (param > 20)
- lmc_modereg_params0.s.wrp = 6;
- if (param > 24) /* RESERVED in DDR4 spec */
- lmc_modereg_params0.s.wrp = 7;
+ lmc_modereg_params0.s.wrp = 1;
+ if (param > 12)
+ lmc_modereg_params0.s.wrp = 2;
+ if (param > 14)
+ lmc_modereg_params0.s.wrp = 3;
+ if (param > 16)
+ lmc_modereg_params0.s.wrp = 4;
+ if (param > 18)
+ lmc_modereg_params0.s.wrp = 5;
+ if (param > 20)
+ lmc_modereg_params0.s.wrp = 6;
+ if (param > 24) /* RESERVED in DDR4 spec */
+ lmc_modereg_params0.s.wrp = 7;
} else { /* DDR3 */
- lmc_modereg_params0.s.wrp = 1;
- if (param > 5)
- lmc_modereg_params0.s.wrp = 2;
- if (param > 6)
- lmc_modereg_params0.s.wrp = 3;
- if (param > 7)
- lmc_modereg_params0.s.wrp = 4;
- if (param > 8)
- lmc_modereg_params0.s.wrp = 5;
- if (param > 10)
- lmc_modereg_params0.s.wrp = 6;
- if (param > 12)
- lmc_modereg_params0.s.wrp = 7;
- }
+ lmc_modereg_params0.s.wrp = 1;
+ if (param > 5)
+ lmc_modereg_params0.s.wrp = 2;
+ if (param > 6)
+ lmc_modereg_params0.s.wrp = 3;
+ if (param > 7)
+ lmc_modereg_params0.s.wrp = 4;
+ if (param > 8)
+ lmc_modereg_params0.s.wrp = 5;
+ if (param > 10)
+ lmc_modereg_params0.s.wrp = 6;
+ if (param > 12)
+ lmc_modereg_params0.s.wrp = 7;
+ }
lmc_modereg_params0.s.ppd = 0;
@@ -4264,7 +4271,7 @@ int init_octeon3_ddr3_interface(bdk_node_t node,
if ((s = lookup_env_parameter_ull("ddr_modereg_params0")) != NULL) {
lmc_modereg_params0.u = strtoull(s, NULL, 0);
}
- ddr_print("MODEREG_PARAMS0 : 0x%016lx\n", lmc_modereg_params0.u);
+ ddr_print("MODEREG_PARAMS0 : 0x%016llx\n", lmc_modereg_params0.u);
DRAM_CSR_WRITE(node, BDK_LMCX_MODEREG_PARAMS0(ddr_interface_num), lmc_modereg_params0.u);
}
@@ -4408,61 +4415,61 @@ int init_octeon3_ddr3_interface(bdk_node_t node,
lmc_modereg_params1.s.dic_01,
lmc_modereg_params1.s.dic_00);
- ddr_print("MODEREG_PARAMS1 : 0x%016lx\n", lmc_modereg_params1.u);
+ ddr_print("MODEREG_PARAMS1 : 0x%016llx\n", lmc_modereg_params1.u);
DRAM_CSR_WRITE(node, BDK_LMCX_MODEREG_PARAMS1(ddr_interface_num), lmc_modereg_params1.u);
} /* LMC(0)_MODEREG_PARAMS1 */
/* LMC(0)_MODEREG_PARAMS2 */
if (ddr_type == DDR4_DRAM) {
- bdk_lmcx_modereg_params2_t lmc_modereg_params2;
- lmc_modereg_params2.u = odt_config[odt_idx].odt_mask2.u;
-
- for (i=0; i<4; ++i) {
- uint64_t value;
- if ((s = lookup_env_parameter("ddr_rtt_park_%1d%1d", !!(i&2), !!(i&1))) != NULL) {
- value = strtoul(s, NULL, 0);
- lmc_modereg_params2.u &= ~((uint64_t)0x7 << (i*10+0));
- lmc_modereg_params2.u |= ( (value & 0x7) << (i*10+0));
- }
- }
-
- if ((s = lookup_env_parameter("ddr_rtt_park")) != NULL) {
- uint64_t value = strtoul(s, NULL, 0);
- for (i=0; i<4; ++i) {
- lmc_modereg_params2.u &= ~((uint64_t)0x7 << (i*10+0));
- lmc_modereg_params2.u |= ( (value & 0x7) << (i*10+0));
- }
- }
-
- if ((s = lookup_env_parameter_ull("ddr_modereg_params2")) != NULL) {
- lmc_modereg_params2.u = strtoull(s, NULL, 0);
- }
-
- ddr_print("RTT_PARK %3d, %3d, %3d, %3d ohms : %x,%x,%x,%x\n",
- imp_values->rtt_nom_ohms[lmc_modereg_params2.s.rtt_park_11],
- imp_values->rtt_nom_ohms[lmc_modereg_params2.s.rtt_park_10],
- imp_values->rtt_nom_ohms[lmc_modereg_params2.s.rtt_park_01],
- imp_values->rtt_nom_ohms[lmc_modereg_params2.s.rtt_park_00],
- lmc_modereg_params2.s.rtt_park_11,
- lmc_modereg_params2.s.rtt_park_10,
- lmc_modereg_params2.s.rtt_park_01,
- lmc_modereg_params2.s.rtt_park_00);
-
- ddr_print("%-45s : 0x%x,0x%x,0x%x,0x%x\n", "VREF_RANGE",
- lmc_modereg_params2.s.vref_range_11,
- lmc_modereg_params2.s.vref_range_10,
- lmc_modereg_params2.s.vref_range_01,
- lmc_modereg_params2.s.vref_range_00);
-
- ddr_print("%-45s : 0x%x,0x%x,0x%x,0x%x\n", "VREF_VALUE",
- lmc_modereg_params2.s.vref_value_11,
- lmc_modereg_params2.s.vref_value_10,
- lmc_modereg_params2.s.vref_value_01,
- lmc_modereg_params2.s.vref_value_00);
-
- ddr_print("MODEREG_PARAMS2 : 0x%016lx\n", lmc_modereg_params2.u);
- DRAM_CSR_WRITE(node, BDK_LMCX_MODEREG_PARAMS2(ddr_interface_num), lmc_modereg_params2.u);
+ bdk_lmcx_modereg_params2_t lmc_modereg_params2;
+ lmc_modereg_params2.u = odt_config[odt_idx].odt_mask2.u;
+
+ for (i=0; i<4; ++i) {
+ uint64_t value;
+ if ((s = lookup_env_parameter("ddr_rtt_park_%1d%1d", !!(i&2), !!(i&1))) != NULL) {
+ value = strtoul(s, NULL, 0);
+ lmc_modereg_params2.u &= ~((uint64_t)0x7 << (i*10+0));
+ lmc_modereg_params2.u |= ( (value & 0x7) << (i*10+0));
+ }
+ }
+
+ if ((s = lookup_env_parameter("ddr_rtt_park")) != NULL) {
+ uint64_t value = strtoul(s, NULL, 0);
+ for (i=0; i<4; ++i) {
+ lmc_modereg_params2.u &= ~((uint64_t)0x7 << (i*10+0));
+ lmc_modereg_params2.u |= ( (value & 0x7) << (i*10+0));
+ }
+ }
+
+ if ((s = lookup_env_parameter_ull("ddr_modereg_params2")) != NULL) {
+ lmc_modereg_params2.u = strtoull(s, NULL, 0);
+ }
+
+ ddr_print("RTT_PARK %3d, %3d, %3d, %3d ohms : %x,%x,%x,%x\n",
+ imp_values->rtt_nom_ohms[lmc_modereg_params2.s.rtt_park_11],
+ imp_values->rtt_nom_ohms[lmc_modereg_params2.s.rtt_park_10],
+ imp_values->rtt_nom_ohms[lmc_modereg_params2.s.rtt_park_01],
+ imp_values->rtt_nom_ohms[lmc_modereg_params2.s.rtt_park_00],
+ lmc_modereg_params2.s.rtt_park_11,
+ lmc_modereg_params2.s.rtt_park_10,
+ lmc_modereg_params2.s.rtt_park_01,
+ lmc_modereg_params2.s.rtt_park_00);
+
+ ddr_print("%-45s : 0x%x,0x%x,0x%x,0x%x\n", "VREF_RANGE",
+ lmc_modereg_params2.s.vref_range_11,
+ lmc_modereg_params2.s.vref_range_10,
+ lmc_modereg_params2.s.vref_range_01,
+ lmc_modereg_params2.s.vref_range_00);
+
+ ddr_print("%-45s : 0x%x,0x%x,0x%x,0x%x\n", "VREF_VALUE",
+ lmc_modereg_params2.s.vref_value_11,
+ lmc_modereg_params2.s.vref_value_10,
+ lmc_modereg_params2.s.vref_value_01,
+ lmc_modereg_params2.s.vref_value_00);
+
+ ddr_print("MODEREG_PARAMS2 : 0x%016llx\n", lmc_modereg_params2.u);
+ DRAM_CSR_WRITE(node, BDK_LMCX_MODEREG_PARAMS2(ddr_interface_num), lmc_modereg_params2.u);
} /* LMC(0)_MODEREG_PARAMS2 */
@@ -4503,7 +4510,7 @@ int init_octeon3_ddr3_interface(bdk_node_t node,
lmc_modereg_params3.s.xrank_add_tccd_s = delay;
}
- ddr_print("MODEREG_PARAMS3 : 0x%016lx\n", lmc_modereg_params3.u);
+ ddr_print("MODEREG_PARAMS3 : 0x%016llx\n", lmc_modereg_params3.u);
DRAM_CSR_WRITE(node, BDK_LMCX_MODEREG_PARAMS3(ddr_interface_num), lmc_modereg_params3.u);
} /* LMC(0)_MODEREG_PARAMS3 */
@@ -4527,7 +4534,7 @@ int init_octeon3_ddr3_interface(bdk_node_t node,
if ((s = lookup_env_parameter_ull("ddr_nxm")) != NULL) {
lmc_nxm.u = strtoull(s, NULL, 0);
}
- ddr_print("LMC_NXM : 0x%016lx\n", lmc_nxm.u);
+ ddr_print("LMC_NXM : 0x%016llx\n", lmc_nxm.u);
DRAM_CSR_WRITE(node, BDK_LMCX_NXM(ddr_interface_num), lmc_nxm.u);
}
@@ -4540,7 +4547,7 @@ int init_octeon3_ddr3_interface(bdk_node_t node,
lmc_wodt_mask.u = strtoull(s, NULL, 0);
}
- ddr_print("WODT_MASK : 0x%016lx\n", lmc_wodt_mask.u);
+ ddr_print("WODT_MASK : 0x%016llx\n", lmc_wodt_mask.u);
DRAM_CSR_WRITE(node, BDK_LMCX_WODT_MASK(ddr_interface_num), lmc_wodt_mask.u);
}
@@ -4554,8 +4561,8 @@ int init_octeon3_ddr3_interface(bdk_node_t node,
lmc_rodt_mask.u = strtoull(s, NULL, 0);
}
- ddr_print("%-45s : 0x%016lx\n", "RODT_MASK", lmc_rodt_mask.u);
- DRAM_CSR_WRITE(node, BDK_LMCX_RODT_MASK(ddr_interface_num), lmc_rodt_mask.u);
+ ddr_print("%-45s : 0x%016llx\n", "RODT_MASK", lmc_rodt_mask.u);
+ DRAM_CSR_WRITE(node, BDK_LMCX_RODT_MASK(ddr_interface_num), lmc_rodt_mask.u);
dyn_rtt_nom_mask = 0;
for (rankx = 0; rankx < dimm_count * 4;rankx++) {
@@ -4583,12 +4590,12 @@ int init_octeon3_ddr3_interface(bdk_node_t node,
comp_ctl2.u = BDK_CSR_READ(node, BDK_LMCX_COMP_CTL2(ddr_interface_num));
- comp_ctl2.s.dqx_ctl = odt_config[odt_idx].odt_ena;
- comp_ctl2.s.ck_ctl = (custom_lmc_config->ck_ctl == 0) ? 4 : custom_lmc_config->ck_ctl; /* Default 4=34.3 ohm */
- comp_ctl2.s.cmd_ctl = (custom_lmc_config->cmd_ctl == 0) ? 4 : custom_lmc_config->cmd_ctl; /* Default 4=34.3 ohm */
- comp_ctl2.s.control_ctl = (custom_lmc_config->ctl_ctl == 0) ? 4 : custom_lmc_config->ctl_ctl; /* Default 4=34.3 ohm */
+ comp_ctl2.s.dqx_ctl = odt_config[odt_idx].odt_ena;
+ comp_ctl2.s.ck_ctl = (custom_lmc_config->ck_ctl == 0) ? 4 : custom_lmc_config->ck_ctl; /* Default 4=34.3 ohm */
+ comp_ctl2.s.cmd_ctl = (custom_lmc_config->cmd_ctl == 0) ? 4 : custom_lmc_config->cmd_ctl; /* Default 4=34.3 ohm */
+ comp_ctl2.s.control_ctl = (custom_lmc_config->ctl_ctl == 0) ? 4 : custom_lmc_config->ctl_ctl; /* Default 4=34.3 ohm */
- // NOTE: these are now done earlier, in Step 6.9.3
+ // NOTE: these are now done earlier, in Step 6.9.3
// comp_ctl2.s.ntune_offset = 0;
// comp_ctl2.s.ptune_offset = 0;
@@ -4607,12 +4614,12 @@ int init_octeon3_ddr3_interface(bdk_node_t node,
comp_ctl2.s.rodt_ctl = default_rodt_ctl;
- // if DDR4, force CK_CTL to 26 ohms if it is currently 34 ohms, and DCLK speed is 1 GHz or more...
- if ((ddr_type == DDR4_DRAM) && (comp_ctl2.s.ck_ctl == ddr4_driver_34_ohm) && (ddr_hertz >= 1000000000)) {
- comp_ctl2.s.ck_ctl = ddr4_driver_26_ohm; // lowest for DDR4 is 26 ohms
- ddr_print("Forcing DDR4 COMP_CTL2[CK_CTL] to %d, %d ohms\n", comp_ctl2.s.ck_ctl,
- imp_values->drive_strength[comp_ctl2.s.ck_ctl]);
- }
+ // if DDR4, force CK_CTL to 26 ohms if it is currently 34 ohms, and DCLK speed is 1 GHz or more...
+ if ((ddr_type == DDR4_DRAM) && (comp_ctl2.s.ck_ctl == ddr4_driver_34_ohm) && (ddr_hertz >= 1000000000)) {
+ comp_ctl2.s.ck_ctl = ddr4_driver_26_ohm; // lowest for DDR4 is 26 ohms
+ ddr_print("Forcing DDR4 COMP_CTL2[CK_CTL] to %d, %d ohms\n", comp_ctl2.s.ck_ctl,
+ imp_values->drive_strength[comp_ctl2.s.ck_ctl]);
+ }
if ((s = lookup_env_parameter("ddr_ck_ctl")) != NULL) {
comp_ctl2.s.ck_ctl = strtoul(s, NULL, 0);
@@ -4623,7 +4630,7 @@ int init_octeon3_ddr3_interface(bdk_node_t node,
}
if ((s = lookup_env_parameter("ddr_control_ctl")) != NULL) {
- comp_ctl2.s.control_ctl = strtoul(s, NULL, 0);
+ comp_ctl2.s.control_ctl = strtoul(s, NULL, 0);
}
if ((s = lookup_env_parameter("ddr_dqx_ctl")) != NULL) {
@@ -4631,13 +4638,13 @@ int init_octeon3_ddr3_interface(bdk_node_t node,
}
ddr_print("%-45s : %d, %d ohms\n", "DQX_CTL ", comp_ctl2.s.dqx_ctl,
- imp_values->dqx_strength [comp_ctl2.s.dqx_ctl ]);
+ imp_values->dqx_strength [comp_ctl2.s.dqx_ctl ]);
ddr_print("%-45s : %d, %d ohms\n", "CK_CTL ", comp_ctl2.s.ck_ctl,
- imp_values->drive_strength[comp_ctl2.s.ck_ctl ]);
+ imp_values->drive_strength[comp_ctl2.s.ck_ctl ]);
ddr_print("%-45s : %d, %d ohms\n", "CMD_CTL ", comp_ctl2.s.cmd_ctl,
- imp_values->drive_strength[comp_ctl2.s.cmd_ctl ]);
+ imp_values->drive_strength[comp_ctl2.s.cmd_ctl ]);
ddr_print("%-45s : %d, %d ohms\n", "CONTROL_CTL ", comp_ctl2.s.control_ctl,
- imp_values->drive_strength[comp_ctl2.s.control_ctl]);
+ imp_values->drive_strength[comp_ctl2.s.control_ctl]);
ddr_print("Read ODT_CTL : 0x%x (%d ohms)\n",
comp_ctl2.s.rodt_ctl, imp_values->rodt_ohms[comp_ctl2.s.rodt_ctl]);
@@ -4656,7 +4663,7 @@ int init_octeon3_ddr3_interface(bdk_node_t node,
node, ddr_interface_num, lmc_phy_ctl.cn81xx.c1_sel);
}
- ddr_print("PHY_CTL : 0x%016lx\n", lmc_phy_ctl.u);
+ ddr_print("PHY_CTL : 0x%016llx\n", lmc_phy_ctl.u);
DRAM_CSR_WRITE(node, BDK_LMCX_PHY_CTL(ddr_interface_num), lmc_phy_ctl.u);
}
@@ -4665,11 +4672,11 @@ int init_octeon3_ddr3_interface(bdk_node_t node,
bdk_lmcx_dimm_ctl_t lmc_dimm_ctl;
for (didx = 0; didx < (unsigned)dimm_count; ++didx) {
- bdk_lmcx_dimmx_params_t lmc_dimmx_params;
- int dimm = didx;
- int rc;
+ bdk_lmcx_dimmx_params_t lmc_dimmx_params;
+ int dimm = didx;
+ int rc;
- lmc_dimmx_params.u = BDK_CSR_READ(node, BDK_LMCX_DIMMX_PARAMS(ddr_interface_num, dimm));
+ lmc_dimmx_params.u = BDK_CSR_READ(node, BDK_LMCX_DIMMX_PARAMS(ddr_interface_num, dimm));
if (ddr_type == DDR4_DRAM) {
@@ -4720,8 +4727,8 @@ int init_octeon3_ddr3_interface(bdk_node_t node,
lmc_dimmx_params.s.rc11 = 0;
lmc_dimmx_params.s.rc12 = 0;
- lmc_dimmx_params.s.rc13 = (spd_dimm_type == 4) ? 0 : 4; /* 0=LRDIMM, 1=RDIMM */
- lmc_dimmx_params.s.rc13 |= (ddr_type == DDR4_DRAM) ? (spd_addr_mirror << 3) : 0;
+ lmc_dimmx_params.s.rc13 = (spd_dimm_type == 4) ? 0 : 4; /* 0=LRDIMM, 1=RDIMM */
+ lmc_dimmx_params.s.rc13 |= (ddr_type == DDR4_DRAM) ? (spd_addr_mirror << 3) : 0;
lmc_dimmx_params.s.rc14 = 0;
//lmc_dimmx_params.s.rc15 = 4; /* 0 nCK latency adder */
lmc_dimmx_params.s.rc15 = 0; /* 1 nCK latency adder */
@@ -4749,38 +4756,38 @@ int init_octeon3_ddr3_interface(bdk_node_t node,
lmc_ddr4_dimm_ctl.s.ddr4_dimm0_wmask = 0x004;
lmc_ddr4_dimm_ctl.s.ddr4_dimm1_wmask = (dimm_count > 1) ? 0x004 : 0x0000;
- /*
- * Handle any overrides from envvars here...
- */
- if ((s = lookup_env_parameter("ddr_ddr4_params0")) != NULL) {
- lmc_dimmx_ddr4_params0.u = strtoul(s, NULL, 0);
- }
-
- if ((s = lookup_env_parameter("ddr_ddr4_params1")) != NULL) {
- lmc_dimmx_ddr4_params1.u = strtoul(s, NULL, 0);
- }
-
- if ((s = lookup_env_parameter("ddr_ddr4_dimm_ctl")) != NULL) {
- lmc_ddr4_dimm_ctl.u = strtoul(s, NULL, 0);
- }
-
- for (i=0; i<11; ++i) {
- uint64_t value;
- if ((s = lookup_env_parameter("ddr_ddr4_rc%1xx", i+1)) != NULL) {
- value = strtoul(s, NULL, 0);
- if (i < 8) {
- lmc_dimmx_ddr4_params0.u &= ~((uint64_t)0xff << (i*8));
- lmc_dimmx_ddr4_params0.u |= (value << (i*8));
- } else {
- lmc_dimmx_ddr4_params1.u &= ~((uint64_t)0xff << ((i-8)*8));
- lmc_dimmx_ddr4_params1.u |= (value << ((i-8)*8));
- }
- }
- }
-
- /*
- * write the final CSR values
- */
+ /*
+ * Handle any overrides from envvars here...
+ */
+ if ((s = lookup_env_parameter("ddr_ddr4_params0")) != NULL) {
+ lmc_dimmx_ddr4_params0.u = strtoul(s, NULL, 0);
+ }
+
+ if ((s = lookup_env_parameter("ddr_ddr4_params1")) != NULL) {
+ lmc_dimmx_ddr4_params1.u = strtoul(s, NULL, 0);
+ }
+
+ if ((s = lookup_env_parameter("ddr_ddr4_dimm_ctl")) != NULL) {
+ lmc_ddr4_dimm_ctl.u = strtoul(s, NULL, 0);
+ }
+
+ for (i=0; i<11; ++i) {
+ uint64_t value;
+ if ((s = lookup_env_parameter("ddr_ddr4_rc%1xx", i+1)) != NULL) {
+ value = strtoul(s, NULL, 0);
+ if (i < 8) {
+ lmc_dimmx_ddr4_params0.u &= ~((uint64_t)0xff << (i*8));
+ lmc_dimmx_ddr4_params0.u |= (value << (i*8));
+ } else {
+ lmc_dimmx_ddr4_params1.u &= ~((uint64_t)0xff << ((i-8)*8));
+ lmc_dimmx_ddr4_params1.u |= (value << ((i-8)*8));
+ }
+ }
+ }
+
+ /*
+ * write the final CSR values
+ */
DRAM_CSR_WRITE(node, BDK_LMCX_DIMMX_DDR4_PARAMS0(ddr_interface_num, dimm), lmc_dimmx_ddr4_params0.u);
DRAM_CSR_WRITE(node, BDK_LMCX_DDR4_DIMM_CTL(ddr_interface_num), lmc_ddr4_dimm_ctl.u);
@@ -4802,71 +4809,71 @@ int init_octeon3_ddr3_interface(bdk_node_t node,
lmc_dimmx_ddr4_params0.s.rc1x );
} else { /* if (ddr_type == DDR4_DRAM) */
- rc = read_spd(node, &dimm_config_table[didx], 69);
- lmc_dimmx_params.s.rc0 = (rc >> 0) & 0xf;
- lmc_dimmx_params.s.rc1 = (rc >> 4) & 0xf;
-
- rc = read_spd(node, &dimm_config_table[didx], 70);
- lmc_dimmx_params.s.rc2 = (rc >> 0) & 0xf;
- lmc_dimmx_params.s.rc3 = (rc >> 4) & 0xf;
-
- rc = read_spd(node, &dimm_config_table[didx], 71);
- lmc_dimmx_params.s.rc4 = (rc >> 0) & 0xf;
- lmc_dimmx_params.s.rc5 = (rc >> 4) & 0xf;
-
- rc = read_spd(node, &dimm_config_table[didx], 72);
- lmc_dimmx_params.s.rc6 = (rc >> 0) & 0xf;
- lmc_dimmx_params.s.rc7 = (rc >> 4) & 0xf;
-
- rc = read_spd(node, &dimm_config_table[didx], 73);
- lmc_dimmx_params.s.rc8 = (rc >> 0) & 0xf;
- lmc_dimmx_params.s.rc9 = (rc >> 4) & 0xf;
-
- rc = read_spd(node, &dimm_config_table[didx], 74);
- lmc_dimmx_params.s.rc10 = (rc >> 0) & 0xf;
- lmc_dimmx_params.s.rc11 = (rc >> 4) & 0xf;
-
- rc = read_spd(node, &dimm_config_table[didx], 75);
- lmc_dimmx_params.s.rc12 = (rc >> 0) & 0xf;
- lmc_dimmx_params.s.rc13 = (rc >> 4) & 0xf;
-
- rc = read_spd(node, &dimm_config_table[didx], 76);
- lmc_dimmx_params.s.rc14 = (rc >> 0) & 0xf;
- lmc_dimmx_params.s.rc15 = (rc >> 4) & 0xf;
-
-
- if ((s = lookup_env_parameter("ddr_clk_drive")) != NULL) {
- if (strcmp(s,"light") == 0) {
- lmc_dimmx_params.s.rc5 = 0x0; /* Light Drive */
- }
- if (strcmp(s,"moderate") == 0) {
- lmc_dimmx_params.s.rc5 = 0x5; /* Moderate Drive */
- }
- if (strcmp(s,"strong") == 0) {
- lmc_dimmx_params.s.rc5 = 0xA; /* Strong Drive */
- }
- }
-
- if ((s = lookup_env_parameter("ddr_cmd_drive")) != NULL) {
- if (strcmp(s,"light") == 0) {
- lmc_dimmx_params.s.rc3 = 0x0; /* Light Drive */
- }
- if (strcmp(s,"moderate") == 0) {
- lmc_dimmx_params.s.rc3 = 0x5; /* Moderate Drive */
- }
- if (strcmp(s,"strong") == 0) {
- lmc_dimmx_params.s.rc3 = 0xA; /* Strong Drive */
- }
- }
-
- if ((s = lookup_env_parameter("ddr_ctl_drive")) != NULL) {
- if (strcmp(s,"light") == 0) {
- lmc_dimmx_params.s.rc4 = 0x0; /* Light Drive */
- }
- if (strcmp(s,"moderate") == 0) {
- lmc_dimmx_params.s.rc4 = 0x5; /* Moderate Drive */
- }
- }
+ rc = read_spd(node, &dimm_config_table[didx], 69);
+ lmc_dimmx_params.s.rc0 = (rc >> 0) & 0xf;
+ lmc_dimmx_params.s.rc1 = (rc >> 4) & 0xf;
+
+ rc = read_spd(node, &dimm_config_table[didx], 70);
+ lmc_dimmx_params.s.rc2 = (rc >> 0) & 0xf;
+ lmc_dimmx_params.s.rc3 = (rc >> 4) & 0xf;
+
+ rc = read_spd(node, &dimm_config_table[didx], 71);
+ lmc_dimmx_params.s.rc4 = (rc >> 0) & 0xf;
+ lmc_dimmx_params.s.rc5 = (rc >> 4) & 0xf;
+
+ rc = read_spd(node, &dimm_config_table[didx], 72);
+ lmc_dimmx_params.s.rc6 = (rc >> 0) & 0xf;
+ lmc_dimmx_params.s.rc7 = (rc >> 4) & 0xf;
+
+ rc = read_spd(node, &dimm_config_table[didx], 73);
+ lmc_dimmx_params.s.rc8 = (rc >> 0) & 0xf;
+ lmc_dimmx_params.s.rc9 = (rc >> 4) & 0xf;
+
+ rc = read_spd(node, &dimm_config_table[didx], 74);
+ lmc_dimmx_params.s.rc10 = (rc >> 0) & 0xf;
+ lmc_dimmx_params.s.rc11 = (rc >> 4) & 0xf;
+
+ rc = read_spd(node, &dimm_config_table[didx], 75);
+ lmc_dimmx_params.s.rc12 = (rc >> 0) & 0xf;
+ lmc_dimmx_params.s.rc13 = (rc >> 4) & 0xf;
+
+ rc = read_spd(node, &dimm_config_table[didx], 76);
+ lmc_dimmx_params.s.rc14 = (rc >> 0) & 0xf;
+ lmc_dimmx_params.s.rc15 = (rc >> 4) & 0xf;
+
+
+ if ((s = lookup_env_parameter("ddr_clk_drive")) != NULL) {
+ if (strcmp(s,"light") == 0) {
+ lmc_dimmx_params.s.rc5 = 0x0; /* Light Drive */
+ }
+ if (strcmp(s,"moderate") == 0) {
+ lmc_dimmx_params.s.rc5 = 0x5; /* Moderate Drive */
+ }
+ if (strcmp(s,"strong") == 0) {
+ lmc_dimmx_params.s.rc5 = 0xA; /* Strong Drive */
+ }
+ }
+
+ if ((s = lookup_env_parameter("ddr_cmd_drive")) != NULL) {
+ if (strcmp(s,"light") == 0) {
+ lmc_dimmx_params.s.rc3 = 0x0; /* Light Drive */
+ }
+ if (strcmp(s,"moderate") == 0) {
+ lmc_dimmx_params.s.rc3 = 0x5; /* Moderate Drive */
+ }
+ if (strcmp(s,"strong") == 0) {
+ lmc_dimmx_params.s.rc3 = 0xA; /* Strong Drive */
+ }
+ }
+
+ if ((s = lookup_env_parameter("ddr_ctl_drive")) != NULL) {
+ if (strcmp(s,"light") == 0) {
+ lmc_dimmx_params.s.rc4 = 0x0; /* Light Drive */
+ }
+ if (strcmp(s,"moderate") == 0) {
+ lmc_dimmx_params.s.rc4 = 0x5; /* Moderate Drive */
+ }
+ }
/*
@@ -4888,116 +4895,116 @@ int init_octeon3_ddr3_interface(bdk_node_t node,
if (1250 > tclk_psecs)
lmc_dimmx_params.s.rc10 = 4;
- } /* if (ddr_type == DDR4_DRAM) */
+ } /* if (ddr_type == DDR4_DRAM) */
if ((s = lookup_env_parameter("ddr_dimmx_params")) != NULL) {
lmc_dimmx_params.u = strtoul(s, NULL, 0);
}
- for (i=0; i<16; ++i) {
- uint64_t value;
- if ((s = lookup_env_parameter("ddr_rc%d", i)) != NULL) {
- value = strtoul(s, NULL, 0);
- lmc_dimmx_params.u &= ~((uint64_t)0xf << (i*4));
- lmc_dimmx_params.u |= ( value << (i*4));
- }
- }
-
- DRAM_CSR_WRITE(node, BDK_LMCX_DIMMX_PARAMS(ddr_interface_num, dimm), lmc_dimmx_params.u);
-
- ddr_print("DIMM%d Register Control Words RC15:RC0 : %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x\n",
- dimm,
- lmc_dimmx_params.s.rc15,
- lmc_dimmx_params.s.rc14,
- lmc_dimmx_params.s.rc13,
- lmc_dimmx_params.s.rc12,
- lmc_dimmx_params.s.rc11,
- lmc_dimmx_params.s.rc10,
- lmc_dimmx_params.s.rc9 ,
- lmc_dimmx_params.s.rc8 ,
- lmc_dimmx_params.s.rc7 ,
- lmc_dimmx_params.s.rc6 ,
- lmc_dimmx_params.s.rc5 ,
- lmc_dimmx_params.s.rc4 ,
- lmc_dimmx_params.s.rc3 ,
- lmc_dimmx_params.s.rc2 ,
- lmc_dimmx_params.s.rc1 ,
- lmc_dimmx_params.s.rc0 );
- } /* for didx */
-
- if (ddr_type == DDR4_DRAM) {
-
- /* LMC0_DIMM_CTL */
- lmc_dimm_ctl.u = BDK_CSR_READ(node, BDK_LMCX_DIMM_CTL(ddr_interface_num));
- lmc_dimm_ctl.s.dimm0_wmask = 0xdf3f;
- lmc_dimm_ctl.s.dimm1_wmask = (dimm_count > 1) ? 0xdf3f : 0x0000;
- lmc_dimm_ctl.s.tcws = 0x4e0;
- lmc_dimm_ctl.cn88xx.parity = custom_lmc_config->parity;
-
- if ((s = lookup_env_parameter("ddr_dimm0_wmask")) != NULL) {
- lmc_dimm_ctl.s.dimm0_wmask = strtoul(s, NULL, 0);
- }
-
- if ((s = lookup_env_parameter("ddr_dimm1_wmask")) != NULL) {
- lmc_dimm_ctl.s.dimm1_wmask = strtoul(s, NULL, 0);
- }
-
- if ((s = lookup_env_parameter("ddr_dimm_ctl_parity")) != NULL) {
- lmc_dimm_ctl.cn88xx.parity = strtoul(s, NULL, 0);
- }
-
- if ((s = lookup_env_parameter("ddr_dimm_ctl_tcws")) != NULL) {
- lmc_dimm_ctl.s.tcws = strtoul(s, NULL, 0);
- }
-
- ddr_print("LMC DIMM_CTL : 0x%016lx\n", lmc_dimm_ctl.u);
- DRAM_CSR_WRITE(node, BDK_LMCX_DIMM_CTL(ddr_interface_num), lmc_dimm_ctl.u);
-
- perform_octeon3_ddr3_sequence(node, rank_mask,
- ddr_interface_num, 0x7 ); /* Init RCW */
-
- /* Write RC0D last */
- lmc_dimm_ctl.s.dimm0_wmask = 0x2000;
- lmc_dimm_ctl.s.dimm1_wmask = (dimm_count > 1) ? 0x2000 : 0x0000;
- ddr_print("LMC DIMM_CTL : 0x%016lx\n", lmc_dimm_ctl.u);
- DRAM_CSR_WRITE(node, BDK_LMCX_DIMM_CTL(ddr_interface_num), lmc_dimm_ctl.u);
-
- /* Don't write any extended registers the second time */
- DRAM_CSR_WRITE(node, BDK_LMCX_DDR4_DIMM_CTL(ddr_interface_num), 0);
-
- perform_octeon3_ddr3_sequence(node, rank_mask,
- ddr_interface_num, 0x7 ); /* Init RCW */
+ for (i=0; i<16; ++i) {
+ uint64_t value;
+ if ((s = lookup_env_parameter("ddr_rc%d", i)) != NULL) {
+ value = strtoul(s, NULL, 0);
+ lmc_dimmx_params.u &= ~((uint64_t)0xf << (i*4));
+ lmc_dimmx_params.u |= ( value << (i*4));
+ }
+ }
+
+ DRAM_CSR_WRITE(node, BDK_LMCX_DIMMX_PARAMS(ddr_interface_num, dimm), lmc_dimmx_params.u);
+
+ ddr_print("DIMM%d Register Control Words RC15:RC0 : %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x\n",
+ dimm,
+ lmc_dimmx_params.s.rc15,
+ lmc_dimmx_params.s.rc14,
+ lmc_dimmx_params.s.rc13,
+ lmc_dimmx_params.s.rc12,
+ lmc_dimmx_params.s.rc11,
+ lmc_dimmx_params.s.rc10,
+ lmc_dimmx_params.s.rc9 ,
+ lmc_dimmx_params.s.rc8 ,
+ lmc_dimmx_params.s.rc7 ,
+ lmc_dimmx_params.s.rc6 ,
+ lmc_dimmx_params.s.rc5 ,
+ lmc_dimmx_params.s.rc4 ,
+ lmc_dimmx_params.s.rc3 ,
+ lmc_dimmx_params.s.rc2 ,
+ lmc_dimmx_params.s.rc1 ,
+ lmc_dimmx_params.s.rc0 );
+ } /* for didx */
+
+ if (ddr_type == DDR4_DRAM) {
+
+ /* LMC0_DIMM_CTL */
+ lmc_dimm_ctl.u = BDK_CSR_READ(node, BDK_LMCX_DIMM_CTL(ddr_interface_num));
+ lmc_dimm_ctl.s.dimm0_wmask = 0xdf3f;
+ lmc_dimm_ctl.s.dimm1_wmask = (dimm_count > 1) ? 0xdf3f : 0x0000;
+ lmc_dimm_ctl.s.tcws = 0x4e0;
+ lmc_dimm_ctl.cn88xx.parity = custom_lmc_config->parity;
+
+ if ((s = lookup_env_parameter("ddr_dimm0_wmask")) != NULL) {
+ lmc_dimm_ctl.s.dimm0_wmask = strtoul(s, NULL, 0);
+ }
+
+ if ((s = lookup_env_parameter("ddr_dimm1_wmask")) != NULL) {
+ lmc_dimm_ctl.s.dimm1_wmask = strtoul(s, NULL, 0);
+ }
+
+ if ((s = lookup_env_parameter("ddr_dimm_ctl_parity")) != NULL) {
+ lmc_dimm_ctl.cn88xx.parity = strtoul(s, NULL, 0);
+ }
+
+ if ((s = lookup_env_parameter("ddr_dimm_ctl_tcws")) != NULL) {
+ lmc_dimm_ctl.s.tcws = strtoul(s, NULL, 0);
+ }
+
+ ddr_print("LMC DIMM_CTL : 0x%016llx\n", lmc_dimm_ctl.u);
+ DRAM_CSR_WRITE(node, BDK_LMCX_DIMM_CTL(ddr_interface_num), lmc_dimm_ctl.u);
+
+ perform_octeon3_ddr3_sequence(node, rank_mask,
+ ddr_interface_num, 0x7 ); /* Init RCW */
+
+ /* Write RC0D last */
+ lmc_dimm_ctl.s.dimm0_wmask = 0x2000;
+ lmc_dimm_ctl.s.dimm1_wmask = (dimm_count > 1) ? 0x2000 : 0x0000;
+ ddr_print("LMC DIMM_CTL : 0x%016llx\n", lmc_dimm_ctl.u);
+ DRAM_CSR_WRITE(node, BDK_LMCX_DIMM_CTL(ddr_interface_num), lmc_dimm_ctl.u);
+
+ /* Don't write any extended registers the second time */
+ DRAM_CSR_WRITE(node, BDK_LMCX_DDR4_DIMM_CTL(ddr_interface_num), 0);
+
+ perform_octeon3_ddr3_sequence(node, rank_mask,
+ ddr_interface_num, 0x7 ); /* Init RCW */
} else {
- /* LMC0_DIMM_CTL */
- lmc_dimm_ctl.u = BDK_CSR_READ(node, BDK_LMCX_DIMM_CTL(ddr_interface_num));
- lmc_dimm_ctl.s.dimm0_wmask = 0xffff;
- lmc_dimm_ctl.s.dimm1_wmask = (dimm_count > 1) ? 0xffff : 0x0000;
- lmc_dimm_ctl.s.tcws = 0x4e0;
- lmc_dimm_ctl.cn88xx.parity = custom_lmc_config->parity;
+ /* LMC0_DIMM_CTL */
+ lmc_dimm_ctl.u = BDK_CSR_READ(node, BDK_LMCX_DIMM_CTL(ddr_interface_num));
+ lmc_dimm_ctl.s.dimm0_wmask = 0xffff;
+ lmc_dimm_ctl.s.dimm1_wmask = (dimm_count > 1) ? 0xffff : 0x0000;
+ lmc_dimm_ctl.s.tcws = 0x4e0;
+ lmc_dimm_ctl.cn88xx.parity = custom_lmc_config->parity;
- if ((s = lookup_env_parameter("ddr_dimm0_wmask")) != NULL) {
- lmc_dimm_ctl.s.dimm0_wmask = strtoul(s, NULL, 0);
- }
+ if ((s = lookup_env_parameter("ddr_dimm0_wmask")) != NULL) {
+ lmc_dimm_ctl.s.dimm0_wmask = strtoul(s, NULL, 0);
+ }
- if ((s = lookup_env_parameter("ddr_dimm1_wmask")) != NULL) {
- lmc_dimm_ctl.s.dimm1_wmask = strtoul(s, NULL, 0);
- }
+ if ((s = lookup_env_parameter("ddr_dimm1_wmask")) != NULL) {
+ lmc_dimm_ctl.s.dimm1_wmask = strtoul(s, NULL, 0);
+ }
- if ((s = lookup_env_parameter("ddr_dimm_ctl_parity")) != NULL) {
- lmc_dimm_ctl.cn88xx.parity = strtoul(s, NULL, 0);
- }
+ if ((s = lookup_env_parameter("ddr_dimm_ctl_parity")) != NULL) {
+ lmc_dimm_ctl.cn88xx.parity = strtoul(s, NULL, 0);
+ }
- if ((s = lookup_env_parameter("ddr_dimm_ctl_tcws")) != NULL) {
- lmc_dimm_ctl.s.tcws = strtoul(s, NULL, 0);
- }
+ if ((s = lookup_env_parameter("ddr_dimm_ctl_tcws")) != NULL) {
+ lmc_dimm_ctl.s.tcws = strtoul(s, NULL, 0);
+ }
- ddr_print("LMC DIMM_CTL : 0x%016lx\n", lmc_dimm_ctl.u);
- DRAM_CSR_WRITE(node, BDK_LMCX_DIMM_CTL(ddr_interface_num), lmc_dimm_ctl.u);
+ ddr_print("LMC DIMM_CTL : 0x%016llx\n", lmc_dimm_ctl.u);
+ DRAM_CSR_WRITE(node, BDK_LMCX_DIMM_CTL(ddr_interface_num), lmc_dimm_ctl.u);
- perform_octeon3_ddr3_sequence(node, rank_mask,
- ddr_interface_num, 0x7 ); /* Init RCW */
- }
+ perform_octeon3_ddr3_sequence(node, rank_mask,
+ ddr_interface_num, 0x7 ); /* Init RCW */
+ }
} else { /* if (spd_rdimm) */
/* Disable register control writes for unbuffered */
bdk_lmcx_dimm_ctl_t lmc_dimm_ctl;
@@ -5083,7 +5090,7 @@ int init_octeon3_ddr3_interface(bdk_node_t node,
read_DAC_DBI_settings(node, ddr_interface_num, /*DAC*/1, dac_settings);
if ((num_samples == 1) || dram_is_verbose(VBL_DEV)) {
display_DAC_DBI_settings(node, ddr_interface_num, /*DAC*/1, use_ecc,
- dac_settings, "Internal VREF");
+ dac_settings, (char *)"Internal VREF");
}
// for DDR4, evaluate the DAC settings and retry if any issues
@@ -5119,7 +5126,7 @@ int init_octeon3_ddr3_interface(bdk_node_t node,
dac_settings[lane] = process_samples_average(&lanes[lane].bytes[0], num_samples,
ddr_interface_num, lane);
}
- display_DAC_DBI_settings(node, ddr_interface_num, /*DAC*/1, use_ecc, dac_settings, "Averaged VREF");
+ display_DAC_DBI_settings(node, ddr_interface_num, /*DAC*/1, use_ecc, dac_settings, (char *)"Averaged VREF");
// finally, write the final DAC values
for (lane = 0; lane < last_lane; lane++) {
@@ -5216,7 +5223,7 @@ int init_octeon3_ddr3_interface(bdk_node_t node,
}
DRAM_CSR_WRITE(node, BDK_LMCX_EXT_CONFIG(ddr_interface_num), ext_config.u);
- ddr_print("%-45s : 0x%016lx\n", "EXT_CONFIG", ext_config.u);
+ ddr_print("%-45s : 0x%016llx\n", "EXT_CONFIG", ext_config.u);
}
@@ -5230,8 +5237,8 @@ int init_octeon3_ddr3_interface(bdk_node_t node,
long enough for a few ZQCS calibrations to occur. This
should ensure that the calibration circuitry is
stabilized before read/write leveling occurs. */
- save_ref_zqcs_int = lmc_config.s.ref_zqcs_int;
- lmc_config.s.ref_zqcs_int = 1 | (32<<7); /* set smallest interval */
+ save_ref_zqcs_int = lmc_config.s.ref_zqcs_int;
+ lmc_config.s.ref_zqcs_int = 1 | (32<<7); /* set smallest interval */
DRAM_CSR_WRITE(node, BDK_LMCX_CONFIG(ddr_interface_num), lmc_config.u);
BDK_CSR_READ(node, BDK_LMCX_CONFIG(ddr_interface_num));
@@ -5245,11 +5252,11 @@ int init_octeon3_ddr3_interface(bdk_node_t node,
* tclk_psecs * 100 * 512 * 128) / (10000*10000)
+ 10 * ((uint64_t)32 * tclk_psecs * 100 * 512 * 128) / (10000*10000);
- VB_PRT(VBL_FAE, "N%d.LMC%d: Waiting %ld usecs for ZQCS calibrations to start\n",
+ VB_PRT(VBL_FAE, "N%d.LMC%d: Waiting %lld usecs for ZQCS calibrations to start\n",
node, ddr_interface_num, temp_delay_usecs);
bdk_wait_usec(temp_delay_usecs);
- lmc_config.s.ref_zqcs_int = save_ref_zqcs_int; /* Restore computed interval */
+ lmc_config.s.ref_zqcs_int = save_ref_zqcs_int; /* Restore computed interval */
DRAM_CSR_WRITE(node, BDK_LMCX_CONFIG(ddr_interface_num), lmc_config.u);
BDK_CSR_READ(node, BDK_LMCX_CONFIG(ddr_interface_num));
@@ -5410,7 +5417,7 @@ int init_octeon3_ddr3_interface(bdk_node_t node,
else {
wlevel_bitmask_errors = 1; /* Force software write-leveling to run */
ddr_print("N%d.LMC%d: Forcing software Write-Leveling\n", node, ddr_interface_num);
- }
+ }
default_wlevel_rtt_nom = (ddr_type == DDR3_DRAM) ? rttnom_20ohm : ddr4_rttnom_40ohm ; /* FIXME? */
@@ -5423,7 +5430,7 @@ int init_octeon3_ddr3_interface(bdk_node_t node,
if ((s = lookup_env_parameter_ull("ddr_hwl_wodt_mask")) != NULL) {
lmc_wodt_mask.u = strtoull(s, NULL, 0);
if (lmc_wodt_mask.u != saved_wodt_mask) { // print/store only when diff
- ddr_print("WODT_MASK : 0x%016lx\n", lmc_wodt_mask.u);
+ ddr_print("WODT_MASK : 0x%016llx\n", lmc_wodt_mask.u);
DRAM_CSR_WRITE(node, BDK_LMCX_WODT_MASK(ddr_interface_num), lmc_wodt_mask.u);
}
}
@@ -5431,18 +5438,18 @@ int init_octeon3_ddr3_interface(bdk_node_t node,
#endif /* WODT_MASK_2R_1S */
lmc_config.u = BDK_CSR_READ(node, BDK_LMCX_CONFIG(ddr_interface_num));
- ecc_ena = lmc_config.s.ecc_ena;
+ ecc_ena = lmc_config.s.ecc_ena;
- if ((s = lookup_env_parameter("ddr_wlevel_roundup")) != NULL) {
- ddr_wlevel_roundup = strtoul(s, NULL, 0);
- }
- if ((s = lookup_env_parameter("ddr_wlevel_printall")) != NULL) {
- ddr_wlevel_printall = strtoul(s, NULL, 0);
- }
+ if ((s = lookup_env_parameter("ddr_wlevel_roundup")) != NULL) {
+ ddr_wlevel_roundup = strtoul(s, NULL, 0);
+ }
+ if ((s = lookup_env_parameter("ddr_wlevel_printall")) != NULL) {
+ ddr_wlevel_printall = strtoul(s, NULL, 0);
+ }
- if ((s = lookup_env_parameter("ddr_disable_hwl_validity")) != NULL) {
- disable_hwl_validity = !!strtoul(s, NULL, 0);
- }
+ if ((s = lookup_env_parameter("ddr_disable_hwl_validity")) != NULL) {
+ disable_hwl_validity = !!strtoul(s, NULL, 0);
+ }
if ((s = lookup_env_parameter("ddr_wlevel_rtt_nom")) != NULL) {
default_wlevel_rtt_nom = strtoul(s, NULL, 0);
@@ -5483,22 +5490,22 @@ int init_octeon3_ddr3_interface(bdk_node_t node,
}
// Start the hardware write-leveling loop per rank
- for (rankx = 0; rankx < dimm_count * 4; rankx++) {
+ for (rankx = 0; rankx < dimm_count * 4; rankx++) {
- if (!(rank_mask & (1 << rankx)))
- continue;
+ if (!(rank_mask & (1 << rankx)))
+ continue;
#if HW_WL_MAJORITY
- // array to collect counts of byte-lane values
- // assume low-order 3 bits and even, so really only 2 bit values
- int wlevel_bytes[9][4];
- memset(wlevel_bytes, 0, sizeof(wlevel_bytes));
+ // array to collect counts of byte-lane values
+ // assume low-order 3 bits and even, so really only 2 bit values
+ int wlevel_bytes[9][4];
+ memset(wlevel_bytes, 0, sizeof(wlevel_bytes));
#endif
- // restructure the looping so we can keep trying until we get the samples we want
- //for (int wloop = 0; wloop < wlevel_loops; wloop++) {
- int wloop = 0;
- int wloop_retries = 0; // retries per sample for HW-related issues with bitmasks or values
+ // restructure the looping so we can keep trying until we get the samples we want
+ //for (int wloop = 0; wloop < wlevel_loops; wloop++) {
+ int wloop = 0;
+ int wloop_retries = 0; // retries per sample for HW-related issues with bitmasks or values
int wloop_retries_total = 0;
int wloop_retries_exhausted = 0;
#define WLOOP_RETRIES_DEFAULT 5
@@ -5506,86 +5513,85 @@ int init_octeon3_ddr3_interface(bdk_node_t node,
int wlevel_bitmask_errors_rank = 0;
int wlevel_validity_errors_rank = 0;
- while (wloop < wlevel_loops) {
+ while (wloop < wlevel_loops) {
- wlevel_ctl.u = BDK_CSR_READ(node, BDK_LMCX_WLEVEL_CTL(ddr_interface_num));
+ wlevel_ctl.u = BDK_CSR_READ(node, BDK_LMCX_WLEVEL_CTL(ddr_interface_num));
- wlevel_ctl.s.rtt_nom = (default_wlevel_rtt_nom > 0) ? (default_wlevel_rtt_nom - 1) : 7;
+ wlevel_ctl.s.rtt_nom = (default_wlevel_rtt_nom > 0) ? (default_wlevel_rtt_nom - 1) : 7;
- DRAM_CSR_WRITE(node, BDK_LMCX_WLEVEL_RANKX(ddr_interface_num, rankx), 0); /* Clear write-level delays */
+ DRAM_CSR_WRITE(node, BDK_LMCX_WLEVEL_RANKX(ddr_interface_num, rankx), 0); /* Clear write-level delays */
- wlevel_bitmask_errors = 0; /* Reset error counters */
+ wlevel_bitmask_errors = 0; /* Reset error counters */
wlevel_validity_errors = 0;
- for (byte_idx=0; byte_idx<9; ++byte_idx) {
- wlevel_bitmask[byte_idx] = 0; /* Reset bitmasks */
- }
+ for (byte_idx=0; byte_idx<9; ++byte_idx) {
+ wlevel_bitmask[byte_idx] = 0; /* Reset bitmasks */
+ }
#if HWL_BY_BYTE // FIXME???
- /* Make a separate pass for each byte to reduce power. */
- for (byte_idx=0; byte_idx<(8+ecc_ena); ++byte_idx) {
+ /* Make a separate pass for each byte to reduce power. */
+ for (byte_idx=0; byte_idx<(8+ecc_ena); ++byte_idx) {
- if (!(ddr_interface_bytemask&(1<<byte_idx)))
- continue;
+ if (!(ddr_interface_bytemask&(1<<byte_idx)))
+ continue;
- wlevel_ctl.s.lanemask = (1<<byte_idx);
+ wlevel_ctl.s.lanemask = (1<<byte_idx);
- DRAM_CSR_WRITE(node, BDK_LMCX_WLEVEL_CTL(ddr_interface_num), wlevel_ctl.u);
+ DRAM_CSR_WRITE(node, BDK_LMCX_WLEVEL_CTL(ddr_interface_num), wlevel_ctl.u);
- /* Read and write values back in order to update the
- status field. This insures that we read the updated
- values after write-leveling has completed. */
- DRAM_CSR_WRITE(node, BDK_LMCX_WLEVEL_RANKX(ddr_interface_num, rankx),
- BDK_CSR_READ(node, BDK_LMCX_WLEVEL_RANKX(ddr_interface_num, rankx)));
+ /* Read and write values back in order to update the
+ status field. This insures that we read the updated
+ values after write-leveling has completed. */
+ DRAM_CSR_WRITE(node, BDK_LMCX_WLEVEL_RANKX(ddr_interface_num, rankx),
+ BDK_CSR_READ(node, BDK_LMCX_WLEVEL_RANKX(ddr_interface_num, rankx)));
- perform_octeon3_ddr3_sequence(node, 1 << rankx, ddr_interface_num, 6); /* write-leveling */
+ perform_octeon3_ddr3_sequence(node, 1 << rankx, ddr_interface_num, 6); /* write-leveling */
- if (!bdk_is_platform(BDK_PLATFORM_ASIM) &&
- BDK_CSR_WAIT_FOR_FIELD(node, BDK_LMCX_WLEVEL_RANKX(ddr_interface_num, rankx),
- status, ==, 3, 1000000))
- {
- error_print("ERROR: Timeout waiting for WLEVEL\n");
- }
- lmc_wlevel_rank.u = BDK_CSR_READ(node, BDK_LMCX_WLEVEL_RANKX(ddr_interface_num, rankx));
+ if (!bdk_is_platform(BDK_PLATFORM_ASIM) &&
+ BDK_CSR_WAIT_FOR_FIELD(node, BDK_LMCX_WLEVEL_RANKX(ddr_interface_num, rankx),
+ status, ==, 3, 1000000))
+ {
+ error_print("ERROR: Timeout waiting for WLEVEL\n");
+ }
+ lmc_wlevel_rank.u = BDK_CSR_READ(node, BDK_LMCX_WLEVEL_RANKX(ddr_interface_num, rankx));
- wlevel_bitmask[byte_idx] = octeon_read_lmcx_ddr3_wlevel_dbg(node, ddr_interface_num, byte_idx);
- if (wlevel_bitmask[byte_idx] == 0)
- ++wlevel_bitmask_errors;
- } /* for (byte_idx=0; byte_idx<(8+ecc_ena); ++byte_idx) */
+ wlevel_bitmask[byte_idx] = octeon_read_lmcx_ddr3_wlevel_dbg(node, ddr_interface_num, byte_idx);
+ if (wlevel_bitmask[byte_idx] == 0)
+ ++wlevel_bitmask_errors;
+ } /* for (byte_idx=0; byte_idx<(8+ecc_ena); ++byte_idx) */
- wlevel_ctl.s.lanemask = /*0x1ff*/ddr_interface_bytemask; // restore for RL
- DRAM_CSR_WRITE(node, BDK_LMCX_WLEVEL_CTL(ddr_interface_num), wlevel_ctl.u);
+ wlevel_ctl.s.lanemask = /*0x1ff*/ddr_interface_bytemask; // restore for RL
+ DRAM_CSR_WRITE(node, BDK_LMCX_WLEVEL_CTL(ddr_interface_num), wlevel_ctl.u);
#else
// do all the byte-lanes at the same time
- wlevel_ctl.s.lanemask = /*0x1ff*/ddr_interface_bytemask; // FIXME?
-
- DRAM_CSR_WRITE(node, BDK_LMCX_WLEVEL_CTL(ddr_interface_num), wlevel_ctl.u);
-
- /* Read and write values back in order to update the
- status field. This insures that we read the updated
- values after write-leveling has completed. */
- DRAM_CSR_WRITE(node, BDK_LMCX_WLEVEL_RANKX(ddr_interface_num, rankx),
- BDK_CSR_READ(node, BDK_LMCX_WLEVEL_RANKX(ddr_interface_num, rankx)));
-
- perform_octeon3_ddr3_sequence(node, 1 << rankx, ddr_interface_num, 6); /* write-leveling */
-
- if (!bdk_is_platform(BDK_PLATFORM_ASIM) &&
- BDK_CSR_WAIT_FOR_FIELD(node, BDK_LMCX_WLEVEL_RANKX(ddr_interface_num, rankx),
- status, ==, 3, 1000000))
- {
- error_print("ERROR: Timeout waiting for WLEVEL\n");
- }
-
- lmc_wlevel_rank.u = BDK_CSR_READ(node, BDK_LMCX_WLEVEL_RANKX(ddr_interface_num, rankx));
-
- for (byte_idx=0; byte_idx<(8+ecc_ena); ++byte_idx) {
- if (!(ddr_interface_bytemask&(1<<byte_idx)))
- continue;
- wlevel_bitmask[byte_idx] = octeon_read_lmcx_ddr3_wlevel_dbg(node, ddr_interface_num, byte_idx);
- if (wlevel_bitmask[byte_idx] == 0)
- ++wlevel_bitmask_errors;
- } /* for (byte_idx=0; byte_idx<(8+ecc_ena); ++byte_idx) */
+ wlevel_ctl.s.lanemask = /*0x1ff*/ddr_interface_bytemask; // FIXME?
+
+ DRAM_CSR_WRITE(node, BDK_LMCX_WLEVEL_CTL(ddr_interface_num), wlevel_ctl.u);
+
+ /* Read and write values back in order to update the
+ status field. This insures that we read the updated
+ values after write-leveling has completed. */
+ DRAM_CSR_WRITE(node, BDK_LMCX_WLEVEL_RANKX(ddr_interface_num, rankx),
+ BDK_CSR_READ(node, BDK_LMCX_WLEVEL_RANKX(ddr_interface_num, rankx)));
+
+ perform_octeon3_ddr3_sequence(node, 1 << rankx, ddr_interface_num, 6); /* write-leveling */
+
+ if (BDK_CSR_WAIT_FOR_FIELD(node, BDK_LMCX_WLEVEL_RANKX(ddr_interface_num, rankx),
+ status, ==, 3, 1000000))
+ {
+ error_print("ERROR: Timeout waiting for WLEVEL\n");
+ }
+
+ lmc_wlevel_rank.u = BDK_CSR_READ(node, BDK_LMCX_WLEVEL_RANKX(ddr_interface_num, rankx));
+
+ for (byte_idx=0; byte_idx<(8+ecc_ena); ++byte_idx) {
+ if (!(ddr_interface_bytemask&(1<<byte_idx)))
+ continue;
+ wlevel_bitmask[byte_idx] = octeon_read_lmcx_ddr3_wlevel_dbg(node, ddr_interface_num, byte_idx);
+ if (wlevel_bitmask[byte_idx] == 0)
+ ++wlevel_bitmask_errors;
+ } /* for (byte_idx=0; byte_idx<(8+ecc_ena); ++byte_idx) */
#endif
// check validity only if no bitmask errors
@@ -5606,128 +5612,128 @@ int init_octeon3_ddr3_interface(bdk_node_t node,
} else
wlevel_bitmask_errors_rank++;
- // before we print, if we had bitmask or validity errors, do a retry...
- if ((wlevel_bitmask_errors != 0) || (wlevel_validity_errors != 0)) {
+ // before we print, if we had bitmask or validity errors, do a retry...
+ if ((wlevel_bitmask_errors != 0) || (wlevel_validity_errors != 0)) {
// VBL must be high to show the bad bitmaps or delays here also
if (dram_is_verbose(VBL_DEV2)) {
display_WL_BM(node, ddr_interface_num, rankx, wlevel_bitmask);
display_WL(node, ddr_interface_num, lmc_wlevel_rank, rankx);
}
- if (wloop_retries < WLOOP_RETRIES_DEFAULT) {
- wloop_retries++;
+ if (wloop_retries < WLOOP_RETRIES_DEFAULT) {
+ wloop_retries++;
wloop_retries_total++;
- // this printout is per-retry: only when VBL is high enough (DEV2?)
- VB_PRT(VBL_DEV2, "N%d.LMC%d.R%d: H/W Write-Leveling had %s errors - retrying...\n",
- node, ddr_interface_num, rankx,
+ // this printout is per-retry: only when VBL is high enough (DEV2?)
+ VB_PRT(VBL_DEV2, "N%d.LMC%d.R%d: H/W Write-Leveling had %s errors - retrying...\n",
+ node, ddr_interface_num, rankx,
(wlevel_bitmask_errors) ? "Bitmask" : "Validity");
- continue; // this takes us back to the top without counting a sample
- } else { // ran out of retries for this sample
+ continue; // this takes us back to the top without counting a sample
+ } else { // ran out of retries for this sample
// retries exhausted, do not print at normal VBL
- VB_PRT(VBL_DEV2, "N%d.LMC%d.R%d: H/W Write-Leveling issues: %s errors\n",
- node, ddr_interface_num, rankx,
+ VB_PRT(VBL_DEV2, "N%d.LMC%d.R%d: H/W Write-Leveling issues: %s errors\n",
+ node, ddr_interface_num, rankx,
(wlevel_bitmask_errors) ? "Bitmask" : "Validity");
wloop_retries_exhausted++;
- }
- }
+ }
+ }
// no errors or exhausted retries, use this sample
wloop_retries = 0; //reset for next sample
- // when only 1 sample or forced, print the bitmasks first and current HW WL
- if ((wlevel_loops == 1) || ddr_wlevel_printall) {
- display_WL_BM(node, ddr_interface_num, rankx, wlevel_bitmask);
- display_WL(node, ddr_interface_num, lmc_wlevel_rank, rankx);
- }
-
- if (ddr_wlevel_roundup) { /* Round up odd bitmask delays */
- for (byte_idx=0; byte_idx<(8+ecc_ena); ++byte_idx) {
- if (!(ddr_interface_bytemask&(1<<byte_idx)))
- continue;
- update_wlevel_rank_struct(&lmc_wlevel_rank,
- byte_idx,
- roundup_ddr3_wlevel_bitmask(wlevel_bitmask[byte_idx]));
- } /* for (byte_idx=0; byte_idx<(8+ecc_ena); ++byte_idx) */
- DRAM_CSR_WRITE(node, BDK_LMCX_WLEVEL_RANKX(ddr_interface_num, rankx), lmc_wlevel_rank.u);
- display_WL(node, ddr_interface_num, lmc_wlevel_rank, rankx);
- }
+ // when only 1 sample or forced, print the bitmasks first and current HW WL
+ if ((wlevel_loops == 1) || ddr_wlevel_printall) {
+ display_WL_BM(node, ddr_interface_num, rankx, wlevel_bitmask);
+ display_WL(node, ddr_interface_num, lmc_wlevel_rank, rankx);
+ }
+
+ if (ddr_wlevel_roundup) { /* Round up odd bitmask delays */
+ for (byte_idx=0; byte_idx<(8+ecc_ena); ++byte_idx) {
+ if (!(ddr_interface_bytemask&(1<<byte_idx)))
+ continue;
+ update_wlevel_rank_struct(&lmc_wlevel_rank,
+ byte_idx,
+ roundup_ddr3_wlevel_bitmask(wlevel_bitmask[byte_idx]));
+ } /* for (byte_idx=0; byte_idx<(8+ecc_ena); ++byte_idx) */
+ DRAM_CSR_WRITE(node, BDK_LMCX_WLEVEL_RANKX(ddr_interface_num, rankx), lmc_wlevel_rank.u);
+ display_WL(node, ddr_interface_num, lmc_wlevel_rank, rankx);
+ }
#if HW_WL_MAJORITY
- // OK, we have a decent sample, no bitmask or validity errors
- for (byte_idx=0; byte_idx<(8+ecc_ena); ++byte_idx) {
- if (!(ddr_interface_bytemask&(1<<byte_idx)))
- continue;
- // increment count of byte-lane value
- int ix = (get_wlevel_rank_struct(&lmc_wlevel_rank, byte_idx) >> 1) & 3; // only 4 values
- wlevel_bytes[byte_idx][ix]++;
- } /* for (byte_idx=0; byte_idx<(8+ecc_ena); ++byte_idx) */
+ // OK, we have a decent sample, no bitmask or validity errors
+ for (byte_idx=0; byte_idx<(8+ecc_ena); ++byte_idx) {
+ if (!(ddr_interface_bytemask&(1<<byte_idx)))
+ continue;
+ // increment count of byte-lane value
+ int ix = (get_wlevel_rank_struct(&lmc_wlevel_rank, byte_idx) >> 1) & 3; // only 4 values
+ wlevel_bytes[byte_idx][ix]++;
+ } /* for (byte_idx=0; byte_idx<(8+ecc_ena); ++byte_idx) */
#endif
- wloop++; // if we get here, we have taken a decent sample
+ wloop++; // if we get here, we have taken a decent sample
- } /* while (wloop < wlevel_loops) */
+ } /* while (wloop < wlevel_loops) */
#if HW_WL_MAJORITY
- // if we did sample more than once, try to pick a majority vote
- if (wlevel_loops > 1) {
- // look for the majority in each byte-lane
- for (byte_idx = 0; byte_idx < (8+ecc_ena); ++byte_idx) {
- int mx = -1, mc = 0, xc = 0, cc = 0;
- int ix, ic;
- if (!(ddr_interface_bytemask&(1<<byte_idx)))
- continue;
- for (ix = 0; ix < 4; ix++) {
- ic = wlevel_bytes[byte_idx][ix];
- // make a bitmask of the ones with a count
- if (ic > 0) {
- mc |= (1 << ix);
- cc++; // count how many had non-zero counts
- }
- // find the majority
- if (ic > xc) { // new max?
- xc = ic; // yes
- mx = ix; // set its index
- }
- }
+ // if we did sample more than once, try to pick a majority vote
+ if (wlevel_loops > 1) {
+ // look for the majority in each byte-lane
+ for (byte_idx = 0; byte_idx < (8+ecc_ena); ++byte_idx) {
+ int mx = -1, mc = 0, xc = 0, cc = 0;
+ int ix, ic;
+ if (!(ddr_interface_bytemask&(1<<byte_idx)))
+ continue;
+ for (ix = 0; ix < 4; ix++) {
+ ic = wlevel_bytes[byte_idx][ix];
+ // make a bitmask of the ones with a count
+ if (ic > 0) {
+ mc |= (1 << ix);
+ cc++; // count how many had non-zero counts
+ }
+ // find the majority
+ if (ic > xc) { // new max?
+ xc = ic; // yes
+ mx = ix; // set its index
+ }
+ }
#if SWL_TRY_HWL_ALT
- // see if there was an alternate
- int alts = (mc & ~(1 << mx)); // take out the majority choice
- if (alts != 0) {
- for (ix = 0; ix < 4; ix++) {
- if (alts & (1 << ix)) { // FIXME: could be done multiple times? bad if so
- hwl_alts[rankx].hwl_alt_mask |= (1 << byte_idx); // set the mask
- hwl_alts[rankx].hwl_alt_delay[byte_idx] = ix << 1; // record the value
- VB_PRT(VBL_DEV, "N%d.LMC%d.R%d: SWL_TRY_HWL_ALT: Byte %d maj %d (%d) alt %d (%d).\n",
+ // see if there was an alternate
+ int alts = (mc & ~(1 << mx)); // take out the majority choice
+ if (alts != 0) {
+ for (ix = 0; ix < 4; ix++) {
+ if (alts & (1 << ix)) { // FIXME: could be done multiple times? bad if so
+ hwl_alts[rankx].hwl_alt_mask |= (1 << byte_idx); // set the mask
+ hwl_alts[rankx].hwl_alt_delay[byte_idx] = ix << 1; // record the value
+ VB_PRT(VBL_DEV, "N%d.LMC%d.R%d: SWL_TRY_HWL_ALT: Byte %d maj %d (%d) alt %d (%d).\n",
node, ddr_interface_num, rankx, byte_idx, mx << 1, xc,
ix << 1, wlevel_bytes[byte_idx][ix]);
- }
- }
- } else {
- debug_print("N%d.LMC%d.R%d: SWL_TRY_HWL_ALT: Byte %d maj %d alt NONE.\n",
- node, ddr_interface_num, rankx, byte_idx, mx << 1);
- }
+ }
+ }
+ } else {
+ debug_print("N%d.LMC%d.R%d: SWL_TRY_HWL_ALT: Byte %d maj %d alt NONE.\n",
+ node, ddr_interface_num, rankx, byte_idx, mx << 1);
+ }
#endif /* SWL_TRY_HWL_ALT */
- if (cc > 2) { // unlikely, but...
- // assume: counts for 3 indices are all 1
- // possiblities are: 0/2/4, 2/4/6, 0/4/6, 0/2/6
- // and the desired?: 2 , 4 , 6, 0
- // we choose the middle, assuming one of the outliers is bad
- // NOTE: this is an ugly hack at the moment; there must be a better way
- switch (mc) {
- case 0x7: mx = 1; break; // was 0/2/4, choose 2
- case 0xb: mx = 0; break; // was 0/2/6, choose 0
- case 0xd: mx = 3; break; // was 0/4/6, choose 6
- case 0xe: mx = 2; break; // was 2/4/6, choose 4
- default:
- case 0xf: mx = 1; break; // was 0/2/4/6, choose 2?
- }
- error_print("N%d.LMC%d.R%d: HW WL MAJORITY: bad byte-lane %d (0x%x), using %d.\n",
- node, ddr_interface_num, rankx, byte_idx, mc, mx << 1);
- }
- update_wlevel_rank_struct(&lmc_wlevel_rank, byte_idx, mx << 1);
- } /* for (byte_idx=0; byte_idx<(8+ecc_ena); ++byte_idx) */
-
- DRAM_CSR_WRITE(node, BDK_LMCX_WLEVEL_RANKX(ddr_interface_num, rankx), lmc_wlevel_rank.u);
- display_WL_with_final(node, ddr_interface_num, lmc_wlevel_rank, rankx);
- } /* if (wlevel_loops > 1) */
+ if (cc > 2) { // unlikely, but...
+ // assume: counts for 3 indices are all 1
+ // possiblities are: 0/2/4, 2/4/6, 0/4/6, 0/2/6
+ // and the desired?: 2 , 4 , 6, 0
+ // we choose the middle, assuming one of the outliers is bad
+ // NOTE: this is an ugly hack at the moment; there must be a better way
+ switch (mc) {
+ case 0x7: mx = 1; break; // was 0/2/4, choose 2
+ case 0xb: mx = 0; break; // was 0/2/6, choose 0
+ case 0xd: mx = 3; break; // was 0/4/6, choose 6
+ case 0xe: mx = 2; break; // was 2/4/6, choose 4
+ default:
+ case 0xf: mx = 1; break; // was 0/2/4/6, choose 2?
+ }
+ error_print("N%d.LMC%d.R%d: HW WL MAJORITY: bad byte-lane %d (0x%x), using %d.\n",
+ node, ddr_interface_num, rankx, byte_idx, mc, mx << 1);
+ }
+ update_wlevel_rank_struct(&lmc_wlevel_rank, byte_idx, mx << 1);
+ } /* for (byte_idx=0; byte_idx<(8+ecc_ena); ++byte_idx) */
+
+ DRAM_CSR_WRITE(node, BDK_LMCX_WLEVEL_RANKX(ddr_interface_num, rankx), lmc_wlevel_rank.u);
+ display_WL_with_final(node, ddr_interface_num, lmc_wlevel_rank, rankx);
+ } /* if (wlevel_loops > 1) */
#endif /* HW_WL_MAJORITY */
// maybe print an error summary for the rank
if ((wlevel_bitmask_errors_rank != 0) || (wlevel_validity_errors_rank != 0)) {
@@ -5737,7 +5743,7 @@ int init_octeon3_ddr3_interface(bdk_node_t node,
wloop_retries_total, wloop_retries_exhausted);
}
- } /* for (rankx = 0; rankx < dimm_count * 4;rankx++) */
+ } /* for (rankx = 0; rankx < dimm_count * 4;rankx++) */
#if WODT_MASK_2R_1S
if ((ddr_type == DDR4_DRAM) && (num_ranks == 2) && (dimm_count == 1)) {
@@ -5747,7 +5753,7 @@ int init_octeon3_ddr3_interface(bdk_node_t node,
lmc_wodt_mask.u = BDK_CSR_READ(node, BDK_LMCX_WODT_MASK(ddr_interface_num));
if (lmc_wodt_mask.u != saved_wodt_mask) { // always restore what was saved if diff
lmc_wodt_mask.u = saved_wodt_mask;
- ddr_print("WODT_MASK : 0x%016lx\n", lmc_wodt_mask.u);
+ ddr_print("WODT_MASK : 0x%016llx\n", lmc_wodt_mask.u);
DRAM_CSR_WRITE(node, BDK_LMCX_WODT_MASK(ddr_interface_num), lmc_wodt_mask.u);
}
}
@@ -5759,26 +5765,26 @@ int init_octeon3_ddr3_interface(bdk_node_t node,
if (! disable_deskew_training) {
deskew_counts_t dsk_counts;
- int retry_count = 0;
+ int retry_count = 0;
- VB_PRT(VBL_FAE, "N%d.LMC%d: Check Deskew Settings before Read-Leveling.\n", node, ddr_interface_num);
+ VB_PRT(VBL_FAE, "N%d.LMC%d: Check Deskew Settings before Read-Leveling.\n", node, ddr_interface_num);
- do {
- Validate_Read_Deskew_Training(node, rank_mask, ddr_interface_num, &dsk_counts, VBL_FAE);
+ do {
+ Validate_Read_Deskew_Training(node, rank_mask, ddr_interface_num, &dsk_counts, VBL_FAE);
- // only RAWCARD A or B will not benefit from retraining if there's only saturation
+ // only RAWCARD A or B will not benefit from retraining if there's only saturation
// or any rawcard if there is a nibble error
- if ((!spd_rawcard_AorB && dsk_counts.saturated > 0) ||
- ((dsk_counts.nibrng_errs != 0) || (dsk_counts.nibunl_errs != 0)))
- {
- retry_count++;
- VB_PRT(VBL_FAE, "N%d.LMC%d: Deskew Status indicates saturation or nibble errors - retry %d Training.\n",
- node, ddr_interface_num, retry_count);
- Perform_Read_Deskew_Training(node, rank_mask, ddr_interface_num,
+ if ((!spd_rawcard_AorB && dsk_counts.saturated > 0) ||
+ ((dsk_counts.nibrng_errs != 0) || (dsk_counts.nibunl_errs != 0)))
+ {
+ retry_count++;
+ VB_PRT(VBL_FAE, "N%d.LMC%d: Deskew Status indicates saturation or nibble errors - retry %d Training.\n",
+ node, ddr_interface_num, retry_count);
+ Perform_Read_Deskew_Training(node, rank_mask, ddr_interface_num,
spd_rawcard_AorB, 0, ddr_interface_64b);
- } else
- break;
- } while (retry_count < 5);
+ } else
+ break;
+ } while (retry_count < 5);
// print the last setting only if we had to do retries here
if (retry_count > 0)
@@ -6019,9 +6025,6 @@ int init_octeon3_ddr3_interface(bdk_node_t node,
DRAM_CSR_WRITE(node, BDK_LMCX_RLEVEL_CTL(ddr_interface_num), rlevel_ctl.u);
- if (bdk_is_platform(BDK_PLATFORM_ASIM))
- rlevel_debug_loops = 0;
-
if ((s = lookup_env_parameter("ddr%d_rlevel_debug_loops", ddr_interface_num)) != NULL) {
rlevel_debug_loops = strtoul(s, NULL, 0);
}
@@ -6038,7 +6041,7 @@ int init_octeon3_ddr3_interface(bdk_node_t node,
ddr_rlevel_compute = strtoul(s, NULL, 0);
}
- ddr_print("RLEVEL_CTL : 0x%016lx\n", rlevel_ctl.u);
+ ddr_print("RLEVEL_CTL : 0x%016llx\n", rlevel_ctl.u);
ddr_print("RLEVEL_OFFSET : %6d\n", rlevel_ctl.s.offset);
ddr_print("RLEVEL_OFFSET_EN : %6d\n", rlevel_ctl.s.offset_en);
@@ -6067,7 +6070,7 @@ int init_octeon3_ddr3_interface(bdk_node_t node,
#ifdef ENABLE_CUSTOM_RLEVEL_TABLE
if (custom_lmc_config->rlevel_table != NULL) {
- char part_number[21];
+ char part_number[21];
/* Check for hard-coded read-leveling settings */
get_dimm_part_number(part_number, node, &dimm_config_table[0], 0, ddr_type);
for (rankx = 0; rankx < dimm_count * 4;rankx++) {
@@ -6081,7 +6084,7 @@ int init_octeon3_ddr3_interface(bdk_node_t node,
debug_print("DIMM part number:\"%s\", SPD: \"%s\"\n", custom_lmc_config->rlevel_table[i].part, part_number);
if ((strcmp(part_number, custom_lmc_config->rlevel_table[i].part) == 0)
&& (_abs(custom_lmc_config->rlevel_table[i].speed - 2*ddr_hertz/(1000*1000)) < 10 ))
- {
+ {
ddr_print("Using hard-coded read leveling for DIMM part number: \"%s\"\n", part_number);
lmc_rlevel_rank.u = custom_lmc_config->rlevel_table[i].rlevel_rank[ddr_interface_num][rankx];
DRAM_CSR_WRITE(node, BDK_LMCX_RLEVEL_RANKX(ddr_interface_num, rankx), lmc_rlevel_rank.u);
@@ -6097,61 +6100,61 @@ int init_octeon3_ddr3_interface(bdk_node_t node,
#endif /* ENABLE_CUSTOM_RLEVEL_TABLE */
while(rlevel_debug_loops--) {
- /* Initialize the error scoreboard */
- memset(rlevel_scoreboard, 0, sizeof(rlevel_scoreboard));
+ /* Initialize the error scoreboard */
+ memset(rlevel_scoreboard, 0, sizeof(rlevel_scoreboard));
- if ((s = lookup_env_parameter("ddr_rlevel_comp_offset")) != NULL) {
- rlevel_comp_offset = strtoul(s, NULL, 0);
- }
-
- disable_sequential_delay_check = custom_lmc_config->disable_sequential_delay_check;
-
- if ((s = lookup_env_parameter("ddr_disable_sequential_delay_check")) != NULL) {
- disable_sequential_delay_check = strtoul(s, NULL, 0);
- }
-
- maximum_adjacent_rlevel_delay_increment = custom_lmc_config->maximum_adjacent_rlevel_delay_increment;
-
- if ((s = lookup_env_parameter("ddr_maximum_adjacent_rlevel_delay_increment")) != NULL) {
- maximum_adjacent_rlevel_delay_increment = strtoul(s, NULL, 0);
- }
+ if ((s = lookup_env_parameter("ddr_rlevel_comp_offset")) != NULL) {
+ rlevel_comp_offset = strtoul(s, NULL, 0);
+ }
- lmc_comp_ctl2.u = BDK_CSR_READ(node, BDK_LMCX_COMP_CTL2(ddr_interface_num));
- saved_ddr__ptune = lmc_comp_ctl2.s.ddr__ptune;
- saved_ddr__ntune = lmc_comp_ctl2.s.ddr__ntune;
+ disable_sequential_delay_check = custom_lmc_config->disable_sequential_delay_check;
- /* Disable dynamic compensation settings */
- if (rlevel_comp_offset != 0) {
- lmc_comp_ctl2.s.ptune = saved_ddr__ptune;
- lmc_comp_ctl2.s.ntune = saved_ddr__ntune;
+ if ((s = lookup_env_parameter("ddr_disable_sequential_delay_check")) != NULL) {
+ disable_sequential_delay_check = strtoul(s, NULL, 0);
+ }
- /* Round up the ptune calculation to bias the odd cases toward ptune */
- lmc_comp_ctl2.s.ptune += divide_roundup(rlevel_comp_offset, 2);
- lmc_comp_ctl2.s.ntune -= rlevel_comp_offset/2;
+ maximum_adjacent_rlevel_delay_increment = custom_lmc_config->maximum_adjacent_rlevel_delay_increment;
- lmc_control.u = BDK_CSR_READ(node, BDK_LMCX_CONTROL(ddr_interface_num));
- saved_int_zqcs_dis = lmc_control.s.int_zqcs_dis;
- lmc_control.s.int_zqcs_dis = 1; /* Disable ZQCS while in bypass. */
- DRAM_CSR_WRITE(node, BDK_LMCX_CONTROL(ddr_interface_num), lmc_control.u);
+ if ((s = lookup_env_parameter("ddr_maximum_adjacent_rlevel_delay_increment")) != NULL) {
+ maximum_adjacent_rlevel_delay_increment = strtoul(s, NULL, 0);
+ }
- lmc_comp_ctl2.s.byp = 1; /* Enable bypass mode */
- DRAM_CSR_WRITE(node, BDK_LMCX_COMP_CTL2(ddr_interface_num), lmc_comp_ctl2.u);
- BDK_CSR_READ(node, BDK_LMCX_COMP_CTL2(ddr_interface_num));
- lmc_comp_ctl2.u = BDK_CSR_READ(node, BDK_LMCX_COMP_CTL2(ddr_interface_num)); /* Read again */
- ddr_print("DDR__PTUNE/DDR__NTUNE : %d/%d\n",
- lmc_comp_ctl2.s.ddr__ptune, lmc_comp_ctl2.s.ddr__ntune);
- }
+ lmc_comp_ctl2.u = BDK_CSR_READ(node, BDK_LMCX_COMP_CTL2(ddr_interface_num));
+ saved_ddr__ptune = lmc_comp_ctl2.s.ddr__ptune;
+ saved_ddr__ntune = lmc_comp_ctl2.s.ddr__ntune;
+
+ /* Disable dynamic compensation settings */
+ if (rlevel_comp_offset != 0) {
+ lmc_comp_ctl2.s.ptune = saved_ddr__ptune;
+ lmc_comp_ctl2.s.ntune = saved_ddr__ntune;
+
+ /* Round up the ptune calculation to bias the odd cases toward ptune */
+ lmc_comp_ctl2.s.ptune += divide_roundup(rlevel_comp_offset, 2);
+ lmc_comp_ctl2.s.ntune -= rlevel_comp_offset/2;
+
+ lmc_control.u = BDK_CSR_READ(node, BDK_LMCX_CONTROL(ddr_interface_num));
+ saved_int_zqcs_dis = lmc_control.s.int_zqcs_dis;
+ lmc_control.s.int_zqcs_dis = 1; /* Disable ZQCS while in bypass. */
+ DRAM_CSR_WRITE(node, BDK_LMCX_CONTROL(ddr_interface_num), lmc_control.u);
+
+ lmc_comp_ctl2.s.byp = 1; /* Enable bypass mode */
+ DRAM_CSR_WRITE(node, BDK_LMCX_COMP_CTL2(ddr_interface_num), lmc_comp_ctl2.u);
+ BDK_CSR_READ(node, BDK_LMCX_COMP_CTL2(ddr_interface_num));
+ lmc_comp_ctl2.u = BDK_CSR_READ(node, BDK_LMCX_COMP_CTL2(ddr_interface_num)); /* Read again */
+ ddr_print("DDR__PTUNE/DDR__NTUNE : %d/%d\n",
+ lmc_comp_ctl2.s.ddr__ptune, lmc_comp_ctl2.s.ddr__ntune);
+ }
- lmc_modereg_params1.u = BDK_CSR_READ(node, BDK_LMCX_MODEREG_PARAMS1(ddr_interface_num));
+ lmc_modereg_params1.u = BDK_CSR_READ(node, BDK_LMCX_MODEREG_PARAMS1(ddr_interface_num));
- for (rtt_idx = min_rtt_nom_idx; rtt_idx <= max_rtt_nom_idx; ++rtt_idx) {
- rtt_nom = imp_values->rtt_nom_table[rtt_idx];
+ for (rtt_idx = min_rtt_nom_idx; rtt_idx <= max_rtt_nom_idx; ++rtt_idx) {
+ rtt_nom = imp_values->rtt_nom_table[rtt_idx];
- /* When the read ODT mask is zero the dyn_rtt_nom_mask is
- zero than RTT_NOM will not be changing during
- read-leveling. Since the value is fixed we only need
- to test it once. */
- if (dyn_rtt_nom_mask == 0) {
+ /* When the read ODT mask is zero the dyn_rtt_nom_mask is
+ zero than RTT_NOM will not be changing during
+ read-leveling. Since the value is fixed we only need
+ to test it once. */
+ if (dyn_rtt_nom_mask == 0) {
print_nom_ohms = -1; // flag not to print NOM ohms
if (rtt_idx != min_rtt_nom_idx)
continue;
@@ -6164,19 +6167,19 @@ int init_octeon3_ddr3_interface(bdk_node_t node,
print_nom_ohms = imp_values->rtt_nom_ohms[lmc_modereg_params1.s.rtt_nom_00];
}
- DRAM_CSR_WRITE(node, BDK_LMCX_MODEREG_PARAMS1(ddr_interface_num), lmc_modereg_params1.u);
- VB_PRT(VBL_TME, "\n");
- VB_PRT(VBL_TME, "RTT_NOM %3d, %3d, %3d, %3d ohms : %x,%x,%x,%x\n",
- imp_values->rtt_nom_ohms[lmc_modereg_params1.s.rtt_nom_11],
- imp_values->rtt_nom_ohms[lmc_modereg_params1.s.rtt_nom_10],
- imp_values->rtt_nom_ohms[lmc_modereg_params1.s.rtt_nom_01],
- imp_values->rtt_nom_ohms[lmc_modereg_params1.s.rtt_nom_00],
- lmc_modereg_params1.s.rtt_nom_11,
- lmc_modereg_params1.s.rtt_nom_10,
- lmc_modereg_params1.s.rtt_nom_01,
- lmc_modereg_params1.s.rtt_nom_00);
+ DRAM_CSR_WRITE(node, BDK_LMCX_MODEREG_PARAMS1(ddr_interface_num), lmc_modereg_params1.u);
+ VB_PRT(VBL_TME, "\n");
+ VB_PRT(VBL_TME, "RTT_NOM %3d, %3d, %3d, %3d ohms : %x,%x,%x,%x\n",
+ imp_values->rtt_nom_ohms[lmc_modereg_params1.s.rtt_nom_11],
+ imp_values->rtt_nom_ohms[lmc_modereg_params1.s.rtt_nom_10],
+ imp_values->rtt_nom_ohms[lmc_modereg_params1.s.rtt_nom_01],
+ imp_values->rtt_nom_ohms[lmc_modereg_params1.s.rtt_nom_00],
+ lmc_modereg_params1.s.rtt_nom_11,
+ lmc_modereg_params1.s.rtt_nom_10,
+ lmc_modereg_params1.s.rtt_nom_01,
+ lmc_modereg_params1.s.rtt_nom_00);
- perform_ddr_init_sequence(node, rank_mask, ddr_interface_num);
+ perform_ddr_init_sequence(node, rank_mask, ddr_interface_num);
// Try RANK outside RODT to rearrange the output...
for (rankx = 0; rankx < dimm_count * 4; rankx++) {
@@ -6194,7 +6197,7 @@ int init_octeon3_ddr3_interface(bdk_node_t node,
for (rodt_ctl = max_rodt_ctl; rodt_ctl >= min_rodt_ctl; --rodt_ctl) {
#if PICK_BEST_RANK_SCORE_NOT_AVG
- rlevel_best_rank_score = DEFAULT_BEST_RANK_SCORE;
+ rlevel_best_rank_score = DEFAULT_BEST_RANK_SCORE;
#endif
rlevel_rodt_errors = 0;
lmc_comp_ctl2.u = BDK_CSR_READ(node, BDK_LMCX_COMP_CTL2(ddr_interface_num));
@@ -6205,119 +6208,116 @@ int init_octeon3_ddr3_interface(bdk_node_t node,
VB_PRT(VBL_DEV, "Read ODT_CTL : 0x%x (%d ohms)\n",
lmc_comp_ctl2.s.rodt_ctl, imp_values->rodt_ohms[lmc_comp_ctl2.s.rodt_ctl]);
- memset(rlevel_byte, 0, sizeof(rlevel_byte));
+ memset(rlevel_byte, 0, sizeof(rlevel_byte));
- for (average_loops = 0; average_loops < rlevel_avg_loops; average_loops++) {
- rlevel_bitmask_errors = 0;
+ for (average_loops = 0; average_loops < rlevel_avg_loops; average_loops++) {
+ rlevel_bitmask_errors = 0;
- if (! (rlevel_separate_ab && spd_rdimm && (ddr_type == DDR4_DRAM))) {
- /* Clear read-level delays */
- DRAM_CSR_WRITE(node, BDK_LMCX_RLEVEL_RANKX(ddr_interface_num, rankx), 0);
+ if (! (rlevel_separate_ab && spd_rdimm && (ddr_type == DDR4_DRAM))) {
+ /* Clear read-level delays */
+ DRAM_CSR_WRITE(node, BDK_LMCX_RLEVEL_RANKX(ddr_interface_num, rankx), 0);
/* read-leveling */
- perform_octeon3_ddr3_sequence(node, 1 << rankx, ddr_interface_num, 1);
+ perform_octeon3_ddr3_sequence(node, 1 << rankx, ddr_interface_num, 1);
- if (!bdk_is_platform(BDK_PLATFORM_ASIM) &&
- BDK_CSR_WAIT_FOR_FIELD(node, BDK_LMCX_RLEVEL_RANKX(ddr_interface_num, rankx),
- status, ==, 3, 1000000))
- {
+ if (BDK_CSR_WAIT_FOR_FIELD(node, BDK_LMCX_RLEVEL_RANKX(ddr_interface_num, rankx),
+ status, ==, 3, 1000000))
+ {
error_print("ERROR: Timeout waiting for RLEVEL\n");
}
- }
+ }
- lmc_rlevel_rank.u = BDK_CSR_READ(node, BDK_LMCX_RLEVEL_RANKX(ddr_interface_num, rankx));
+ lmc_rlevel_rank.u = BDK_CSR_READ(node, BDK_LMCX_RLEVEL_RANKX(ddr_interface_num, rankx));
- { // start bitmask interpretation block
+ { // start bitmask interpretation block
int redoing_nonseq_errs = 0;
memset(rlevel_bitmask, 0, sizeof(rlevel_bitmask));
- if (rlevel_separate_ab && spd_rdimm && (ddr_type == DDR4_DRAM)) {
- bdk_lmcx_rlevel_rankx_t lmc_rlevel_rank_aside;
- bdk_lmcx_modereg_params0_t lmc_modereg_params0;
+ if (rlevel_separate_ab && spd_rdimm && (ddr_type == DDR4_DRAM)) {
+ bdk_lmcx_rlevel_rankx_t lmc_rlevel_rank_aside;
+ bdk_lmcx_modereg_params0_t lmc_modereg_params0;
- /* A-side */
- lmc_modereg_params0.u = BDK_CSR_READ(node, BDK_LMCX_MODEREG_PARAMS0(ddr_interface_num));
- lmc_modereg_params0.s.mprloc = 0; /* MPR Page 0 Location 0 */
- DRAM_CSR_WRITE(node, BDK_LMCX_MODEREG_PARAMS0(ddr_interface_num), lmc_modereg_params0.u);
+ /* A-side */
+ lmc_modereg_params0.u = BDK_CSR_READ(node, BDK_LMCX_MODEREG_PARAMS0(ddr_interface_num));
+ lmc_modereg_params0.s.mprloc = 0; /* MPR Page 0 Location 0 */
+ DRAM_CSR_WRITE(node, BDK_LMCX_MODEREG_PARAMS0(ddr_interface_num), lmc_modereg_params0.u);
- /* Clear read-level delays */
- DRAM_CSR_WRITE(node, BDK_LMCX_RLEVEL_RANKX(ddr_interface_num, rankx), 0);
+ /* Clear read-level delays */
+ DRAM_CSR_WRITE(node, BDK_LMCX_RLEVEL_RANKX(ddr_interface_num, rankx), 0);
- perform_octeon3_ddr3_sequence(node, 1 << rankx, ddr_interface_num, 1); /* read-leveling */
+ perform_octeon3_ddr3_sequence(node, 1 << rankx, ddr_interface_num, 1); /* read-leveling */
- if (!bdk_is_platform(BDK_PLATFORM_ASIM) &&
- BDK_CSR_WAIT_FOR_FIELD(node, BDK_LMCX_RLEVEL_RANKX(ddr_interface_num, rankx),
- status, ==, 3, 1000000))
- {
- error_print("ERROR: Timeout waiting for RLEVEL\n");
+ if (BDK_CSR_WAIT_FOR_FIELD(node, BDK_LMCX_RLEVEL_RANKX(ddr_interface_num, rankx),
+ status, ==, 3, 1000000))
+ {
+ error_print("ERROR: Timeout waiting for RLEVEL\n");
- }
- lmc_rlevel_rank.u = BDK_CSR_READ(node, BDK_LMCX_RLEVEL_RANKX(ddr_interface_num, rankx));
+ }
+ lmc_rlevel_rank.u = BDK_CSR_READ(node, BDK_LMCX_RLEVEL_RANKX(ddr_interface_num, rankx));
- lmc_rlevel_rank_aside.u = lmc_rlevel_rank.u;
+ lmc_rlevel_rank_aside.u = lmc_rlevel_rank.u;
- rlevel_bitmask[0].bm = octeon_read_lmcx_ddr3_rlevel_dbg(node, ddr_interface_num, 0);
- rlevel_bitmask[1].bm = octeon_read_lmcx_ddr3_rlevel_dbg(node, ddr_interface_num, 1);
- rlevel_bitmask[2].bm = octeon_read_lmcx_ddr3_rlevel_dbg(node, ddr_interface_num, 2);
- rlevel_bitmask[3].bm = octeon_read_lmcx_ddr3_rlevel_dbg(node, ddr_interface_num, 3);
- rlevel_bitmask[8].bm = octeon_read_lmcx_ddr3_rlevel_dbg(node, ddr_interface_num, 8);
- /* A-side complete */
+ rlevel_bitmask[0].bm = octeon_read_lmcx_ddr3_rlevel_dbg(node, ddr_interface_num, 0);
+ rlevel_bitmask[1].bm = octeon_read_lmcx_ddr3_rlevel_dbg(node, ddr_interface_num, 1);
+ rlevel_bitmask[2].bm = octeon_read_lmcx_ddr3_rlevel_dbg(node, ddr_interface_num, 2);
+ rlevel_bitmask[3].bm = octeon_read_lmcx_ddr3_rlevel_dbg(node, ddr_interface_num, 3);
+ rlevel_bitmask[8].bm = octeon_read_lmcx_ddr3_rlevel_dbg(node, ddr_interface_num, 8);
+ /* A-side complete */
- /* B-side */
- lmc_modereg_params0.u = BDK_CSR_READ(node, BDK_LMCX_MODEREG_PARAMS0(ddr_interface_num));
- lmc_modereg_params0.s.mprloc = 3; /* MPR Page 0 Location 3 */
- DRAM_CSR_WRITE(node, BDK_LMCX_MODEREG_PARAMS0(ddr_interface_num), lmc_modereg_params0.u);
+ /* B-side */
+ lmc_modereg_params0.u = BDK_CSR_READ(node, BDK_LMCX_MODEREG_PARAMS0(ddr_interface_num));
+ lmc_modereg_params0.s.mprloc = 3; /* MPR Page 0 Location 3 */
+ DRAM_CSR_WRITE(node, BDK_LMCX_MODEREG_PARAMS0(ddr_interface_num), lmc_modereg_params0.u);
- /* Clear read-level delays */
- DRAM_CSR_WRITE(node, BDK_LMCX_RLEVEL_RANKX(ddr_interface_num, rankx), 0);
+ /* Clear read-level delays */
+ DRAM_CSR_WRITE(node, BDK_LMCX_RLEVEL_RANKX(ddr_interface_num, rankx), 0);
- perform_octeon3_ddr3_sequence(node, 1 << rankx, ddr_interface_num, 1); /* read-leveling */
+ perform_octeon3_ddr3_sequence(node, 1 << rankx, ddr_interface_num, 1); /* read-leveling */
- if (!bdk_is_platform(BDK_PLATFORM_ASIM) &&
- BDK_CSR_WAIT_FOR_FIELD(node, BDK_LMCX_RLEVEL_RANKX(ddr_interface_num, rankx),
- status, ==, 3, 1000000))
- {
- error_print("ERROR: Timeout waiting for RLEVEL\n");
- }
- lmc_rlevel_rank.u = BDK_CSR_READ(node, BDK_LMCX_RLEVEL_RANKX(ddr_interface_num, rankx));
+ if (BDK_CSR_WAIT_FOR_FIELD(node, BDK_LMCX_RLEVEL_RANKX(ddr_interface_num, rankx),
+ status, ==, 3, 1000000))
+ {
+ error_print("ERROR: Timeout waiting for RLEVEL\n");
+ }
+ lmc_rlevel_rank.u = BDK_CSR_READ(node, BDK_LMCX_RLEVEL_RANKX(ddr_interface_num, rankx));
- rlevel_bitmask[4].bm = octeon_read_lmcx_ddr3_rlevel_dbg(node, ddr_interface_num, 4);
- rlevel_bitmask[5].bm = octeon_read_lmcx_ddr3_rlevel_dbg(node, ddr_interface_num, 5);
- rlevel_bitmask[6].bm = octeon_read_lmcx_ddr3_rlevel_dbg(node, ddr_interface_num, 6);
- rlevel_bitmask[7].bm = octeon_read_lmcx_ddr3_rlevel_dbg(node, ddr_interface_num, 7);
- /* B-side complete */
+ rlevel_bitmask[4].bm = octeon_read_lmcx_ddr3_rlevel_dbg(node, ddr_interface_num, 4);
+ rlevel_bitmask[5].bm = octeon_read_lmcx_ddr3_rlevel_dbg(node, ddr_interface_num, 5);
+ rlevel_bitmask[6].bm = octeon_read_lmcx_ddr3_rlevel_dbg(node, ddr_interface_num, 6);
+ rlevel_bitmask[7].bm = octeon_read_lmcx_ddr3_rlevel_dbg(node, ddr_interface_num, 7);
+ /* B-side complete */
- update_rlevel_rank_struct(&lmc_rlevel_rank, 0, lmc_rlevel_rank_aside.cn83xx.byte0);
- update_rlevel_rank_struct(&lmc_rlevel_rank, 1, lmc_rlevel_rank_aside.cn83xx.byte1);
- update_rlevel_rank_struct(&lmc_rlevel_rank, 2, lmc_rlevel_rank_aside.cn83xx.byte2);
- update_rlevel_rank_struct(&lmc_rlevel_rank, 3, lmc_rlevel_rank_aside.cn83xx.byte3);
- update_rlevel_rank_struct(&lmc_rlevel_rank, 8, lmc_rlevel_rank_aside.cn83xx.byte8); /* ECC A-side */
+ update_rlevel_rank_struct(&lmc_rlevel_rank, 0, lmc_rlevel_rank_aside.cn83xx.byte0);
+ update_rlevel_rank_struct(&lmc_rlevel_rank, 1, lmc_rlevel_rank_aside.cn83xx.byte1);
+ update_rlevel_rank_struct(&lmc_rlevel_rank, 2, lmc_rlevel_rank_aside.cn83xx.byte2);
+ update_rlevel_rank_struct(&lmc_rlevel_rank, 3, lmc_rlevel_rank_aside.cn83xx.byte3);
+ update_rlevel_rank_struct(&lmc_rlevel_rank, 8, lmc_rlevel_rank_aside.cn83xx.byte8); /* ECC A-side */
- lmc_modereg_params0.u = BDK_CSR_READ(node, BDK_LMCX_MODEREG_PARAMS0(ddr_interface_num));
- lmc_modereg_params0.s.mprloc = 0; /* MPR Page 0 Location 0 */
- DRAM_CSR_WRITE(node, BDK_LMCX_MODEREG_PARAMS0(ddr_interface_num), lmc_modereg_params0.u);
+ lmc_modereg_params0.u = BDK_CSR_READ(node, BDK_LMCX_MODEREG_PARAMS0(ddr_interface_num));
+ lmc_modereg_params0.s.mprloc = 0; /* MPR Page 0 Location 0 */
+ DRAM_CSR_WRITE(node, BDK_LMCX_MODEREG_PARAMS0(ddr_interface_num), lmc_modereg_params0.u);
- } /* if (rlevel_separate_ab && spd_rdimm && (ddr_type == DDR4_DRAM)) */
+ } /* if (rlevel_separate_ab && spd_rdimm && (ddr_type == DDR4_DRAM)) */
- /*
+ /*
* Evaluate the quality of the read-leveling delays from the bitmasks.
* Also save off a software computed read-leveling mask that may be
* used later to qualify the delay results from Octeon.
*/
- for (byte_idx = 0; byte_idx < (8+ecc_ena); ++byte_idx) {
+ for (byte_idx = 0; byte_idx < (8+ecc_ena); ++byte_idx) {
int bmerr;
- if (!(ddr_interface_bytemask&(1<<byte_idx)))
- continue;
- if (! (rlevel_separate_ab && spd_rdimm && (ddr_type == DDR4_DRAM))) {
- rlevel_bitmask[byte_idx].bm =
- octeon_read_lmcx_ddr3_rlevel_dbg(node, ddr_interface_num, byte_idx);
- }
+ if (!(ddr_interface_bytemask&(1<<byte_idx)))
+ continue;
+ if (! (rlevel_separate_ab && spd_rdimm && (ddr_type == DDR4_DRAM))) {
+ rlevel_bitmask[byte_idx].bm =
+ octeon_read_lmcx_ddr3_rlevel_dbg(node, ddr_interface_num, byte_idx);
+ }
bmerr = validate_ddr3_rlevel_bitmask(&rlevel_bitmask[byte_idx], ddr_type);
- rlevel_bitmask[byte_idx].errs = bmerr;
- rlevel_bitmask_errors += bmerr;
+ rlevel_bitmask[byte_idx].errs = bmerr;
+ rlevel_bitmask_errors += bmerr;
#if PERFECT_BITMASK_COUNTING
if ((ddr_type == DDR4_DRAM) && !bmerr) { // count only the "perfect" bitmasks
// FIXME: could optimize this a bit?
@@ -6326,51 +6326,51 @@ int init_octeon3_ddr3_interface(bdk_node_t node,
rank_perfect_counts[rankx].total[byte_idx] += 1;
}
#endif /* PERFECT_BITMASK_COUNTING */
- }
-
- /* Set delays for unused bytes to match byte 0. */
- for (byte_idx = 0; byte_idx < 9; ++byte_idx) {
- if (ddr_interface_bytemask & (1 << byte_idx))
- continue;
- update_rlevel_rank_struct(&lmc_rlevel_rank, byte_idx, lmc_rlevel_rank.cn83xx.byte0);
- }
-
- /* Save a copy of the byte delays in physical
- order for sequential evaluation. */
- unpack_rlevel_settings(ddr_interface_bytemask, ecc_ena, rlevel_byte, lmc_rlevel_rank);
+ }
+
+ /* Set delays for unused bytes to match byte 0. */
+ for (byte_idx = 0; byte_idx < 9; ++byte_idx) {
+ if (ddr_interface_bytemask & (1 << byte_idx))
+ continue;
+ update_rlevel_rank_struct(&lmc_rlevel_rank, byte_idx, lmc_rlevel_rank.cn83xx.byte0);
+ }
+
+ /* Save a copy of the byte delays in physical
+ order for sequential evaluation. */
+ unpack_rlevel_settings(ddr_interface_bytemask, ecc_ena, rlevel_byte, lmc_rlevel_rank);
redo_nonseq_errs:
rlevel_nonseq_errors = 0;
- if (! disable_sequential_delay_check) {
- if ((ddr_interface_bytemask & 0xff) == 0xff) {
- /* Evaluate delay sequence across the whole range of bytes for standard dimms. */
- if ((spd_dimm_type == 1) || (spd_dimm_type == 5)) { /* 1=RDIMM, 5=Mini-RDIMM */
- int register_adjacent_delay = _abs(rlevel_byte[4].delay - rlevel_byte[5].delay);
- /* Registered dimm topology routes from the center. */
- rlevel_nonseq_errors += nonsequential_delays(rlevel_byte, 0, 3+ecc_ena,
- maximum_adjacent_rlevel_delay_increment);
- rlevel_nonseq_errors += nonsequential_delays(rlevel_byte, 5, 7+ecc_ena,
- maximum_adjacent_rlevel_delay_increment);
+ if (! disable_sequential_delay_check) {
+ if ((ddr_interface_bytemask & 0xff) == 0xff) {
+ /* Evaluate delay sequence across the whole range of bytes for standard dimms. */
+ if ((spd_dimm_type == 1) || (spd_dimm_type == 5)) { /* 1=RDIMM, 5=Mini-RDIMM */
+ int register_adjacent_delay = _abs(rlevel_byte[4].delay - rlevel_byte[5].delay);
+ /* Registered dimm topology routes from the center. */
+ rlevel_nonseq_errors += nonsequential_delays(rlevel_byte, 0, 3+ecc_ena,
+ maximum_adjacent_rlevel_delay_increment);
+ rlevel_nonseq_errors += nonsequential_delays(rlevel_byte, 5, 7+ecc_ena,
+ maximum_adjacent_rlevel_delay_increment);
// byte 5 sqerrs never gets cleared for RDIMMs
rlevel_byte[5].sqerrs = 0;
- if (register_adjacent_delay > 1) {
- /* Assess proximity of bytes on opposite sides of register */
- rlevel_nonseq_errors += (register_adjacent_delay-1) * RLEVEL_ADJACENT_DELAY_ERROR;
+ if (register_adjacent_delay > 1) {
+ /* Assess proximity of bytes on opposite sides of register */
+ rlevel_nonseq_errors += (register_adjacent_delay-1) * RLEVEL_ADJACENT_DELAY_ERROR;
// update byte 5 error
- rlevel_byte[5].sqerrs += (register_adjacent_delay-1) * RLEVEL_ADJACENT_DELAY_ERROR;
+ rlevel_byte[5].sqerrs += (register_adjacent_delay-1) * RLEVEL_ADJACENT_DELAY_ERROR;
}
- }
- if ((spd_dimm_type == 2) || (spd_dimm_type == 6)) { /* 2=UDIMM, 6=Mini-UDIMM */
- /* Unbuffered dimm topology routes from end to end. */
- rlevel_nonseq_errors += nonsequential_delays(rlevel_byte, 0, 7+ecc_ena,
- maximum_adjacent_rlevel_delay_increment);
- }
- } else {
- rlevel_nonseq_errors += nonsequential_delays(rlevel_byte, 0, 3+ecc_ena,
- maximum_adjacent_rlevel_delay_increment);
- }
- } /* if (! disable_sequential_delay_check) */
+ }
+ if ((spd_dimm_type == 2) || (spd_dimm_type == 6)) { /* 2=UDIMM, 6=Mini-UDIMM */
+ /* Unbuffered dimm topology routes from end to end. */
+ rlevel_nonseq_errors += nonsequential_delays(rlevel_byte, 0, 7+ecc_ena,
+ maximum_adjacent_rlevel_delay_increment);
+ }
+ } else {
+ rlevel_nonseq_errors += nonsequential_delays(rlevel_byte, 0, 3+ecc_ena,
+ maximum_adjacent_rlevel_delay_increment);
+ }
+ } /* if (! disable_sequential_delay_check) */
#if 0
// FIXME FIXME: disabled for now, it was too much...
@@ -6390,16 +6390,16 @@ int init_octeon3_ddr3_interface(bdk_node_t node,
rlevel_rank_errors = rlevel_bitmask_errors + rlevel_nonseq_errors;
#endif
- // print original sample here only if we are not really averaging or picking best
+ // print original sample here only if we are not really averaging or picking best
// also do not print if we were redoing the NONSEQ score for using COMPUTED
- if (!redoing_nonseq_errs && ((rlevel_avg_loops < 2) || dram_is_verbose(VBL_DEV2))) {
+ if (!redoing_nonseq_errs && ((rlevel_avg_loops < 2) || dram_is_verbose(VBL_DEV2))) {
display_RL_BM(node, ddr_interface_num, rankx, rlevel_bitmask, ecc_ena);
display_RL_BM_scores(node, ddr_interface_num, rankx, rlevel_bitmask, ecc_ena);
display_RL_SEQ_scores(node, ddr_interface_num, rankx, rlevel_byte, ecc_ena);
- display_RL_with_score(node, ddr_interface_num, lmc_rlevel_rank, rankx, rlevel_rank_errors);
- }
+ display_RL_with_score(node, ddr_interface_num, lmc_rlevel_rank, rankx, rlevel_rank_errors);
+ }
- if (ddr_rlevel_compute) {
+ if (ddr_rlevel_compute) {
if (!redoing_nonseq_errs) {
/* Recompute the delays based on the bitmask */
for (byte_idx = 0; byte_idx < (8+ecc_ena); ++byte_idx) {
@@ -6425,77 +6425,77 @@ int init_octeon3_ddr3_interface(bdk_node_t node,
rlevel_rank_errors);
}
}
- } /* if (ddr_rlevel_compute) */
+ } /* if (ddr_rlevel_compute) */
- } // end bitmask interpretation block
+ } // end bitmask interpretation block
#if PICK_BEST_RANK_SCORE_NOT_AVG
- // if it is a better (lower) score, then keep it
- if (rlevel_rank_errors < rlevel_best_rank_score) {
- rlevel_best_rank_score = rlevel_rank_errors;
+ // if it is a better (lower) score, then keep it
+ if (rlevel_rank_errors < rlevel_best_rank_score) {
+ rlevel_best_rank_score = rlevel_rank_errors;
- // save the new best delays and best errors
- for (byte_idx = 0; byte_idx < 9; ++byte_idx) {
- rlevel_byte[byte_idx].best = rlevel_byte[byte_idx].delay;
- rlevel_byte[byte_idx].bestsq = rlevel_byte[byte_idx].sqerrs;
+ // save the new best delays and best errors
+ for (byte_idx = 0; byte_idx < 9; ++byte_idx) {
+ rlevel_byte[byte_idx].best = rlevel_byte[byte_idx].delay;
+ rlevel_byte[byte_idx].bestsq = rlevel_byte[byte_idx].sqerrs;
// save bitmasks and their scores as well
// xlate UNPACKED index to PACKED index to get from rlevel_bitmask
- rlevel_byte[byte_idx].bm = rlevel_bitmask[XUP(byte_idx, !!ecc_ena)].bm;
- rlevel_byte[byte_idx].bmerrs = rlevel_bitmask[XUP(byte_idx, !!ecc_ena)].errs;
- }
- }
+ rlevel_byte[byte_idx].bm = rlevel_bitmask[XUP(byte_idx, !!ecc_ena)].bm;
+ rlevel_byte[byte_idx].bmerrs = rlevel_bitmask[XUP(byte_idx, !!ecc_ena)].errs;
+ }
+ }
#else /* PICK_BEST_RANK_SCORE_NOT_AVG */
- /* Accumulate the total score across averaging loops for this setting */
- debug_print("rlevel_scoreboard[rtt_nom=%d][rodt_ctl=%d][rankx=%d].score: %d [%d]\n",
- rtt_nom, rodt_ctl, rankx, rlevel_rank_errors, average_loops);
- rlevel_scoreboard[rtt_nom][rodt_ctl][rankx].score += rlevel_rank_errors;
-
- /* Accumulate the delay totals and loop counts
- necessary to compute average delay results */
- for (byte_idx = 0; byte_idx < 9; ++byte_idx) {
- if (rlevel_byte[byte_idx].delay != 0) { /* Don't include delay=0 in the average */
- ++rlevel_byte[byte_idx].loop_count;
- rlevel_byte[byte_idx].loop_total += rlevel_byte[byte_idx].delay;
- }
- } /* for (byte_idx = 0; byte_idx < 9; ++byte_idx) */
+ /* Accumulate the total score across averaging loops for this setting */
+ debug_print("rlevel_scoreboard[rtt_nom=%d][rodt_ctl=%d][rankx=%d].score: %d [%d]\n",
+ rtt_nom, rodt_ctl, rankx, rlevel_rank_errors, average_loops);
+ rlevel_scoreboard[rtt_nom][rodt_ctl][rankx].score += rlevel_rank_errors;
+
+ /* Accumulate the delay totals and loop counts
+ necessary to compute average delay results */
+ for (byte_idx = 0; byte_idx < 9; ++byte_idx) {
+ if (rlevel_byte[byte_idx].delay != 0) { /* Don't include delay=0 in the average */
+ ++rlevel_byte[byte_idx].loop_count;
+ rlevel_byte[byte_idx].loop_total += rlevel_byte[byte_idx].delay;
+ }
+ } /* for (byte_idx = 0; byte_idx < 9; ++byte_idx) */
#endif /* PICK_BEST_RANK_SCORE_NOT_AVG */
- rlevel_rodt_errors += rlevel_rank_errors;
+ rlevel_rodt_errors += rlevel_rank_errors;
- } /* for (average_loops = 0; average_loops < rlevel_avg_loops; average_loops++) */
+ } /* for (average_loops = 0; average_loops < rlevel_avg_loops; average_loops++) */
#if PICK_BEST_RANK_SCORE_NOT_AVG
- /* We recorded the best score across the averaging loops */
- rlevel_scoreboard[rtt_nom][rodt_ctl][rankx].score = rlevel_best_rank_score;
+ /* We recorded the best score across the averaging loops */
+ rlevel_scoreboard[rtt_nom][rodt_ctl][rankx].score = rlevel_best_rank_score;
- /* Restore the delays from the best fields that go with the best score */
- for (byte_idx = 0; byte_idx < 9; ++byte_idx) {
- rlevel_byte[byte_idx].delay = rlevel_byte[byte_idx].best;
- rlevel_byte[byte_idx].sqerrs = rlevel_byte[byte_idx].bestsq;
- }
+ /* Restore the delays from the best fields that go with the best score */
+ for (byte_idx = 0; byte_idx < 9; ++byte_idx) {
+ rlevel_byte[byte_idx].delay = rlevel_byte[byte_idx].best;
+ rlevel_byte[byte_idx].sqerrs = rlevel_byte[byte_idx].bestsq;
+ }
#else /* PICK_BEST_RANK_SCORE_NOT_AVG */
- /* Compute the average score across averaging loops */
- rlevel_scoreboard[rtt_nom][rodt_ctl][rankx].score =
- divide_nint(rlevel_scoreboard[rtt_nom][rodt_ctl][rankx].score, rlevel_avg_loops);
-
- /* Compute the average delay results */
- for (byte_idx=0; byte_idx < 9; ++byte_idx) {
- if (rlevel_byte[byte_idx].loop_count == 0)
- rlevel_byte[byte_idx].loop_count = 1;
- rlevel_byte[byte_idx].delay = divide_nint(rlevel_byte[byte_idx].loop_total,
- rlevel_byte[byte_idx].loop_count);
- }
+ /* Compute the average score across averaging loops */
+ rlevel_scoreboard[rtt_nom][rodt_ctl][rankx].score =
+ divide_nint(rlevel_scoreboard[rtt_nom][rodt_ctl][rankx].score, rlevel_avg_loops);
+
+ /* Compute the average delay results */
+ for (byte_idx=0; byte_idx < 9; ++byte_idx) {
+ if (rlevel_byte[byte_idx].loop_count == 0)
+ rlevel_byte[byte_idx].loop_count = 1;
+ rlevel_byte[byte_idx].delay = divide_nint(rlevel_byte[byte_idx].loop_total,
+ rlevel_byte[byte_idx].loop_count);
+ }
#endif /* PICK_BEST_RANK_SCORE_NOT_AVG */
- lmc_rlevel_rank.u = BDK_CSR_READ(node, BDK_LMCX_RLEVEL_RANKX(ddr_interface_num, rankx));
+ lmc_rlevel_rank.u = BDK_CSR_READ(node, BDK_LMCX_RLEVEL_RANKX(ddr_interface_num, rankx));
- pack_rlevel_settings(ddr_interface_bytemask, ecc_ena, rlevel_byte, &lmc_rlevel_rank);
+ pack_rlevel_settings(ddr_interface_bytemask, ecc_ena, rlevel_byte, &lmc_rlevel_rank);
- if (rlevel_avg_loops > 1) {
+ if (rlevel_avg_loops > 1) {
#if PICK_BEST_RANK_SCORE_NOT_AVG
// restore the "best" bitmasks and their scores for printing
for (byte_idx = 0; byte_idx < 9; ++byte_idx) {
@@ -6518,93 +6518,93 @@ int init_octeon3_ddr3_interface(bdk_node_t node,
WITH_RODT_BESTSCORE);
#else /* PICK_BEST_RANK_SCORE_NOT_AVG */
- display_RL_with_average(node, ddr_interface_num, lmc_rlevel_rank, rankx,
- rlevel_scoreboard[rtt_nom][rodt_ctl][rankx].score);
+ display_RL_with_average(node, ddr_interface_num, lmc_rlevel_rank, rankx,
+ rlevel_scoreboard[rtt_nom][rodt_ctl][rankx].score);
#endif /* PICK_BEST_RANK_SCORE_NOT_AVG */
- } /* if (rlevel_avg_loops > 1) */
+ } /* if (rlevel_avg_loops > 1) */
- rlevel_scoreboard[rtt_nom][rodt_ctl][rankx].setting = lmc_rlevel_rank.u;
+ rlevel_scoreboard[rtt_nom][rodt_ctl][rankx].setting = lmc_rlevel_rank.u;
} /* for (rodt_ctl = max_rodt_ctl; rodt_ctl >= min_rodt_ctl; --rodt_ctl) */
} /* for (rankx = 0; rankx < dimm_count*4; rankx++) */
- } /* for (rtt_idx=min_rtt_nom_idx; rtt_idx<max_rtt_nom_idx; ++rtt_idx) */
-
-
- /* Re-enable dynamic compensation settings. */
- if (rlevel_comp_offset != 0) {
- lmc_comp_ctl2.u = BDK_CSR_READ(node, BDK_LMCX_COMP_CTL2(ddr_interface_num));
-
- lmc_comp_ctl2.s.ptune = 0;
- lmc_comp_ctl2.s.ntune = 0;
- lmc_comp_ctl2.s.byp = 0; /* Disable bypass mode */
- DRAM_CSR_WRITE(node, BDK_LMCX_COMP_CTL2(ddr_interface_num), lmc_comp_ctl2.u);
- BDK_CSR_READ(node, BDK_LMCX_COMP_CTL2(ddr_interface_num)); /* Read once */
-
- lmc_comp_ctl2.u = BDK_CSR_READ(node, BDK_LMCX_COMP_CTL2(ddr_interface_num)); /* Read again */
- ddr_print("DDR__PTUNE/DDR__NTUNE : %d/%d\n",
- lmc_comp_ctl2.s.ddr__ptune, lmc_comp_ctl2.s.ddr__ntune);
-
- lmc_control.u = BDK_CSR_READ(node, BDK_LMCX_CONTROL(ddr_interface_num));
- lmc_control.s.int_zqcs_dis = saved_int_zqcs_dis; /* Restore original setting */
- DRAM_CSR_WRITE(node, BDK_LMCX_CONTROL(ddr_interface_num), lmc_control.u);
-
- }
-
-
- {
- int override_compensation = 0;
- if ((s = lookup_env_parameter("ddr__ptune")) != NULL) {
- saved_ddr__ptune = strtoul(s, NULL, 0);
- override_compensation = 1;
- }
- if ((s = lookup_env_parameter("ddr__ntune")) != NULL) {
- saved_ddr__ntune = strtoul(s, NULL, 0);
- override_compensation = 1;
- }
- if (override_compensation) {
- lmc_comp_ctl2.s.ptune = saved_ddr__ptune;
- lmc_comp_ctl2.s.ntune = saved_ddr__ntune;
-
- lmc_control.u = BDK_CSR_READ(node, BDK_LMCX_CONTROL(ddr_interface_num));
- saved_int_zqcs_dis = lmc_control.s.int_zqcs_dis;
- lmc_control.s.int_zqcs_dis = 1; /* Disable ZQCS while in bypass. */
- DRAM_CSR_WRITE(node, BDK_LMCX_CONTROL(ddr_interface_num), lmc_control.u);
-
- lmc_comp_ctl2.s.byp = 1; /* Enable bypass mode */
- DRAM_CSR_WRITE(node, BDK_LMCX_COMP_CTL2(ddr_interface_num), lmc_comp_ctl2.u);
- lmc_comp_ctl2.u = BDK_CSR_READ(node, BDK_LMCX_COMP_CTL2(ddr_interface_num)); /* Read again */
-
- ddr_print("DDR__PTUNE/DDR__NTUNE : %d/%d\n",
- lmc_comp_ctl2.s.ptune, lmc_comp_ctl2.s.ntune);
- }
- }
- { /* Evaluation block */
- int best_rodt_score = DEFAULT_BEST_RANK_SCORE; /* Start with an arbitrarily high score */
- int auto_rodt_ctl = 0;
- int auto_rtt_nom = 0;
- int rodt_score;
- int rodt_row_skip_mask = 0;
-
- // just add specific RODT rows to the skip mask for DDR4 at this time...
- if (ddr_type == DDR4_DRAM) {
- rodt_row_skip_mask |= (1 << ddr4_rodt_ctl_34_ohm); // skip RODT row 34 ohms for all DDR4 types
- rodt_row_skip_mask |= (1 << ddr4_rodt_ctl_40_ohm); // skip RODT row 40 ohms for all DDR4 types
+ } /* for (rtt_idx=min_rtt_nom_idx; rtt_idx<max_rtt_nom_idx; ++rtt_idx) */
+
+
+ /* Re-enable dynamic compensation settings. */
+ if (rlevel_comp_offset != 0) {
+ lmc_comp_ctl2.u = BDK_CSR_READ(node, BDK_LMCX_COMP_CTL2(ddr_interface_num));
+
+ lmc_comp_ctl2.s.ptune = 0;
+ lmc_comp_ctl2.s.ntune = 0;
+ lmc_comp_ctl2.s.byp = 0; /* Disable bypass mode */
+ DRAM_CSR_WRITE(node, BDK_LMCX_COMP_CTL2(ddr_interface_num), lmc_comp_ctl2.u);
+ BDK_CSR_READ(node, BDK_LMCX_COMP_CTL2(ddr_interface_num)); /* Read once */
+
+ lmc_comp_ctl2.u = BDK_CSR_READ(node, BDK_LMCX_COMP_CTL2(ddr_interface_num)); /* Read again */
+ ddr_print("DDR__PTUNE/DDR__NTUNE : %d/%d\n",
+ lmc_comp_ctl2.s.ddr__ptune, lmc_comp_ctl2.s.ddr__ntune);
+
+ lmc_control.u = BDK_CSR_READ(node, BDK_LMCX_CONTROL(ddr_interface_num));
+ lmc_control.s.int_zqcs_dis = saved_int_zqcs_dis; /* Restore original setting */
+ DRAM_CSR_WRITE(node, BDK_LMCX_CONTROL(ddr_interface_num), lmc_control.u);
+
+ }
+
+
+ {
+ int override_compensation = 0;
+ if ((s = lookup_env_parameter("ddr__ptune")) != NULL) {
+ saved_ddr__ptune = strtoul(s, NULL, 0);
+ override_compensation = 1;
+ }
+ if ((s = lookup_env_parameter("ddr__ntune")) != NULL) {
+ saved_ddr__ntune = strtoul(s, NULL, 0);
+ override_compensation = 1;
+ }
+ if (override_compensation) {
+ lmc_comp_ctl2.s.ptune = saved_ddr__ptune;
+ lmc_comp_ctl2.s.ntune = saved_ddr__ntune;
+
+ lmc_control.u = BDK_CSR_READ(node, BDK_LMCX_CONTROL(ddr_interface_num));
+ saved_int_zqcs_dis = lmc_control.s.int_zqcs_dis;
+ lmc_control.s.int_zqcs_dis = 1; /* Disable ZQCS while in bypass. */
+ DRAM_CSR_WRITE(node, BDK_LMCX_CONTROL(ddr_interface_num), lmc_control.u);
+
+ lmc_comp_ctl2.s.byp = 1; /* Enable bypass mode */
+ DRAM_CSR_WRITE(node, BDK_LMCX_COMP_CTL2(ddr_interface_num), lmc_comp_ctl2.u);
+ lmc_comp_ctl2.u = BDK_CSR_READ(node, BDK_LMCX_COMP_CTL2(ddr_interface_num)); /* Read again */
+
+ ddr_print("DDR__PTUNE/DDR__NTUNE : %d/%d\n",
+ lmc_comp_ctl2.s.ptune, lmc_comp_ctl2.s.ntune);
+ }
+ }
+ { /* Evaluation block */
+ int best_rodt_score = DEFAULT_BEST_RANK_SCORE; /* Start with an arbitrarily high score */
+ int auto_rodt_ctl = 0;
+ int auto_rtt_nom = 0;
+ int rodt_score;
+ int rodt_row_skip_mask = 0;
+
+ // just add specific RODT rows to the skip mask for DDR4 at this time...
+ if (ddr_type == DDR4_DRAM) {
+ rodt_row_skip_mask |= (1 << ddr4_rodt_ctl_34_ohm); // skip RODT row 34 ohms for all DDR4 types
+ rodt_row_skip_mask |= (1 << ddr4_rodt_ctl_40_ohm); // skip RODT row 40 ohms for all DDR4 types
#if ADD_48_OHM_SKIP
- rodt_row_skip_mask |= (1 << ddr4_rodt_ctl_48_ohm); // skip RODT row 48 ohms for all DDR4 types
+ rodt_row_skip_mask |= (1 << ddr4_rodt_ctl_48_ohm); // skip RODT row 48 ohms for all DDR4 types
#endif /* ADD_48OHM_SKIP */
#if NOSKIP_40_48_OHM
- // For now, do not skip RODT row 40 or 48 ohm when ddr_hertz is above 1075 MHz
- if (ddr_hertz > 1075000000) {
- rodt_row_skip_mask &= ~(1 << ddr4_rodt_ctl_40_ohm); // noskip RODT row 40 ohms
- rodt_row_skip_mask &= ~(1 << ddr4_rodt_ctl_48_ohm); // noskip RODT row 48 ohms
- }
+ // For now, do not skip RODT row 40 or 48 ohm when ddr_hertz is above 1075 MHz
+ if (ddr_hertz > 1075000000) {
+ rodt_row_skip_mask &= ~(1 << ddr4_rodt_ctl_40_ohm); // noskip RODT row 40 ohms
+ rodt_row_skip_mask &= ~(1 << ddr4_rodt_ctl_48_ohm); // noskip RODT row 48 ohms
+ }
#endif /* NOSKIP_40_48_OHM */
#if NOSKIP_48_STACKED
- // For now, do not skip RODT row 48 ohm for 2Rx4 stacked die DIMMs
- if ((is_stacked_die) && (num_ranks == 2) && (dram_width == 4)) {
- rodt_row_skip_mask &= ~(1 << ddr4_rodt_ctl_48_ohm); // noskip RODT row 48 ohms
- }
+ // For now, do not skip RODT row 48 ohm for 2Rx4 stacked die DIMMs
+ if ((is_stacked_die) && (num_ranks == 2) && (dram_width == 4)) {
+ rodt_row_skip_mask &= ~(1 << ddr4_rodt_ctl_48_ohm); // noskip RODT row 48 ohms
+ }
#endif /* NOSKIP_48_STACKED */
#if NOSKIP_FOR_MINI
// for now, leave all rows eligible when we have mini-DIMMs...
@@ -6618,65 +6618,65 @@ int init_octeon3_ddr3_interface(bdk_node_t node,
rodt_row_skip_mask = 0;
}
#endif /* NOSKIP_FOR_2S_1R */
- }
-
- VB_PRT(VBL_DEV, "Evaluating Read-Leveling Scoreboard for AUTO settings.\n");
- for (rtt_idx=min_rtt_nom_idx; rtt_idx<=max_rtt_nom_idx; ++rtt_idx) {
- rtt_nom = imp_values->rtt_nom_table[rtt_idx];
-
- /* When the read ODT mask is zero the dyn_rtt_nom_mask is
- zero than RTT_NOM will not be changing during
- read-leveling. Since the value is fixed we only need
- to test it once. */
- if ((dyn_rtt_nom_mask == 0) && (rtt_idx != min_rtt_nom_idx))
- continue;
-
- for (rodt_ctl=max_rodt_ctl; rodt_ctl>=min_rodt_ctl; --rodt_ctl) {
- rodt_score = 0;
- for (rankx = 0; rankx < dimm_count * 4;rankx++) {
- if (!(rank_mask & (1 << rankx)))
- continue;
- debug_print("rlevel_scoreboard[rtt_nom=%d][rodt_ctl=%d][rankx=%d].score:%d\n",
- rtt_nom, rodt_ctl, rankx, rlevel_scoreboard[rtt_nom][rodt_ctl][rankx].score);
- rodt_score += rlevel_scoreboard[rtt_nom][rodt_ctl][rankx].score;
- }
- // FIXME: do we need to skip RODT rows here, like we do below in the by-RANK settings?
-
- /* When using automatic ODT settings use the ODT
- settings associated with the best score for
- all of the tested ODT combinations. */
-
- if ((rodt_score < best_rodt_score) || // always take lower score, OR
- ((rodt_score == best_rodt_score) && // take same score if RODT ohms are higher
- (imp_values->rodt_ohms[rodt_ctl] > imp_values->rodt_ohms[auto_rodt_ctl])))
- {
- debug_print("AUTO: new best score for rodt:%d (%3d), new score:%d, previous score:%d\n",
- rodt_ctl, imp_values->rodt_ohms[rodt_ctl], rodt_score, best_rodt_score);
- best_rodt_score = rodt_score;
- auto_rodt_ctl = rodt_ctl;
- auto_rtt_nom = rtt_nom;
- }
- } /* for (rodt_ctl=max_rodt_ctl; rodt_ctl>=min_rodt_ctl; --rodt_ctl) */
- } /* for (rtt_idx=min_rtt_nom_idx; rtt_idx<=max_rtt_nom_idx; ++rtt_idx) */
-
- lmc_modereg_params1.u = BDK_CSR_READ(node, BDK_LMCX_MODEREG_PARAMS1(ddr_interface_num));
-
- if (ddr_rtt_nom_auto) {
- /* Store the automatically set RTT_NOM value */
- if (dyn_rtt_nom_mask & 1) lmc_modereg_params1.s.rtt_nom_00 = auto_rtt_nom;
- if (dyn_rtt_nom_mask & 2) lmc_modereg_params1.s.rtt_nom_01 = auto_rtt_nom;
- if (dyn_rtt_nom_mask & 4) lmc_modereg_params1.s.rtt_nom_10 = auto_rtt_nom;
- if (dyn_rtt_nom_mask & 8) lmc_modereg_params1.s.rtt_nom_11 = auto_rtt_nom;
- } else {
- /* restore the manual settings to the register */
- lmc_modereg_params1.s.rtt_nom_00 = default_rtt_nom[0];
- lmc_modereg_params1.s.rtt_nom_01 = default_rtt_nom[1];
- lmc_modereg_params1.s.rtt_nom_10 = default_rtt_nom[2];
- lmc_modereg_params1.s.rtt_nom_11 = default_rtt_nom[3];
- }
-
- DRAM_CSR_WRITE(node, BDK_LMCX_MODEREG_PARAMS1(ddr_interface_num), lmc_modereg_params1.u);
- VB_PRT(VBL_DEV, "RTT_NOM %3d, %3d, %3d, %3d ohms : %x,%x,%x,%x\n",
+ }
+
+ VB_PRT(VBL_DEV, "Evaluating Read-Leveling Scoreboard for AUTO settings.\n");
+ for (rtt_idx=min_rtt_nom_idx; rtt_idx<=max_rtt_nom_idx; ++rtt_idx) {
+ rtt_nom = imp_values->rtt_nom_table[rtt_idx];
+
+ /* When the read ODT mask is zero the dyn_rtt_nom_mask is
+ zero than RTT_NOM will not be changing during
+ read-leveling. Since the value is fixed we only need
+ to test it once. */
+ if ((dyn_rtt_nom_mask == 0) && (rtt_idx != min_rtt_nom_idx))
+ continue;
+
+ for (rodt_ctl=max_rodt_ctl; rodt_ctl>=min_rodt_ctl; --rodt_ctl) {
+ rodt_score = 0;
+ for (rankx = 0; rankx < dimm_count * 4;rankx++) {
+ if (!(rank_mask & (1 << rankx)))
+ continue;
+ debug_print("rlevel_scoreboard[rtt_nom=%d][rodt_ctl=%d][rankx=%d].score:%d\n",
+ rtt_nom, rodt_ctl, rankx, rlevel_scoreboard[rtt_nom][rodt_ctl][rankx].score);
+ rodt_score += rlevel_scoreboard[rtt_nom][rodt_ctl][rankx].score;
+ }
+ // FIXME: do we need to skip RODT rows here, like we do below in the by-RANK settings?
+
+ /* When using automatic ODT settings use the ODT
+ settings associated with the best score for
+ all of the tested ODT combinations. */
+
+ if ((rodt_score < best_rodt_score) || // always take lower score, OR
+ ((rodt_score == best_rodt_score) && // take same score if RODT ohms are higher
+ (imp_values->rodt_ohms[rodt_ctl] > imp_values->rodt_ohms[auto_rodt_ctl])))
+ {
+ debug_print("AUTO: new best score for rodt:%d (%3d), new score:%d, previous score:%d\n",
+ rodt_ctl, imp_values->rodt_ohms[rodt_ctl], rodt_score, best_rodt_score);
+ best_rodt_score = rodt_score;
+ auto_rodt_ctl = rodt_ctl;
+ auto_rtt_nom = rtt_nom;
+ }
+ } /* for (rodt_ctl=max_rodt_ctl; rodt_ctl>=min_rodt_ctl; --rodt_ctl) */
+ } /* for (rtt_idx=min_rtt_nom_idx; rtt_idx<=max_rtt_nom_idx; ++rtt_idx) */
+
+ lmc_modereg_params1.u = BDK_CSR_READ(node, BDK_LMCX_MODEREG_PARAMS1(ddr_interface_num));
+
+ if (ddr_rtt_nom_auto) {
+ /* Store the automatically set RTT_NOM value */
+ if (dyn_rtt_nom_mask & 1) lmc_modereg_params1.s.rtt_nom_00 = auto_rtt_nom;
+ if (dyn_rtt_nom_mask & 2) lmc_modereg_params1.s.rtt_nom_01 = auto_rtt_nom;
+ if (dyn_rtt_nom_mask & 4) lmc_modereg_params1.s.rtt_nom_10 = auto_rtt_nom;
+ if (dyn_rtt_nom_mask & 8) lmc_modereg_params1.s.rtt_nom_11 = auto_rtt_nom;
+ } else {
+ /* restore the manual settings to the register */
+ lmc_modereg_params1.s.rtt_nom_00 = default_rtt_nom[0];
+ lmc_modereg_params1.s.rtt_nom_01 = default_rtt_nom[1];
+ lmc_modereg_params1.s.rtt_nom_10 = default_rtt_nom[2];
+ lmc_modereg_params1.s.rtt_nom_11 = default_rtt_nom[3];
+ }
+
+ DRAM_CSR_WRITE(node, BDK_LMCX_MODEREG_PARAMS1(ddr_interface_num), lmc_modereg_params1.u);
+ VB_PRT(VBL_DEV, "RTT_NOM %3d, %3d, %3d, %3d ohms : %x,%x,%x,%x\n",
imp_values->rtt_nom_ohms[lmc_modereg_params1.s.rtt_nom_11],
imp_values->rtt_nom_ohms[lmc_modereg_params1.s.rtt_nom_10],
imp_values->rtt_nom_ohms[lmc_modereg_params1.s.rtt_nom_01],
@@ -6686,7 +6686,7 @@ int init_octeon3_ddr3_interface(bdk_node_t node,
lmc_modereg_params1.s.rtt_nom_01,
lmc_modereg_params1.s.rtt_nom_00);
- VB_PRT(VBL_DEV, "RTT_WR %3d, %3d, %3d, %3d ohms : %x,%x,%x,%x\n",
+ VB_PRT(VBL_DEV, "RTT_WR %3d, %3d, %3d, %3d ohms : %x,%x,%x,%x\n",
imp_values->rtt_wr_ohms[EXTR_WR(lmc_modereg_params1.u, 3)],
imp_values->rtt_wr_ohms[EXTR_WR(lmc_modereg_params1.u, 2)],
imp_values->rtt_wr_ohms[EXTR_WR(lmc_modereg_params1.u, 1)],
@@ -6696,7 +6696,7 @@ int init_octeon3_ddr3_interface(bdk_node_t node,
EXTR_WR(lmc_modereg_params1.u, 1),
EXTR_WR(lmc_modereg_params1.u, 0));
- VB_PRT(VBL_DEV, "DIC %3d, %3d, %3d, %3d ohms : %x,%x,%x,%x\n",
+ VB_PRT(VBL_DEV, "DIC %3d, %3d, %3d, %3d ohms : %x,%x,%x,%x\n",
imp_values->dic_ohms[lmc_modereg_params1.s.dic_11],
imp_values->dic_ohms[lmc_modereg_params1.s.dic_10],
imp_values->dic_ohms[lmc_modereg_params1.s.dic_01],
@@ -6706,167 +6706,167 @@ int init_octeon3_ddr3_interface(bdk_node_t node,
lmc_modereg_params1.s.dic_01,
lmc_modereg_params1.s.dic_00);
- if (ddr_type == DDR4_DRAM) {
- bdk_lmcx_modereg_params2_t lmc_modereg_params2;
- /*
- * We must read the CSR, and not depend on odt_config[odt_idx].odt_mask2,
- * since we could have overridden values with envvars.
- * NOTE: this corrects the printout, since the CSR is not written with the old values...
- */
- lmc_modereg_params2.u = BDK_CSR_READ(node, BDK_LMCX_MODEREG_PARAMS2(ddr_interface_num));
-
- VB_PRT(VBL_DEV, "RTT_PARK %3d, %3d, %3d, %3d ohms : %x,%x,%x,%x\n",
- imp_values->rtt_nom_ohms[lmc_modereg_params2.s.rtt_park_11],
- imp_values->rtt_nom_ohms[lmc_modereg_params2.s.rtt_park_10],
- imp_values->rtt_nom_ohms[lmc_modereg_params2.s.rtt_park_01],
- imp_values->rtt_nom_ohms[lmc_modereg_params2.s.rtt_park_00],
- lmc_modereg_params2.s.rtt_park_11,
- lmc_modereg_params2.s.rtt_park_10,
- lmc_modereg_params2.s.rtt_park_01,
- lmc_modereg_params2.s.rtt_park_00);
-
- VB_PRT(VBL_DEV, "%-45s : 0x%x,0x%x,0x%x,0x%x\n", "VREF_RANGE",
- lmc_modereg_params2.s.vref_range_11,
- lmc_modereg_params2.s.vref_range_10,
- lmc_modereg_params2.s.vref_range_01,
- lmc_modereg_params2.s.vref_range_00);
-
- VB_PRT(VBL_DEV, "%-45s : 0x%x,0x%x,0x%x,0x%x\n", "VREF_VALUE",
- lmc_modereg_params2.s.vref_value_11,
- lmc_modereg_params2.s.vref_value_10,
- lmc_modereg_params2.s.vref_value_01,
- lmc_modereg_params2.s.vref_value_00);
- }
-
- lmc_comp_ctl2.u = BDK_CSR_READ(node, BDK_LMCX_COMP_CTL2(ddr_interface_num));
- if (ddr_rodt_ctl_auto)
- lmc_comp_ctl2.s.rodt_ctl = auto_rodt_ctl;
- else
- lmc_comp_ctl2.s.rodt_ctl = default_rodt_ctl; // back to the original setting
- DRAM_CSR_WRITE(node, BDK_LMCX_COMP_CTL2(ddr_interface_num), lmc_comp_ctl2.u);
- lmc_comp_ctl2.u = BDK_CSR_READ(node, BDK_LMCX_COMP_CTL2(ddr_interface_num));
- VB_PRT(VBL_DEV, "Read ODT_CTL : 0x%x (%d ohms)\n",
- lmc_comp_ctl2.s.rodt_ctl, imp_values->rodt_ohms[lmc_comp_ctl2.s.rodt_ctl]);
-
- ////////////////// this is the start of the RANK MAJOR LOOP
-
- for (rankx = 0; rankx < dimm_count * 4; rankx++) {
- int best_rank_score = DEFAULT_BEST_RANK_SCORE; /* Start with an arbitrarily high score */
- int best_rank_rtt_nom = 0;
- //int best_rank_nom_ohms = 0;
- int best_rank_ctl = 0;
- int best_rank_ohms = 0;
- int best_rankx = 0;
-
- if (!(rank_mask & (1 << rankx)))
- continue;
+ if (ddr_type == DDR4_DRAM) {
+ bdk_lmcx_modereg_params2_t lmc_modereg_params2;
+ /*
+ * We must read the CSR, and not depend on odt_config[odt_idx].odt_mask2,
+ * since we could have overridden values with envvars.
+ * NOTE: this corrects the printout, since the CSR is not written with the old values...
+ */
+ lmc_modereg_params2.u = BDK_CSR_READ(node, BDK_LMCX_MODEREG_PARAMS2(ddr_interface_num));
+
+ VB_PRT(VBL_DEV, "RTT_PARK %3d, %3d, %3d, %3d ohms : %x,%x,%x,%x\n",
+ imp_values->rtt_nom_ohms[lmc_modereg_params2.s.rtt_park_11],
+ imp_values->rtt_nom_ohms[lmc_modereg_params2.s.rtt_park_10],
+ imp_values->rtt_nom_ohms[lmc_modereg_params2.s.rtt_park_01],
+ imp_values->rtt_nom_ohms[lmc_modereg_params2.s.rtt_park_00],
+ lmc_modereg_params2.s.rtt_park_11,
+ lmc_modereg_params2.s.rtt_park_10,
+ lmc_modereg_params2.s.rtt_park_01,
+ lmc_modereg_params2.s.rtt_park_00);
+
+ VB_PRT(VBL_DEV, "%-45s : 0x%x,0x%x,0x%x,0x%x\n", "VREF_RANGE",
+ lmc_modereg_params2.s.vref_range_11,
+ lmc_modereg_params2.s.vref_range_10,
+ lmc_modereg_params2.s.vref_range_01,
+ lmc_modereg_params2.s.vref_range_00);
+
+ VB_PRT(VBL_DEV, "%-45s : 0x%x,0x%x,0x%x,0x%x\n", "VREF_VALUE",
+ lmc_modereg_params2.s.vref_value_11,
+ lmc_modereg_params2.s.vref_value_10,
+ lmc_modereg_params2.s.vref_value_01,
+ lmc_modereg_params2.s.vref_value_00);
+ }
+
+ lmc_comp_ctl2.u = BDK_CSR_READ(node, BDK_LMCX_COMP_CTL2(ddr_interface_num));
+ if (ddr_rodt_ctl_auto)
+ lmc_comp_ctl2.s.rodt_ctl = auto_rodt_ctl;
+ else
+ lmc_comp_ctl2.s.rodt_ctl = default_rodt_ctl; // back to the original setting
+ DRAM_CSR_WRITE(node, BDK_LMCX_COMP_CTL2(ddr_interface_num), lmc_comp_ctl2.u);
+ lmc_comp_ctl2.u = BDK_CSR_READ(node, BDK_LMCX_COMP_CTL2(ddr_interface_num));
+ VB_PRT(VBL_DEV, "Read ODT_CTL : 0x%x (%d ohms)\n",
+ lmc_comp_ctl2.s.rodt_ctl, imp_values->rodt_ohms[lmc_comp_ctl2.s.rodt_ctl]);
+
+ ////////////////// this is the start of the RANK MAJOR LOOP
+
+ for (rankx = 0; rankx < dimm_count * 4; rankx++) {
+ int best_rank_score = DEFAULT_BEST_RANK_SCORE; /* Start with an arbitrarily high score */
+ int best_rank_rtt_nom = 0;
+ //int best_rank_nom_ohms = 0;
+ int best_rank_ctl = 0;
+ int best_rank_ohms = 0;
+ int best_rankx = 0;
+
+ if (!(rank_mask & (1 << rankx)))
+ continue;
/* Use the delays associated with the best score for each individual rank */
VB_PRT(VBL_TME, "Evaluating Read-Leveling Scoreboard for Rank %d settings.\n", rankx);
- // some of the rank-related loops below need to operate only on the ranks of a single DIMM,
- // so create a mask for their use here
- int dimm_rank_mask;
- if (num_ranks == 4)
- dimm_rank_mask = rank_mask; // should be 1111
- else {
- dimm_rank_mask = rank_mask & 3; // should be 01 or 11
- if (rankx >= 2)
- dimm_rank_mask <<= 2; // doing a rank on the second DIMM, should be 0100 or 1100
- }
- debug_print("DIMM rank mask: 0x%x, rank mask: 0x%x, rankx: %d\n", dimm_rank_mask, rank_mask, rankx);
-
- ////////////////// this is the start of the BEST ROW SCORE LOOP
-
- for (rtt_idx = min_rtt_nom_idx; rtt_idx <= max_rtt_nom_idx; ++rtt_idx) {
- //int rtt_nom_ohms;
- rtt_nom = imp_values->rtt_nom_table[rtt_idx];
- //rtt_nom_ohms = imp_values->rtt_nom_ohms[rtt_nom];
-
- /* When the read ODT mask is zero the dyn_rtt_nom_mask is
- zero than RTT_NOM will not be changing during
- read-leveling. Since the value is fixed we only need
- to test it once. */
- if ((dyn_rtt_nom_mask == 0) && (rtt_idx != min_rtt_nom_idx))
- continue;
-
- debug_print("N%d.LMC%d.R%d: starting RTT_NOM %d (%d)\n",
- node, ddr_interface_num, rankx, rtt_nom, rtt_nom_ohms);
-
- for (rodt_ctl = max_rodt_ctl; rodt_ctl >= min_rodt_ctl; --rodt_ctl) {
- int next_ohms = imp_values->rodt_ohms[rodt_ctl];
-
- // skip RODT rows in mask, but *NOT* rows with too high a score;
- // we will not use the skipped ones for printing or evaluating, but
- // we need to allow all the non-skipped ones to be candidates for "best"
- if (((1 << rodt_ctl) & rodt_row_skip_mask) != 0) {
- debug_print("N%d.LMC%d.R%d: SKIPPING rodt:%d (%d) with rank_score:%d\n",
- node, ddr_interface_num, rankx, rodt_ctl, next_ohms, next_score);
- continue;
- }
- for (int orankx = 0; orankx < dimm_count * 4; orankx++) { // this is ROFFIX-0528
- if (!(dimm_rank_mask & (1 << orankx))) // stay on the same DIMM
- continue;
-
- int next_score = rlevel_scoreboard[rtt_nom][rodt_ctl][orankx].score;
-
- if (next_score > best_rank_score) // always skip a higher score
- continue;
- if (next_score == best_rank_score) { // if scores are equal
- if (next_ohms < best_rank_ohms) // always skip lower ohms
- continue;
- if (next_ohms == best_rank_ohms) { // if same ohms
- if (orankx != rankx) // always skip the other rank(s)
- continue;
- }
- // else next_ohms are greater, always choose it
- }
- // else next_score is less than current best, so always choose it
- VB_PRT(VBL_DEV2, "N%d.LMC%d.R%d: new best score: rank %d, rodt %d(%3d), new best %d, previous best %d(%d)\n",
+ // some of the rank-related loops below need to operate only on the ranks of a single DIMM,
+ // so create a mask for their use here
+ int dimm_rank_mask;
+ if (num_ranks == 4)
+ dimm_rank_mask = rank_mask; // should be 1111
+ else {
+ dimm_rank_mask = rank_mask & 3; // should be 01 or 11
+ if (rankx >= 2)
+ dimm_rank_mask <<= 2; // doing a rank on the second DIMM, should be 0100 or 1100
+ }
+ debug_print("DIMM rank mask: 0x%x, rank mask: 0x%x, rankx: %d\n", dimm_rank_mask, rank_mask, rankx);
+
+ ////////////////// this is the start of the BEST ROW SCORE LOOP
+
+ for (rtt_idx = min_rtt_nom_idx; rtt_idx <= max_rtt_nom_idx; ++rtt_idx) {
+ //int rtt_nom_ohms;
+ rtt_nom = imp_values->rtt_nom_table[rtt_idx];
+ //rtt_nom_ohms = imp_values->rtt_nom_ohms[rtt_nom];
+
+ /* When the read ODT mask is zero the dyn_rtt_nom_mask is
+ zero than RTT_NOM will not be changing during
+ read-leveling. Since the value is fixed we only need
+ to test it once. */
+ if ((dyn_rtt_nom_mask == 0) && (rtt_idx != min_rtt_nom_idx))
+ continue;
+
+ debug_print("N%d.LMC%d.R%d: starting RTT_NOM %d (%d)\n",
+ node, ddr_interface_num, rankx, rtt_nom, rtt_nom_ohms);
+
+ for (rodt_ctl = max_rodt_ctl; rodt_ctl >= min_rodt_ctl; --rodt_ctl) {
+ int next_ohms = imp_values->rodt_ohms[rodt_ctl];
+
+ // skip RODT rows in mask, but *NOT* rows with too high a score;
+ // we will not use the skipped ones for printing or evaluating, but
+ // we need to allow all the non-skipped ones to be candidates for "best"
+ if (((1 << rodt_ctl) & rodt_row_skip_mask) != 0) {
+ debug_print("N%d.LMC%d.R%d: SKIPPING rodt:%d (%d) with rank_score:%d\n",
+ node, ddr_interface_num, rankx, rodt_ctl, next_ohms, next_score);
+ continue;
+ }
+ for (int orankx = 0; orankx < dimm_count * 4; orankx++) { // this is ROFFIX-0528
+ if (!(dimm_rank_mask & (1 << orankx))) // stay on the same DIMM
+ continue;
+
+ int next_score = rlevel_scoreboard[rtt_nom][rodt_ctl][orankx].score;
+
+ if (next_score > best_rank_score) // always skip a higher score
+ continue;
+ if (next_score == best_rank_score) { // if scores are equal
+ if (next_ohms < best_rank_ohms) // always skip lower ohms
+ continue;
+ if (next_ohms == best_rank_ohms) { // if same ohms
+ if (orankx != rankx) // always skip the other rank(s)
+ continue;
+ }
+ // else next_ohms are greater, always choose it
+ }
+ // else next_score is less than current best, so always choose it
+ VB_PRT(VBL_DEV2, "N%d.LMC%d.R%d: new best score: rank %d, rodt %d(%3d), new best %d, previous best %d(%d)\n",
node, ddr_interface_num, rankx, orankx, rodt_ctl, next_ohms, next_score,
best_rank_score, best_rank_ohms);
- best_rank_score = next_score;
- best_rank_rtt_nom = rtt_nom;
- //best_rank_nom_ohms = rtt_nom_ohms;
- best_rank_ctl = rodt_ctl;
- best_rank_ohms = next_ohms;
- best_rankx = orankx;
- lmc_rlevel_rank.u = rlevel_scoreboard[rtt_nom][rodt_ctl][orankx].setting;
+ best_rank_score = next_score;
+ best_rank_rtt_nom = rtt_nom;
+ //best_rank_nom_ohms = rtt_nom_ohms;
+ best_rank_ctl = rodt_ctl;
+ best_rank_ohms = next_ohms;
+ best_rankx = orankx;
+ lmc_rlevel_rank.u = rlevel_scoreboard[rtt_nom][rodt_ctl][orankx].setting;
- } /* for (int orankx = 0; orankx < dimm_count * 4; orankx++) */
- } /* for (rodt_ctl = max_rodt_ctl; rodt_ctl >= min_rodt_ctl; --rodt_ctl) */
- } /* for (rtt_idx = min_rtt_nom_idx; rtt_idx <= max_rtt_nom_idx; ++rtt_idx) */
-
- ////////////////// this is the end of the BEST ROW SCORE LOOP
-
- // DANGER, Will Robinson!! Abort now if we did not find a best score at all...
- if (best_rank_score == DEFAULT_BEST_RANK_SCORE) {
- error_print("WARNING: no best rank score found for N%d.LMC%d.R%d - resetting node...\n",
- node, ddr_interface_num, rankx);
- bdk_wait_usec(500000);
- bdk_reset_chip(node);
- }
+ } /* for (int orankx = 0; orankx < dimm_count * 4; orankx++) */
+ } /* for (rodt_ctl = max_rodt_ctl; rodt_ctl >= min_rodt_ctl; --rodt_ctl) */
+ } /* for (rtt_idx = min_rtt_nom_idx; rtt_idx <= max_rtt_nom_idx; ++rtt_idx) */
+
+ ////////////////// this is the end of the BEST ROW SCORE LOOP
+
+ // DANGER, Will Robinson!! Abort now if we did not find a best score at all...
+ if (best_rank_score == DEFAULT_BEST_RANK_SCORE) {
+ error_print("WARNING: no best rank score found for N%d.LMC%d.R%d - resetting node...\n",
+ node, ddr_interface_num, rankx);
+ bdk_wait_usec(500000);
+ bdk_reset_chip(node);
+ }
// FIXME: relative now, but still arbitrary...
// halve the range if 2 DIMMs unless they are single rank...
- int MAX_RANK_SCORE = best_rank_score;
+ int MAX_RANK_SCORE = best_rank_score;
MAX_RANK_SCORE += (MAX_RANK_SCORE_LIMIT / ((num_ranks > 1) ? dimm_count : 1));
- if (!ecc_ena){
- lmc_rlevel_rank.cn83xx.byte8 = lmc_rlevel_rank.cn83xx.byte0; /* ECC is not used */
- }
+ if (!ecc_ena){
+ lmc_rlevel_rank.cn83xx.byte8 = lmc_rlevel_rank.cn83xx.byte0; /* ECC is not used */
+ }
- // at the end, write the best row settings to the current rank
- DRAM_CSR_WRITE(node, BDK_LMCX_RLEVEL_RANKX(ddr_interface_num, rankx), lmc_rlevel_rank.u);
- lmc_rlevel_rank.u = BDK_CSR_READ(node, BDK_LMCX_RLEVEL_RANKX(ddr_interface_num, rankx));
+ // at the end, write the best row settings to the current rank
+ DRAM_CSR_WRITE(node, BDK_LMCX_RLEVEL_RANKX(ddr_interface_num, rankx), lmc_rlevel_rank.u);
+ lmc_rlevel_rank.u = BDK_CSR_READ(node, BDK_LMCX_RLEVEL_RANKX(ddr_interface_num, rankx));
- bdk_lmcx_rlevel_rankx_t saved_rlevel_rank;
- saved_rlevel_rank.u = lmc_rlevel_rank.u;
+ bdk_lmcx_rlevel_rankx_t saved_rlevel_rank;
+ saved_rlevel_rank.u = lmc_rlevel_rank.u;
- ////////////////// this is the start of the PRINT LOOP
+ ////////////////// this is the start of the PRINT LOOP
- // for pass==0, print current rank, pass==1 print other rank(s)
- // this is done because we want to show each ranks RODT values together, not interlaced
+ // for pass==0, print current rank, pass==1 print other rank(s)
+ // this is done because we want to show each ranks RODT values together, not interlaced
#if COUNT_RL_CANDIDATES
// keep separates for ranks - pass=0 target rank, pass=1 other rank on DIMM
int mask_skipped[2] = {0,0};
@@ -6874,17 +6874,17 @@ int init_octeon3_ddr3_interface(bdk_node_t node,
int selected_rows[2] = {0,0};
int zero_scores[2] = {0,0};
#endif /* COUNT_RL_CANDIDATES */
- for (int pass = 0; pass < 2; pass++ ) {
- for (int orankx = 0; orankx < dimm_count * 4; orankx++) {
- if (!(dimm_rank_mask & (1 << orankx))) // stay on the same DIMM
- continue;
+ for (int pass = 0; pass < 2; pass++ ) {
+ for (int orankx = 0; orankx < dimm_count * 4; orankx++) {
+ if (!(dimm_rank_mask & (1 << orankx))) // stay on the same DIMM
+ continue;
- if (((pass == 0) && (orankx != rankx)) || ((pass != 0) && (orankx == rankx)))
- continue;
+ if (((pass == 0) && (orankx != rankx)) || ((pass != 0) && (orankx == rankx)))
+ continue;
- for (rtt_idx = min_rtt_nom_idx; rtt_idx <= max_rtt_nom_idx; ++rtt_idx) {
- rtt_nom = imp_values->rtt_nom_table[rtt_idx];
- if (dyn_rtt_nom_mask == 0) {
+ for (rtt_idx = min_rtt_nom_idx; rtt_idx <= max_rtt_nom_idx; ++rtt_idx) {
+ rtt_nom = imp_values->rtt_nom_table[rtt_idx];
+ if (dyn_rtt_nom_mask == 0) {
print_nom_ohms = -1;
if (rtt_idx != min_rtt_nom_idx)
continue;
@@ -6892,16 +6892,16 @@ int init_octeon3_ddr3_interface(bdk_node_t node,
print_nom_ohms = imp_values->rtt_nom_ohms[rtt_nom];
}
- // cycle through all the RODT values...
- for (rodt_ctl = max_rodt_ctl; rodt_ctl >= min_rodt_ctl; --rodt_ctl) {
- bdk_lmcx_rlevel_rankx_t temp_rlevel_rank;
- int temp_score = rlevel_scoreboard[rtt_nom][rodt_ctl][orankx].score;
- temp_rlevel_rank.u = rlevel_scoreboard[rtt_nom][rodt_ctl][orankx].setting;
+ // cycle through all the RODT values...
+ for (rodt_ctl = max_rodt_ctl; rodt_ctl >= min_rodt_ctl; --rodt_ctl) {
+ bdk_lmcx_rlevel_rankx_t temp_rlevel_rank;
+ int temp_score = rlevel_scoreboard[rtt_nom][rodt_ctl][orankx].score;
+ temp_rlevel_rank.u = rlevel_scoreboard[rtt_nom][rodt_ctl][orankx].setting;
- // skip RODT rows in mask, or rows with too high a score;
- // we will not use them for printing or evaluating...
+ // skip RODT rows in mask, or rows with too high a score;
+ // we will not use them for printing or evaluating...
#if COUNT_RL_CANDIDATES
- int skip_row;
+ int skip_row;
if ((1 << rodt_ctl) & rodt_row_skip_mask) {
skip_row = WITH_RODT_SKIPPING;
++mask_skipped[pass];
@@ -6914,10 +6914,10 @@ int init_octeon3_ddr3_interface(bdk_node_t node,
if (temp_score == 0)
++zero_scores[pass];
}
-
+
#else /* COUNT_RL_CANDIDATES */
- int skip_row = (((1 << rodt_ctl) & rodt_row_skip_mask) || (temp_score > MAX_RANK_SCORE))
- ? WITH_RODT_SKIPPING: WITH_RODT_BLANK;
+ int skip_row = (((1 << rodt_ctl) & rodt_row_skip_mask) || (temp_score > MAX_RANK_SCORE))
+ ? WITH_RODT_SKIPPING: WITH_RODT_BLANK;
#endif /* COUNT_RL_CANDIDATES */
// identify and print the BEST ROW when it comes up
@@ -6929,16 +6929,16 @@ int init_octeon3_ddr3_interface(bdk_node_t node,
skip_row = WITH_RODT_BESTROW;
}
- display_RL_with_RODT(node, ddr_interface_num,
- temp_rlevel_rank, orankx, temp_score,
- print_nom_ohms,
- imp_values->rodt_ohms[rodt_ctl],
- skip_row);
+ display_RL_with_RODT(node, ddr_interface_num,
+ temp_rlevel_rank, orankx, temp_score,
+ print_nom_ohms,
+ imp_values->rodt_ohms[rodt_ctl],
+ skip_row);
- } /* for (rodt_ctl = max_rodt_ctl; rodt_ctl >= min_rodt_ctl; --rodt_ctl) */
- } /* for (rtt_idx=min_rtt_nom_idx; rtt_idx<=max_rtt_nom_idx; ++rtt_idx) */
- } /* for (int orankx = 0; orankx < dimm_count * 4; orankx++) { */
- } /* for (int pass = 0; pass < 2; pass++ ) */
+ } /* for (rodt_ctl = max_rodt_ctl; rodt_ctl >= min_rodt_ctl; --rodt_ctl) */
+ } /* for (rtt_idx=min_rtt_nom_idx; rtt_idx<=max_rtt_nom_idx; ++rtt_idx) */
+ } /* for (int orankx = 0; orankx < dimm_count * 4; orankx++) { */
+ } /* for (int pass = 0; pass < 2; pass++ ) */
#if COUNT_RL_CANDIDATES
VB_PRT(VBL_TME, "N%d.LMC%d.R%d: RLROWS: selected %d+%d, zero_scores %d+%d, mask_skipped %d+%d, score_skipped %d+%d\n",
node, ddr_interface_num, rankx,
@@ -6948,247 +6948,247 @@ int init_octeon3_ddr3_interface(bdk_node_t node,
score_skipped[0], score_skipped[1]);
#endif /* COUNT_RL_CANDIDATES */
- ////////////////// this is the end of the PRINT LOOP
-
- // now evaluate which bytes need adjusting
- uint64_t byte_msk = 0x3f; // 6-bit fields
- uint64_t best_byte, new_byte, temp_byte, orig_best_byte;
-
- uint64_t rank_best_bytes[9]; // collect the new byte values; first init with current best for neighbor use
- for (int byte_idx = 0, byte_sh = 0; byte_idx < 8+ecc_ena; byte_idx++, byte_sh += 6) {
- rank_best_bytes[byte_idx] = (lmc_rlevel_rank.u >> byte_sh) & byte_msk;
- }
-
- ////////////////// this is the start of the BEST BYTE LOOP
-
- for (int byte_idx = 0, byte_sh = 0; byte_idx < 8+ecc_ena; byte_idx++, byte_sh += 6) {
- best_byte = orig_best_byte = rank_best_bytes[byte_idx];
-
- ////////////////// this is the start of the BEST BYTE AVERAGING LOOP
-
- // validate the initial "best" byte by looking at the average of the unskipped byte-column entries
- // we want to do this before we go further, so we can try to start with a better initial value
- // this is the so-called "BESTBUY" patch set
- int sum = 0, count = 0;
-
- for (rtt_idx = min_rtt_nom_idx; rtt_idx <= max_rtt_nom_idx; ++rtt_idx) {
- rtt_nom = imp_values->rtt_nom_table[rtt_idx];
- if ((dyn_rtt_nom_mask == 0) && (rtt_idx != min_rtt_nom_idx))
- continue;
-
- for (rodt_ctl = max_rodt_ctl; rodt_ctl >= min_rodt_ctl; --rodt_ctl) {
- bdk_lmcx_rlevel_rankx_t temp_rlevel_rank;
- int temp_score;
- for (int orankx = 0; orankx < dimm_count * 4; orankx++) { // average over all the ranks
- if (!(dimm_rank_mask & (1 << orankx))) // stay on the same DIMM
- continue;
- temp_score = rlevel_scoreboard[rtt_nom][rodt_ctl][orankx].score;
- // skip RODT rows in mask, or rows with too high a score;
- // we will not use them for printing or evaluating...
-
- if (!((1 << rodt_ctl) & rodt_row_skip_mask) &&
- (temp_score <= MAX_RANK_SCORE))
- {
- temp_rlevel_rank.u = rlevel_scoreboard[rtt_nom][rodt_ctl][orankx].setting;
- temp_byte = (temp_rlevel_rank.u >> byte_sh) & byte_msk;
- sum += temp_byte;
- count++;
- }
- } /* for (int orankx = 0; orankx < dimm_count * 4; orankx++) */
- } /* for (rodt_ctl = max_rodt_ctl; rodt_ctl >= min_rodt_ctl; --rodt_ctl) */
- } /* for (rtt_idx=min_rtt_nom_idx; rtt_idx<=max_rtt_nom_idx; ++rtt_idx) */
-
- ////////////////// this is the end of the BEST BYTE AVERAGING LOOP
-
-
- uint64_t avg_byte = divide_nint(sum, count); // FIXME: validate count and sum??
- int avg_diff = (int)best_byte - (int)avg_byte;
- new_byte = best_byte;
- if (avg_diff != 0) {
- // bump best up/dn by 1, not necessarily all the way to avg
- new_byte = best_byte + ((avg_diff > 0) ? -1: 1);
- }
-
- VB_PRT(VBL_DEV, "N%d.LMC%d.R%d: START: Byte %d: best %d is different by %d from average %d, using %d.\n",
- node, ddr_interface_num, rankx,
- byte_idx, (int)best_byte, avg_diff, (int)avg_byte, (int)new_byte);
- best_byte = new_byte;
-
- // At this point best_byte is either:
- // 1. the original byte-column value from the best scoring RODT row, OR
- // 2. that value bumped toward the average of all the byte-column values
- //
- // best_byte will not change from here on...
-
- ////////////////// this is the start of the BEST BYTE COUNTING LOOP
-
- // NOTE: we do this next loop separately from above, because we count relative to "best_byte"
- // which may have been modified by the above averaging operation...
+ ////////////////// this is the end of the PRINT LOOP
+
+ // now evaluate which bytes need adjusting
+ uint64_t byte_msk = 0x3f; // 6-bit fields
+ uint64_t best_byte, new_byte, temp_byte, orig_best_byte;
+
+ uint64_t rank_best_bytes[9]; // collect the new byte values; first init with current best for neighbor use
+ for (int byte_idx = 0, byte_sh = 0; byte_idx < 8+ecc_ena; byte_idx++, byte_sh += 6) {
+ rank_best_bytes[byte_idx] = (lmc_rlevel_rank.u >> byte_sh) & byte_msk;
+ }
+
+ ////////////////// this is the start of the BEST BYTE LOOP
+
+ for (int byte_idx = 0, byte_sh = 0; byte_idx < 8+ecc_ena; byte_idx++, byte_sh += 6) {
+ best_byte = orig_best_byte = rank_best_bytes[byte_idx];
+
+ ////////////////// this is the start of the BEST BYTE AVERAGING LOOP
+
+ // validate the initial "best" byte by looking at the average of the unskipped byte-column entries
+ // we want to do this before we go further, so we can try to start with a better initial value
+ // this is the so-called "BESTBUY" patch set
+ int sum = 0, count = 0;
+
+ for (rtt_idx = min_rtt_nom_idx; rtt_idx <= max_rtt_nom_idx; ++rtt_idx) {
+ rtt_nom = imp_values->rtt_nom_table[rtt_idx];
+ if ((dyn_rtt_nom_mask == 0) && (rtt_idx != min_rtt_nom_idx))
+ continue;
+
+ for (rodt_ctl = max_rodt_ctl; rodt_ctl >= min_rodt_ctl; --rodt_ctl) {
+ bdk_lmcx_rlevel_rankx_t temp_rlevel_rank;
+ int temp_score;
+ for (int orankx = 0; orankx < dimm_count * 4; orankx++) { // average over all the ranks
+ if (!(dimm_rank_mask & (1 << orankx))) // stay on the same DIMM
+ continue;
+ temp_score = rlevel_scoreboard[rtt_nom][rodt_ctl][orankx].score;
+ // skip RODT rows in mask, or rows with too high a score;
+ // we will not use them for printing or evaluating...
+
+ if (!((1 << rodt_ctl) & rodt_row_skip_mask) &&
+ (temp_score <= MAX_RANK_SCORE))
+ {
+ temp_rlevel_rank.u = rlevel_scoreboard[rtt_nom][rodt_ctl][orankx].setting;
+ temp_byte = (temp_rlevel_rank.u >> byte_sh) & byte_msk;
+ sum += temp_byte;
+ count++;
+ }
+ } /* for (int orankx = 0; orankx < dimm_count * 4; orankx++) */
+ } /* for (rodt_ctl = max_rodt_ctl; rodt_ctl >= min_rodt_ctl; --rodt_ctl) */
+ } /* for (rtt_idx=min_rtt_nom_idx; rtt_idx<=max_rtt_nom_idx; ++rtt_idx) */
+
+ ////////////////// this is the end of the BEST BYTE AVERAGING LOOP
+
+
+ uint64_t avg_byte = divide_nint(sum, count); // FIXME: validate count and sum??
+ int avg_diff = (int)best_byte - (int)avg_byte;
+ new_byte = best_byte;
+ if (avg_diff != 0) {
+ // bump best up/dn by 1, not necessarily all the way to avg
+ new_byte = best_byte + ((avg_diff > 0) ? -1: 1);
+ }
+
+ VB_PRT(VBL_DEV, "N%d.LMC%d.R%d: START: Byte %d: best %d is different by %d from average %d, using %d.\n",
+ node, ddr_interface_num, rankx,
+ byte_idx, (int)best_byte, avg_diff, (int)avg_byte, (int)new_byte);
+ best_byte = new_byte;
+
+ // At this point best_byte is either:
+ // 1. the original byte-column value from the best scoring RODT row, OR
+ // 2. that value bumped toward the average of all the byte-column values
+ //
+ // best_byte will not change from here on...
+
+ ////////////////// this is the start of the BEST BYTE COUNTING LOOP
+
+ // NOTE: we do this next loop separately from above, because we count relative to "best_byte"
+ // which may have been modified by the above averaging operation...
//
// Also, the above only moves toward the average by +- 1, so that we will always have a count
// of at least 1 for the original best byte, even if all the others are further away and not counted;
// this ensures we will go back to the original if no others are counted...
// FIXME: this could cause issue if the range of values for a byte-lane are too disparate...
- int count_less = 0, count_same = 0, count_more = 0;
+ int count_less = 0, count_same = 0, count_more = 0;
#if FAILSAFE_CHECK
uint64_t count_byte = new_byte; // save the value we will count around
#endif /* FAILSAFE_CHECK */
#if RANK_MAJORITY
- int rank_less = 0, rank_same = 0, rank_more = 0;
+ int rank_less = 0, rank_same = 0, rank_more = 0;
#endif /* RANK_MAJORITY */
- for (rtt_idx = min_rtt_nom_idx; rtt_idx <= max_rtt_nom_idx; ++rtt_idx) {
- rtt_nom = imp_values->rtt_nom_table[rtt_idx];
- if ((dyn_rtt_nom_mask == 0) && (rtt_idx != min_rtt_nom_idx))
- continue;
-
- for (rodt_ctl = max_rodt_ctl; rodt_ctl >= min_rodt_ctl; --rodt_ctl) {
- bdk_lmcx_rlevel_rankx_t temp_rlevel_rank;
- int temp_score;
- for (int orankx = 0; orankx < dimm_count * 4; orankx++) { // count over all the ranks
- if (!(dimm_rank_mask & (1 << orankx))) // stay on the same DIMM
- continue;
- temp_score = rlevel_scoreboard[rtt_nom][rodt_ctl][orankx].score;
- // skip RODT rows in mask, or rows with too high a score;
- // we will not use them for printing or evaluating...
- if (((1 << rodt_ctl) & rodt_row_skip_mask) ||
- (temp_score > MAX_RANK_SCORE))
- {
- continue;
- }
- temp_rlevel_rank.u = rlevel_scoreboard[rtt_nom][rodt_ctl][orankx].setting;
- temp_byte = (temp_rlevel_rank.u >> byte_sh) & byte_msk;
-
- if (temp_byte == 0) // do not count it if illegal
- continue;
- else if (temp_byte == best_byte)
- count_same++;
- else if (temp_byte == best_byte - 1)
- count_less++;
- else if (temp_byte == best_byte + 1)
- count_more++;
- // else do not count anything more than 1 away from the best
+ for (rtt_idx = min_rtt_nom_idx; rtt_idx <= max_rtt_nom_idx; ++rtt_idx) {
+ rtt_nom = imp_values->rtt_nom_table[rtt_idx];
+ if ((dyn_rtt_nom_mask == 0) && (rtt_idx != min_rtt_nom_idx))
+ continue;
+
+ for (rodt_ctl = max_rodt_ctl; rodt_ctl >= min_rodt_ctl; --rodt_ctl) {
+ bdk_lmcx_rlevel_rankx_t temp_rlevel_rank;
+ int temp_score;
+ for (int orankx = 0; orankx < dimm_count * 4; orankx++) { // count over all the ranks
+ if (!(dimm_rank_mask & (1 << orankx))) // stay on the same DIMM
+ continue;
+ temp_score = rlevel_scoreboard[rtt_nom][rodt_ctl][orankx].score;
+ // skip RODT rows in mask, or rows with too high a score;
+ // we will not use them for printing or evaluating...
+ if (((1 << rodt_ctl) & rodt_row_skip_mask) ||
+ (temp_score > MAX_RANK_SCORE))
+ {
+ continue;
+ }
+ temp_rlevel_rank.u = rlevel_scoreboard[rtt_nom][rodt_ctl][orankx].setting;
+ temp_byte = (temp_rlevel_rank.u >> byte_sh) & byte_msk;
+
+ if (temp_byte == 0) // do not count it if illegal
+ continue;
+ else if (temp_byte == best_byte)
+ count_same++;
+ else if (temp_byte == best_byte - 1)
+ count_less++;
+ else if (temp_byte == best_byte + 1)
+ count_more++;
+ // else do not count anything more than 1 away from the best
#if RANK_MAJORITY
- // FIXME? count is relative to best_byte; should it be rank-based?
- if (orankx != rankx) // rank counts only on main rank
- continue;
- else if (temp_byte == best_byte)
- rank_same++;
- else if (temp_byte == best_byte - 1)
- rank_less++;
- else if (temp_byte == best_byte + 1)
- rank_more++;
+ // FIXME? count is relative to best_byte; should it be rank-based?
+ if (orankx != rankx) // rank counts only on main rank
+ continue;
+ else if (temp_byte == best_byte)
+ rank_same++;
+ else if (temp_byte == best_byte - 1)
+ rank_less++;
+ else if (temp_byte == best_byte + 1)
+ rank_more++;
#endif /* RANK_MAJORITY */
- } /* for (int orankx = 0; orankx < dimm_count * 4; orankx++) */
- } /* for (rodt_ctl = max_rodt_ctl; rodt_ctl >= min_rodt_ctl; --rodt_ctl) */
- } /* for (rtt_idx=min_rtt_nom_idx; rtt_idx<=max_rtt_nom_idx; ++rtt_idx) */
+ } /* for (int orankx = 0; orankx < dimm_count * 4; orankx++) */
+ } /* for (rodt_ctl = max_rodt_ctl; rodt_ctl >= min_rodt_ctl; --rodt_ctl) */
+ } /* for (rtt_idx=min_rtt_nom_idx; rtt_idx<=max_rtt_nom_idx; ++rtt_idx) */
#if RANK_MAJORITY
- VB_PRT(VBL_DEV, "N%d.LMC%d.R%d: COUNT: Byte %d: orig %d now %d, more %d same %d less %d (%d/%d/%d)\n",
- node, ddr_interface_num, rankx,
- byte_idx, (int)orig_best_byte, (int)best_byte,
- count_more, count_same, count_less,
- rank_more, rank_same, rank_less);
+ VB_PRT(VBL_DEV, "N%d.LMC%d.R%d: COUNT: Byte %d: orig %d now %d, more %d same %d less %d (%d/%d/%d)\n",
+ node, ddr_interface_num, rankx,
+ byte_idx, (int)orig_best_byte, (int)best_byte,
+ count_more, count_same, count_less,
+ rank_more, rank_same, rank_less);
#else /* RANK_MAJORITY */
- VB_PRT(VBL_DEV, "N%d.LMC%d.R%d: COUNT: Byte %d: orig %d now %d, more %d same %d less %d\n",
- node, ddr_interface_num, rankx,
- byte_idx, (int)orig_best_byte, (int)best_byte,
- count_more, count_same, count_less);
+ VB_PRT(VBL_DEV, "N%d.LMC%d.R%d: COUNT: Byte %d: orig %d now %d, more %d same %d less %d\n",
+ node, ddr_interface_num, rankx,
+ byte_idx, (int)orig_best_byte, (int)best_byte,
+ count_more, count_same, count_less);
#endif /* RANK_MAJORITY */
- ////////////////// this is the end of the BEST BYTE COUNTING LOOP
-
- // choose the new byte value
- // we need to check that there is no gap greater than 2 between adjacent bytes
- // (adjacency depends on DIMM type)
- // use the neighbor value to help decide
- // initially, the rank_best_bytes[] will contain values from the chosen lowest score rank
- new_byte = 0;
-
- // neighbor is index-1 unless we are index 0 or index 8 (ECC)
- int neighbor = (byte_idx == 8) ? 3 : ((byte_idx == 0) ? 1 : byte_idx - 1);
- uint64_t neigh_byte = rank_best_bytes[neighbor];
-
-
- // can go up or down or stay the same, so look at a numeric average to help
- new_byte = divide_nint(((count_more * (best_byte + 1)) +
- (count_same * (best_byte + 0)) +
- (count_less * (best_byte - 1))),
- max(1, (count_more + count_same + count_less)));
-
- // use neighbor to help choose with average
- if ((byte_idx > 0) && (_abs(neigh_byte - new_byte) > 2)) // but not for byte 0
- {
- uint64_t avg_pick = new_byte;
- if ((new_byte - best_byte) != 0)
- new_byte = best_byte; // back to best, average did not get better
- else // avg was the same, still too far, now move it towards the neighbor
- new_byte += (neigh_byte > new_byte) ? 1 : -1;
-
- VB_PRT(VBL_DEV, "N%d.LMC%d.R%d: AVERAGE: Byte %d: neighbor %d too different %d from average %d, picking %d.\n",
- node, ddr_interface_num, rankx,
- byte_idx, neighbor, (int)neigh_byte, (int)avg_pick, (int)new_byte);
- }
+ ////////////////// this is the end of the BEST BYTE COUNTING LOOP
+
+ // choose the new byte value
+ // we need to check that there is no gap greater than 2 between adjacent bytes
+ // (adjacency depends on DIMM type)
+ // use the neighbor value to help decide
+ // initially, the rank_best_bytes[] will contain values from the chosen lowest score rank
+ new_byte = 0;
+
+ // neighbor is index-1 unless we are index 0 or index 8 (ECC)
+ int neighbor = (byte_idx == 8) ? 3 : ((byte_idx == 0) ? 1 : byte_idx - 1);
+ uint64_t neigh_byte = rank_best_bytes[neighbor];
+
+
+ // can go up or down or stay the same, so look at a numeric average to help
+ new_byte = divide_nint(((count_more * (best_byte + 1)) +
+ (count_same * (best_byte + 0)) +
+ (count_less * (best_byte - 1))),
+ max(1, (count_more + count_same + count_less)));
+
+ // use neighbor to help choose with average
+ if ((byte_idx > 0) && (_abs(neigh_byte - new_byte) > 2)) // but not for byte 0
+ {
+ uint64_t avg_pick = new_byte;
+ if ((new_byte - best_byte) != 0)
+ new_byte = best_byte; // back to best, average did not get better
+ else // avg was the same, still too far, now move it towards the neighbor
+ new_byte += (neigh_byte > new_byte) ? 1 : -1;
+
+ VB_PRT(VBL_DEV, "N%d.LMC%d.R%d: AVERAGE: Byte %d: neighbor %d too different %d from average %d, picking %d.\n",
+ node, ddr_interface_num, rankx,
+ byte_idx, neighbor, (int)neigh_byte, (int)avg_pick, (int)new_byte);
+ }
#if MAJORITY_OVER_AVG
- // NOTE:
- // For now, we let the neighbor processing above trump the new simple majority processing here.
- // This is mostly because we have seen no smoking gun for a neighbor bad choice (yet?).
- // Also note that we will ALWAYS be using byte 0 majority, because of the if clause above.
- else {
- // majority is dependent on the counts, which are relative to best_byte, so start there
- uint64_t maj_byte = best_byte;
- if ((count_more > count_same) && (count_more > count_less)) {
- maj_byte++;
- } else if ((count_less > count_same) && (count_less > count_more)) {
- maj_byte--;
- }
- if (maj_byte != new_byte) {
- // print only when majority choice is different from average
- VB_PRT(VBL_DEV, "N%d.LMC%d.R%d: MAJORTY: Byte %d: picking majority of %d over average %d.\n",
- node, ddr_interface_num, rankx,
- byte_idx, (int)maj_byte, (int)new_byte);
- new_byte = maj_byte;
- } else {
- VB_PRT(VBL_DEV, "N%d.LMC%d.R%d: AVERAGE: Byte %d: picking average of %d.\n",
- node, ddr_interface_num, rankx,
- byte_idx, (int)new_byte);
- }
+ // NOTE:
+ // For now, we let the neighbor processing above trump the new simple majority processing here.
+ // This is mostly because we have seen no smoking gun for a neighbor bad choice (yet?).
+ // Also note that we will ALWAYS be using byte 0 majority, because of the if clause above.
+ else {
+ // majority is dependent on the counts, which are relative to best_byte, so start there
+ uint64_t maj_byte = best_byte;
+ if ((count_more > count_same) && (count_more > count_less)) {
+ maj_byte++;
+ } else if ((count_less > count_same) && (count_less > count_more)) {
+ maj_byte--;
+ }
+ if (maj_byte != new_byte) {
+ // print only when majority choice is different from average
+ VB_PRT(VBL_DEV, "N%d.LMC%d.R%d: MAJORTY: Byte %d: picking majority of %d over average %d.\n",
+ node, ddr_interface_num, rankx,
+ byte_idx, (int)maj_byte, (int)new_byte);
+ new_byte = maj_byte;
+ } else {
+ VB_PRT(VBL_DEV, "N%d.LMC%d.R%d: AVERAGE: Byte %d: picking average of %d.\n",
+ node, ddr_interface_num, rankx,
+ byte_idx, (int)new_byte);
+ }
#if RANK_MAJORITY
- // rank majority is dependent on the rank counts, which are relative to best_byte,
- // so start there, and adjust according to the rank counts majority
- uint64_t rank_maj = best_byte;
- if ((rank_more > rank_same) && (rank_more > rank_less)) {
- rank_maj++;
- } else if ((rank_less > rank_same) && (rank_less > rank_more)) {
- rank_maj--;
- }
- int rank_sum = rank_more + rank_same + rank_less;
-
- // now, let rank majority possibly rule over the current new_byte however we got it
- if (rank_maj != new_byte) { // only if different
- // Here is where we decide whether to completely apply RANK_MAJORITY or not
- // FIXME: For the moment, we do it ONLY when running 2-slot configs
- // FIXME? or when rank_sum is big enough?
- if ((dimm_count > 1) || (rank_sum > 2)) {
- // print only when rank majority choice is selected
- VB_PRT(VBL_DEV, "N%d.LMC%d.R%d: RANKMAJ: Byte %d: picking %d over %d.\n",
- node, ddr_interface_num, rankx,
- byte_idx, (int)rank_maj, (int)new_byte);
- new_byte = rank_maj;
- } else { // FIXME: print some info when we could have chosen RANKMAJ but did not
- VB_PRT(VBL_DEV, "N%d.LMC%d.R%d: RANKMAJ: Byte %d: NOT using %d over %d (best=%d,sum=%d).\n",
- node, ddr_interface_num, rankx,
- byte_idx, (int)rank_maj, (int)new_byte,
- (int)best_byte, rank_sum);
- }
- }
+ // rank majority is dependent on the rank counts, which are relative to best_byte,
+ // so start there, and adjust according to the rank counts majority
+ uint64_t rank_maj = best_byte;
+ if ((rank_more > rank_same) && (rank_more > rank_less)) {
+ rank_maj++;
+ } else if ((rank_less > rank_same) && (rank_less > rank_more)) {
+ rank_maj--;
+ }
+ int rank_sum = rank_more + rank_same + rank_less;
+
+ // now, let rank majority possibly rule over the current new_byte however we got it
+ if (rank_maj != new_byte) { // only if different
+ // Here is where we decide whether to completely apply RANK_MAJORITY or not
+ // FIXME: For the moment, we do it ONLY when running 2-slot configs
+ // FIXME? or when rank_sum is big enough?
+ if ((dimm_count > 1) || (rank_sum > 2)) {
+ // print only when rank majority choice is selected
+ VB_PRT(VBL_DEV, "N%d.LMC%d.R%d: RANKMAJ: Byte %d: picking %d over %d.\n",
+ node, ddr_interface_num, rankx,
+ byte_idx, (int)rank_maj, (int)new_byte);
+ new_byte = rank_maj;
+ } else { // FIXME: print some info when we could have chosen RANKMAJ but did not
+ VB_PRT(VBL_DEV, "N%d.LMC%d.R%d: RANKMAJ: Byte %d: NOT using %d over %d (best=%d,sum=%d).\n",
+ node, ddr_interface_num, rankx,
+ byte_idx, (int)rank_maj, (int)new_byte,
+ (int)best_byte, rank_sum);
+ }
+ }
#endif /* RANK_MAJORITY */
- }
+ }
#else
- else {
- VB_PRT(VBL_DEV, "N%d.LMC%d.R%d: AVERAGE: Byte %d: picking average of %d.\n",
- node, ddr_interface_num, rankx,
- byte_idx, (int)new_byte);
- }
+ else {
+ VB_PRT(VBL_DEV, "N%d.LMC%d.R%d: AVERAGE: Byte %d: picking average of %d.\n",
+ node, ddr_interface_num, rankx,
+ byte_idx, (int)new_byte);
+ }
#endif
#if FAILSAFE_CHECK
// one last check:
@@ -7196,9 +7196,9 @@ int init_octeon3_ddr3_interface(bdk_node_t node,
// FIXME: go back to original best byte from the best row
if ((new_byte == count_byte) && (count_same == 0)) {
new_byte = orig_best_byte;
- VB_PRT(VBL_DEV, "N%d.LMC%d.R%d: FAILSAF: Byte %d: going back to original %d.\n",
- node, ddr_interface_num, rankx,
- byte_idx, (int)new_byte);
+ VB_PRT(VBL_DEV, "N%d.LMC%d.R%d: FAILSAF: Byte %d: going back to original %d.\n",
+ node, ddr_interface_num, rankx,
+ byte_idx, (int)new_byte);
}
#endif /* FAILSAFE_CHECK */
#if PERFECT_BITMASK_COUNTING
@@ -7206,26 +7206,28 @@ int init_octeon3_ddr3_interface(bdk_node_t node,
// Remember, we only counted for DDR4, so zero means none or DDR3, and we bypass this...
if (rank_perfect_counts[rankx].total[byte_idx] > 0) {
// FIXME: should be more error checking, look for ties, etc...
- int i, delay_count, delay_value, delay_max;
+ /* FIXME(dhendrix): i shadows another local variable, changed to _i in this block */
+// int i, delay_count, delay_value, delay_max;
+ int _i, delay_count, delay_value, delay_max;
uint32_t ties;
delay_value = -1;
delay_max = 0;
ties = 0;
- for (i = 0; i < 32; i++) {
- delay_count = rank_perfect_counts[rankx].count[byte_idx][i];
+ for (_i = 0; _i < 32; _i++) {
+ delay_count = rank_perfect_counts[rankx].count[byte_idx][_i];
if (delay_count > 0) { // only look closer if there are any,,,
if (delay_count > delay_max) {
delay_max = delay_count;
- delay_value = i;
+ delay_value = _i;
ties = 0; // reset ties to none
} else if (delay_count == delay_max) {
if (ties == 0)
ties = 1UL << delay_value; // put in original value
- ties |= 1UL << i; // add new value
+ ties |= 1UL << _i; // add new value
}
}
- } /* for (i = 0; i < 32; i++) */
+ } /* for (_i = 0; _i < 32; _i++) */
if (delay_value >= 0) {
if (ties != 0) {
@@ -7266,69 +7268,69 @@ int init_octeon3_ddr3_interface(bdk_node_t node,
} /* if (rank_perfect_counts[rankx].total[byte_idx] > 0) */
#endif /* PERFECT_BITMASK_COUNTING */
- VB_PRT(VBL_DEV, "N%d.LMC%d.R%d: SUMMARY: Byte %d: %s: orig %d now %d, more %d same %d less %d, using %d\n",
- node, ddr_interface_num, rankx,
- byte_idx, "AVG", (int)orig_best_byte,
- (int)best_byte, count_more, count_same, count_less, (int)new_byte);
+ VB_PRT(VBL_DEV, "N%d.LMC%d.R%d: SUMMARY: Byte %d: %s: orig %d now %d, more %d same %d less %d, using %d\n",
+ node, ddr_interface_num, rankx,
+ byte_idx, "AVG", (int)orig_best_byte,
+ (int)best_byte, count_more, count_same, count_less, (int)new_byte);
- // update the byte with the new value (NOTE: orig value in the CSR may not be current "best")
- lmc_rlevel_rank.u &= ~(byte_msk << byte_sh);
- lmc_rlevel_rank.u |= (new_byte << byte_sh);
+ // update the byte with the new value (NOTE: orig value in the CSR may not be current "best")
+ lmc_rlevel_rank.u &= ~(byte_msk << byte_sh);
+ lmc_rlevel_rank.u |= (new_byte << byte_sh);
- rank_best_bytes[byte_idx] = new_byte; // save new best for neighbor use
+ rank_best_bytes[byte_idx] = new_byte; // save new best for neighbor use
- } /* for (byte_idx = 0; byte_idx < 8+ecc_ena; byte_idx++) */
+ } /* for (byte_idx = 0; byte_idx < 8+ecc_ena; byte_idx++) */
- ////////////////// this is the end of the BEST BYTE LOOP
+ ////////////////// this is the end of the BEST BYTE LOOP
- if (saved_rlevel_rank.u != lmc_rlevel_rank.u) {
- DRAM_CSR_WRITE(node, BDK_LMCX_RLEVEL_RANKX(ddr_interface_num, rankx), lmc_rlevel_rank.u);
- lmc_rlevel_rank.u = BDK_CSR_READ(node, BDK_LMCX_RLEVEL_RANKX(ddr_interface_num, rankx));
- debug_print("Adjusting Read-Leveling per-RANK settings.\n");
- } else {
- debug_print("Not Adjusting Read-Leveling per-RANK settings.\n");
- }
- display_RL_with_final(node, ddr_interface_num, lmc_rlevel_rank, rankx);
+ if (saved_rlevel_rank.u != lmc_rlevel_rank.u) {
+ DRAM_CSR_WRITE(node, BDK_LMCX_RLEVEL_RANKX(ddr_interface_num, rankx), lmc_rlevel_rank.u);
+ lmc_rlevel_rank.u = BDK_CSR_READ(node, BDK_LMCX_RLEVEL_RANKX(ddr_interface_num, rankx));
+ debug_print("Adjusting Read-Leveling per-RANK settings.\n");
+ } else {
+ debug_print("Not Adjusting Read-Leveling per-RANK settings.\n");
+ }
+ display_RL_with_final(node, ddr_interface_num, lmc_rlevel_rank, rankx);
#if RLEXTRAS_PATCH
#define RLEVEL_RANKX_EXTRAS_INCR 4
- if ((rank_mask & 0x0F) != 0x0F) { // if there are unused entries to be filled
- bdk_lmcx_rlevel_rankx_t temp_rlevel_rank = lmc_rlevel_rank; // copy the current rank
- int byte, delay;
- if (rankx < 3) {
- debug_print("N%d.LMC%d.R%d: checking for RLEVEL_RANK unused entries.\n",
- node, ddr_interface_num, rankx);
- for (byte = 0; byte < 9; byte++) { // modify the copy in prep for writing to empty slot(s)
- delay = get_rlevel_rank_struct(&temp_rlevel_rank, byte) + RLEVEL_RANKX_EXTRAS_INCR;
- if (delay > (int)RLEVEL_BYTE_MSK) delay = RLEVEL_BYTE_MSK;
- update_rlevel_rank_struct(&temp_rlevel_rank, byte, delay);
- }
- if (rankx == 0) { // if rank 0, write rank 1 and rank 2 here if empty
- if (!(rank_mask & (1<<1))) { // check that rank 1 is empty
- VB_PRT(VBL_DEV, "N%d.LMC%d.R%d: writing RLEVEL_RANK unused entry R%d.\n",
- node, ddr_interface_num, rankx, 1);
- DRAM_CSR_WRITE(node, BDK_LMCX_RLEVEL_RANKX(ddr_interface_num, 1), temp_rlevel_rank.u);
- }
- if (!(rank_mask & (1<<2))) { // check that rank 2 is empty
- VB_PRT(VBL_DEV, "N%d.LMC%d.R%d: writing RLEVEL_RANK unused entry R%d.\n",
- node, ddr_interface_num, rankx, 2);
- DRAM_CSR_WRITE(node, BDK_LMCX_RLEVEL_RANKX(ddr_interface_num, 2), temp_rlevel_rank.u);
- }
- }
- // if ranks 0, 1 or 2, write rank 3 here if empty
- if (!(rank_mask & (1<<3))) { // check that rank 3 is empty
- VB_PRT(VBL_DEV, "N%d.LMC%d.R%d: writing RLEVEL_RANK unused entry R%d.\n",
- node, ddr_interface_num, rankx, 3);
- DRAM_CSR_WRITE(node, BDK_LMCX_RLEVEL_RANKX(ddr_interface_num, 3), temp_rlevel_rank.u);
- }
- }
- }
+ if ((rank_mask & 0x0F) != 0x0F) { // if there are unused entries to be filled
+ bdk_lmcx_rlevel_rankx_t temp_rlevel_rank = lmc_rlevel_rank; // copy the current rank
+ int byte, delay;
+ if (rankx < 3) {
+ debug_print("N%d.LMC%d.R%d: checking for RLEVEL_RANK unused entries.\n",
+ node, ddr_interface_num, rankx);
+ for (byte = 0; byte < 9; byte++) { // modify the copy in prep for writing to empty slot(s)
+ delay = get_rlevel_rank_struct(&temp_rlevel_rank, byte) + RLEVEL_RANKX_EXTRAS_INCR;
+ if (delay > (int)RLEVEL_BYTE_MSK) delay = RLEVEL_BYTE_MSK;
+ update_rlevel_rank_struct(&temp_rlevel_rank, byte, delay);
+ }
+ if (rankx == 0) { // if rank 0, write rank 1 and rank 2 here if empty
+ if (!(rank_mask & (1<<1))) { // check that rank 1 is empty
+ VB_PRT(VBL_DEV, "N%d.LMC%d.R%d: writing RLEVEL_RANK unused entry R%d.\n",
+ node, ddr_interface_num, rankx, 1);
+ DRAM_CSR_WRITE(node, BDK_LMCX_RLEVEL_RANKX(ddr_interface_num, 1), temp_rlevel_rank.u);
+ }
+ if (!(rank_mask & (1<<2))) { // check that rank 2 is empty
+ VB_PRT(VBL_DEV, "N%d.LMC%d.R%d: writing RLEVEL_RANK unused entry R%d.\n",
+ node, ddr_interface_num, rankx, 2);
+ DRAM_CSR_WRITE(node, BDK_LMCX_RLEVEL_RANKX(ddr_interface_num, 2), temp_rlevel_rank.u);
+ }
+ }
+ // if ranks 0, 1 or 2, write rank 3 here if empty
+ if (!(rank_mask & (1<<3))) { // check that rank 3 is empty
+ VB_PRT(VBL_DEV, "N%d.LMC%d.R%d: writing RLEVEL_RANK unused entry R%d.\n",
+ node, ddr_interface_num, rankx, 3);
+ DRAM_CSR_WRITE(node, BDK_LMCX_RLEVEL_RANKX(ddr_interface_num, 3), temp_rlevel_rank.u);
+ }
+ }
+ }
#endif /* RLEXTRAS_PATCH */
- } /* for (rankx = 0; rankx < dimm_count * 4; rankx++) */
+ } /* for (rankx = 0; rankx < dimm_count * 4; rankx++) */
- ////////////////// this is the end of the RANK MAJOR LOOP
+ ////////////////// this is the end of the RANK MAJOR LOOP
- } /* Evaluation block */
+ } /* Evaluation block */
} /* while(rlevel_debug_loops--) */
lmc_control.s.ddr2t = save_ddr2t;
@@ -7362,21 +7364,6 @@ int init_octeon3_ddr3_interface(bdk_node_t node,
lmc_rlevel_rank.u = value;
}
-
- if (bdk_is_platform(BDK_PLATFORM_ASIM)) {
- parameter_set |= 1;
-
- lmc_rlevel_rank.cn83xx.byte8 = 3;
- lmc_rlevel_rank.cn83xx.byte7 = 3;
- lmc_rlevel_rank.cn83xx.byte6 = 3;
- lmc_rlevel_rank.cn83xx.byte5 = 3;
- lmc_rlevel_rank.cn83xx.byte4 = 3;
- lmc_rlevel_rank.cn83xx.byte3 = 3;
- lmc_rlevel_rank.cn83xx.byte2 = 3;
- lmc_rlevel_rank.cn83xx.byte1 = 3;
- lmc_rlevel_rank.cn83xx.byte0 = 3;
- }
-
if (parameter_set) {
DRAM_CSR_WRITE(node, BDK_LMCX_RLEVEL_RANKX(ddr_interface_num, rankx), lmc_rlevel_rank.u);
display_RL(node, ddr_interface_num, lmc_rlevel_rank, rankx);
@@ -7402,12 +7389,12 @@ int init_octeon3_ddr3_interface(bdk_node_t node,
lmc_modereg_params0.s.al = 2; /* CL-2 */
lmc_control.s.pocas = 1;
- ddr_print("MODEREG_PARAMS0 : 0x%016lx\n", lmc_modereg_params0.u);
+ ddr_print("MODEREG_PARAMS0 : 0x%016llx\n", lmc_modereg_params0.u);
DRAM_CSR_WRITE(node, BDK_LMCX_MODEREG_PARAMS0(ddr_interface_num), lmc_modereg_params0.u);
- ddr_print("TIMING_PARAMS1 : 0x%016lx\n", lmc_timing_params1.u);
+ ddr_print("TIMING_PARAMS1 : 0x%016llx\n", lmc_timing_params1.u);
DRAM_CSR_WRITE(node, BDK_LMCX_TIMING_PARAMS1(ddr_interface_num), lmc_timing_params1.u);
- ddr_print("LMC_CONTROL : 0x%016lx\n", lmc_control.u);
+ ddr_print("LMC_CONTROL : 0x%016llx\n", lmc_control.u);
DRAM_CSR_WRITE(node, BDK_LMCX_CONTROL(ddr_interface_num), lmc_control.u);
for (rankx = 0; rankx < dimm_count * 4; rankx++) {
@@ -7422,8 +7409,8 @@ int init_octeon3_ddr3_interface(bdk_node_t node,
// this is here just for output, to allow check of the Deskew settings one last time...
if (! disable_deskew_training) {
deskew_counts_t dsk_counts;
- VB_PRT(VBL_TME, "N%d.LMC%d: Check Deskew Settings before software Write-Leveling.\n",
- node, ddr_interface_num);
+ VB_PRT(VBL_TME, "N%d.LMC%d: Check Deskew Settings before software Write-Leveling.\n",
+ node, ddr_interface_num);
Validate_Read_Deskew_Training(node, rank_mask, ddr_interface_num, &dsk_counts, VBL_TME); // TME for FINAL
}
@@ -7480,7 +7467,7 @@ int init_octeon3_ddr3_interface(bdk_node_t node,
#endif
int sw_wlevel_enable = 1; /* FIX... Should be customizable. */
int interfaces;
- int measured_vref_flag;
+ int measured_vref_flag;
typedef enum {
WL_ESTIMATED = 0, /* HW/SW wleveling failed. Results
estimated. */
@@ -7532,8 +7519,8 @@ int init_octeon3_ddr3_interface(bdk_node_t node,
} /* for (rankx = 0; rankx < dimm_count * 4; rankx++) */
#endif
- /* Get the measured_vref setting from the config, check for an override... */
- /* NOTE: measured_vref=1 (ON) means force use of MEASURED Vref... */
+ /* Get the measured_vref setting from the config, check for an override... */
+ /* NOTE: measured_vref=1 (ON) means force use of MEASURED Vref... */
// NOTE: measured VREF can only be done for DDR4
if (ddr_type == DDR4_DRAM) {
measured_vref_flag = custom_lmc_config->measured_vref;
@@ -7560,7 +7547,7 @@ int init_octeon3_ddr3_interface(bdk_node_t node,
** ranks 0 and 2, but only 2 ranks are active. */
active_rank = 0;
- interfaces = __builtin_popcount(ddr_interface_mask);
+ interfaces = bdk_pop(ddr_interface_mask);
#define VREF_RANGE1_LIMIT 0x33 // range1 is valid for 0x00 - 0x32
#define VREF_RANGE2_LIMIT 0x18 // range2 is valid for 0x00 - 0x17
@@ -7572,14 +7559,14 @@ int init_octeon3_ddr3_interface(bdk_node_t node,
for (rankx = 0; rankx < dimm_count * 4; rankx++) {
uint64_t rank_addr;
int vref_value, final_vref_value, final_vref_range = 0;
- int start_vref_value = 0, computed_final_vref_value = -1;
+ int start_vref_value = 0, computed_final_vref_value = -1;
char best_vref_values_count, vref_values_count;
char best_vref_values_start, vref_values_start;
int bytes_failed;
sw_wl_status_t byte_test_status[9];
sw_wl_status_t sw_wl_rank_status = WL_HARDWARE;
- int sw_wl_failed = 0;
+ int sw_wl_failed = 0;
int sw_wlevel_hw = sw_wlevel_hw_default;
if (!sw_wlevel_enable)
@@ -7592,14 +7579,14 @@ int init_octeon3_ddr3_interface(bdk_node_t node,
node, ddr_interface_num, rankx,
(sw_wlevel_hw) ? "with H/W assist" : "with S/W algorithm");
- if ((ddr_type == DDR4_DRAM) && (num_ranks != 4)) {
- // always compute when we can...
- computed_final_vref_value = compute_vref_value(node, ddr_interface_num, rankx,
- dimm_count, num_ranks, imp_values,
- is_stacked_die);
- if (!measured_vref_flag) // but only use it if allowed
- start_vref_value = VREF_FINAL; // skip all the measured Vref processing, just the final setting
- }
+ if ((ddr_type == DDR4_DRAM) && (num_ranks != 4)) {
+ // always compute when we can...
+ computed_final_vref_value = compute_vref_value(node, ddr_interface_num, rankx,
+ dimm_count, num_ranks, imp_values,
+ is_stacked_die);
+ if (!measured_vref_flag) // but only use it if allowed
+ start_vref_value = VREF_FINAL; // skip all the measured Vref processing, just the final setting
+ }
/* Save off the h/w wl results */
lmc_wlevel_rank_hw_results.u = BDK_CSR_READ(node, BDK_LMCX_WLEVEL_RANKX(ddr_interface_num, rankx));
@@ -7619,36 +7606,36 @@ int init_octeon3_ddr3_interface(bdk_node_t node,
} else {
vrange = 0; vvalue = vref_value - VREF_RANGE2_LIMIT;
}
- set_vref(node, ddr_interface_num, rankx,
+ set_vref(node, ddr_interface_num, rankx,
vrange, vvalue);
} else { /* if (vref_value < VREF_FINAL) */
/* Print the final Vref value first. */
- /* Always print the computed first if its valid */
- if (computed_final_vref_value >= 0) {
- ddr_print("N%d.LMC%d.R%d: Vref Computed Summary :"
- " %2d (0x%02x)\n",
- node, ddr_interface_num,
- rankx, computed_final_vref_value,
- computed_final_vref_value);
- }
- if (!measured_vref_flag) { // setup to use the computed
- best_vref_values_count = 1;
- final_vref_value = computed_final_vref_value;
- } else { // setup to use the measured
- if (best_vref_values_count > 0) {
- best_vref_values_count = max(best_vref_values_count, 2);
+ /* Always print the computed first if its valid */
+ if (computed_final_vref_value >= 0) {
+ ddr_print("N%d.LMC%d.R%d: Vref Computed Summary :"
+ " %2d (0x%02x)\n",
+ node, ddr_interface_num,
+ rankx, computed_final_vref_value,
+ computed_final_vref_value);
+ }
+ if (!measured_vref_flag) { // setup to use the computed
+ best_vref_values_count = 1;
+ final_vref_value = computed_final_vref_value;
+ } else { // setup to use the measured
+ if (best_vref_values_count > 0) {
+ best_vref_values_count = max(best_vref_values_count, 2);
#if 0
// NOTE: this already adjusts VREF via calculating 40% rather than 50%
- final_vref_value = best_vref_values_start + divide_roundup((best_vref_values_count-1)*4,10);
- ddr_print("N%d.LMC%d.R%d: Vref Training Summary :"
- " %2d <----- %2d (0x%02x) -----> %2d range: %2d\n",
- node, ddr_interface_num, rankx, best_vref_values_start,
- final_vref_value, final_vref_value,
- best_vref_values_start+best_vref_values_count-1,
- best_vref_values_count-1);
+ final_vref_value = best_vref_values_start + divide_roundup((best_vref_values_count-1)*4,10);
+ ddr_print("N%d.LMC%d.R%d: Vref Training Summary :"
+ " %2d <----- %2d (0x%02x) -----> %2d range: %2d\n",
+ node, ddr_interface_num, rankx, best_vref_values_start,
+ final_vref_value, final_vref_value,
+ best_vref_values_start+best_vref_values_count-1,
+ best_vref_values_count-1);
#else
- final_vref_value = best_vref_values_start + divide_nint(best_vref_values_count - 1, 2);
+ final_vref_value = best_vref_values_start + divide_nint(best_vref_values_count - 1, 2);
if (final_vref_value < VREF_RANGE2_LIMIT) {
final_vref_range = 1;
} else {
@@ -7680,36 +7667,36 @@ int init_octeon3_ddr3_interface(bdk_node_t node,
}
#endif
- } else {
- /* If nothing passed use the default Vref value for this rank */
- bdk_lmcx_modereg_params2_t lmc_modereg_params2;
- lmc_modereg_params2.u = BDK_CSR_READ(node, BDK_LMCX_MODEREG_PARAMS2(ddr_interface_num));
- final_vref_value = (lmc_modereg_params2.u >> (rankx * 10 + 3)) & 0x3f;
- final_vref_range = (lmc_modereg_params2.u >> (rankx * 10 + 9)) & 0x01;
-
- ddr_print("N%d.LMC%d.R%d: Vref Using Default :"
- " %2d <----- %2d (0x%02x) -----> %2d, range%1d\n",
- node, ddr_interface_num, rankx,
+ } else {
+ /* If nothing passed use the default Vref value for this rank */
+ bdk_lmcx_modereg_params2_t lmc_modereg_params2;
+ lmc_modereg_params2.u = BDK_CSR_READ(node, BDK_LMCX_MODEREG_PARAMS2(ddr_interface_num));
+ final_vref_value = (lmc_modereg_params2.u >> (rankx * 10 + 3)) & 0x3f;
+ final_vref_range = (lmc_modereg_params2.u >> (rankx * 10 + 9)) & 0x01;
+
+ ddr_print("N%d.LMC%d.R%d: Vref Using Default :"
+ " %2d <----- %2d (0x%02x) -----> %2d, range%1d\n",
+ node, ddr_interface_num, rankx,
final_vref_value, final_vref_value,
- final_vref_value, final_vref_value, final_vref_range+1);
- }
- }
+ final_vref_value, final_vref_value, final_vref_range+1);
+ }
+ }
- // allow override
+ // allow override
if ((s = lookup_env_parameter("ddr%d_vref_value_%1d%1d",
ddr_interface_num, !!(rankx&2), !!(rankx&1))) != NULL) {
final_vref_value = strtoul(s, NULL, 0);
}
- set_vref(node, ddr_interface_num, rankx, final_vref_range, final_vref_value);
+ set_vref(node, ddr_interface_num, rankx, final_vref_range, final_vref_value);
- } /* if (vref_value < VREF_FINAL) */
+ } /* if (vref_value < VREF_FINAL) */
} /* if (ddr_type == DDR4_DRAM) */
lmc_wlevel_rank.u = lmc_wlevel_rank_hw_results.u; /* Restore the saved value */
- for (byte = 0; byte < 9; ++byte)
- byte_test_status[byte] = WL_ESTIMATED;
+ for (byte = 0; byte < 9; ++byte)
+ byte_test_status[byte] = WL_ESTIMATED;
if (wlevel_bitmask_errors == 0) {
@@ -7718,14 +7705,14 @@ int init_octeon3_ddr3_interface(bdk_node_t node,
// FIXME: these now put in by test_dram_byte()
//rank_addr |= (ddr_interface_num<<7); /* Map address into proper interface */
//rank_addr = bdk_numa_get_address(node, rank_addr);
- VB_PRT(VBL_DEV, "N%d.LMC%d.R%d: Active Rank %d Address: 0x%lx\n",
+ VB_PRT(VBL_DEV, "N%d.LMC%d.R%d: Active Rank %d Address: 0x%llx\n",
node, ddr_interface_num, rankx, active_rank, rank_addr);
- { // start parallel write-leveling block for delay high-order bits
- int errors = 0;
- int byte_delay[9];
- uint64_t bytemask;
- int bytes_todo;
+ { // start parallel write-leveling block for delay high-order bits
+ int errors = 0;
+ int byte_delay[9];
+ uint64_t bytemask;
+ int bytes_todo;
if (ddr_interface_64b) {
bytes_todo = (sw_wlevel_hw) ? ddr_interface_bytemask : 0xFF;
@@ -7735,16 +7722,16 @@ int init_octeon3_ddr3_interface(bdk_node_t node,
bytemask = 0x00000000ffffffffULL;
}
- for (byte = 0; byte < 9; ++byte) {
- if (!(bytes_todo & (1 << byte))) {
- byte_delay[byte] = 0;
- } else {
- byte_delay[byte] = get_wlevel_rank_struct(&lmc_wlevel_rank, byte);
- }
- } /* for (byte = 0; byte < 9; ++byte) */
+ for (byte = 0; byte < 9; ++byte) {
+ if (!(bytes_todo & (1 << byte))) {
+ byte_delay[byte] = 0;
+ } else {
+ byte_delay[byte] = get_wlevel_rank_struct(&lmc_wlevel_rank, byte);
+ }
+ } /* for (byte = 0; byte < 9; ++byte) */
#define WL_MIN_NO_ERRORS_COUNT 3 // FIXME? three passes without errors
- int no_errors_count = 0;
+ int no_errors_count = 0;
// Change verbosity if using measured vs computed VREF or DDR3
// measured goes many times through SWL, computed and DDR3 only once
@@ -7757,14 +7744,14 @@ int init_octeon3_ddr3_interface(bdk_node_t node,
uint64_t start_dram_dclk, stop_dram_dclk;
uint64_t start_dram_ops, stop_dram_ops;
#endif
- do {
- // write the current set of WL delays
- DRAM_CSR_WRITE(node, BDK_LMCX_WLEVEL_RANKX(ddr_interface_num, rankx), lmc_wlevel_rank.u);
- lmc_wlevel_rank.u = BDK_CSR_READ(node, BDK_LMCX_WLEVEL_RANKX(ddr_interface_num, rankx));
+ do {
+ // write the current set of WL delays
+ DRAM_CSR_WRITE(node, BDK_LMCX_WLEVEL_RANKX(ddr_interface_num, rankx), lmc_wlevel_rank.u);
+ lmc_wlevel_rank.u = BDK_CSR_READ(node, BDK_LMCX_WLEVEL_RANKX(ddr_interface_num, rankx));
- bdk_watchdog_poke();
+ bdk_watchdog_poke();
- // do the test
+ // do the test
if (sw_wlevel_hw) {
errors = run_best_hw_patterns(node, ddr_interface_num, rank_addr,
DBTRAIN_TEST, bad_bits);
@@ -7787,10 +7774,10 @@ int init_octeon3_ddr3_interface(bdk_node_t node,
#endif
}
- VB_PRT(VBL_DEV2, "N%d.LMC%d.R%d: S/W write-leveling TEST: returned 0x%x\n",
+ VB_PRT(VBL_DEV2, "N%d.LMC%d.R%d: S/W write-leveling TEST: returned 0x%x\n",
node, ddr_interface_num, rankx, errors);
- // remember, errors will not be returned for byte-lanes that have maxxed out...
+ // remember, errors will not be returned for byte-lanes that have maxxed out...
if (errors == 0) {
no_errors_count++; // bump
if (no_errors_count > 1) // bypass check/update completely
@@ -7798,39 +7785,39 @@ int init_octeon3_ddr3_interface(bdk_node_t node,
} else
no_errors_count = 0; // reset
- // check errors by byte
- for (byte = 0; byte < 9; ++byte) {
- if (!(bytes_todo & (1 << byte)))
- continue;
-
- delay = byte_delay[byte];
- if (errors & (1 << byte)) { // yes, an error in this byte lane
- debug_print(" byte %d delay %2d Errors\n", byte, delay);
- // since this byte had an error, we move to the next delay value, unless maxxed out
- delay += 8; // incr by 8 to do only delay high-order bits
- if (delay < 32) {
- update_wlevel_rank_struct(&lmc_wlevel_rank, byte, delay);
- debug_print(" byte %d delay %2d New\n", byte, delay);
- byte_delay[byte] = delay;
- } else { // reached max delay, maybe really done with this byte
+ // check errors by byte
+ for (byte = 0; byte < 9; ++byte) {
+ if (!(bytes_todo & (1 << byte)))
+ continue;
+
+ delay = byte_delay[byte];
+ if (errors & (1 << byte)) { // yes, an error in this byte lane
+ debug_print(" byte %d delay %2d Errors\n", byte, delay);
+ // since this byte had an error, we move to the next delay value, unless maxxed out
+ delay += 8; // incr by 8 to do only delay high-order bits
+ if (delay < 32) {
+ update_wlevel_rank_struct(&lmc_wlevel_rank, byte, delay);
+ debug_print(" byte %d delay %2d New\n", byte, delay);
+ byte_delay[byte] = delay;
+ } else { // reached max delay, maybe really done with this byte
#if SWL_TRY_HWL_ALT
- if (!measured_vref_flag && // consider an alt only for computed VREF and
+ if (!measured_vref_flag && // consider an alt only for computed VREF and
(hwl_alts[rankx].hwl_alt_mask & (1 << byte))) // if an alt exists...
{
int bad_delay = delay & 0x6; // just orig low-3 bits
- delay = hwl_alts[rankx].hwl_alt_delay[byte]; // yes, use it
- hwl_alts[rankx].hwl_alt_mask &= ~(1 << byte); // clear that flag
- update_wlevel_rank_struct(&lmc_wlevel_rank, byte, delay);
- byte_delay[byte] = delay;
- debug_print(" byte %d delay %2d ALTERNATE\n", byte, delay);
- VB_PRT(VBL_DEV, "N%d.LMC%d.R%d: SWL: Byte %d: %d FAIL, trying ALTERNATE %d\n",
+ delay = hwl_alts[rankx].hwl_alt_delay[byte]; // yes, use it
+ hwl_alts[rankx].hwl_alt_mask &= ~(1 << byte); // clear that flag
+ update_wlevel_rank_struct(&lmc_wlevel_rank, byte, delay);
+ byte_delay[byte] = delay;
+ debug_print(" byte %d delay %2d ALTERNATE\n", byte, delay);
+ VB_PRT(VBL_DEV, "N%d.LMC%d.R%d: SWL: Byte %d: %d FAIL, trying ALTERNATE %d\n",
node, ddr_interface_num, rankx, byte, bad_delay, delay);
- } else
+ } else
#endif /* SWL_TRY_HWL_ALT */
{
unsigned bits_bad;
- if (byte < 8) {
+ if (byte < 8) {
bytemask &= ~(0xffULL << (8*byte)); // test no longer, remove from byte mask
bits_bad = (unsigned)((bad_bits[0] >> (8 * byte)) & 0xffUL);
} else {
@@ -7839,18 +7826,18 @@ int init_octeon3_ddr3_interface(bdk_node_t node,
bytes_todo &= ~(1 << byte); // remove from bytes to do
byte_test_status[byte] = WL_ESTIMATED; // make sure this is set for this case
debug_print(" byte %d delay %2d Exhausted\n", byte, delay);
- VB_PRT(vbl_local, "N%d.LMC%d.R%d: SWL: Byte %d (0x%02x): delay %d EXHAUSTED \n",
+ VB_PRT(vbl_local, "N%d.LMC%d.R%d: SWL: Byte %d (0x%02x): delay %d EXHAUSTED \n",
node, ddr_interface_num, rankx, byte, bits_bad, delay);
}
- }
- } else { // no error, stay with current delay, but keep testing it...
- debug_print(" byte %d delay %2d Passed\n", byte, delay);
- byte_test_status[byte] = WL_HARDWARE; // change status
- }
+ }
+ } else { // no error, stay with current delay, but keep testing it...
+ debug_print(" byte %d delay %2d Passed\n", byte, delay);
+ byte_test_status[byte] = WL_HARDWARE; // change status
+ }
- } /* for (byte = 0; byte < 9; ++byte) */
+ } /* for (byte = 0; byte < 9; ++byte) */
- } while (no_errors_count < WL_MIN_NO_ERRORS_COUNT);
+ } while (no_errors_count < WL_MIN_NO_ERRORS_COUNT);
#if ENABLE_SW_WLEVEL_UTILIZATION
if (! sw_wlevel_hw) {
@@ -7863,11 +7850,11 @@ int init_octeon3_ddr3_interface(bdk_node_t node,
percent_x10 / 10, percent_x10 % 10);
}
#endif
- if (errors) {
- debug_print("End WLEV_64 while loop: vref_value %d(0x%x), errors 0x%02x\n",
- vref_value, vref_value, errors);
- }
- } // end parallel write-leveling block for delay high-order bits
+ if (errors) {
+ debug_print("End WLEV_64 while loop: vref_value %d(0x%x), errors 0x%02x\n",
+ vref_value, vref_value, errors);
+ }
+ } // end parallel write-leveling block for delay high-order bits
if (sw_wlevel_hw) { // if we used HW-assist, we did the ECC byte when approp.
VB_PRT(VBL_DEV, "N%d.LMC%d.R%d: HW-assist SWL - no ECC estimate!!!\n",
@@ -7882,13 +7869,13 @@ int init_octeon3_ddr3_interface(bdk_node_t node,
if ((save_byte8 != lmc_wlevel_rank.s.byte3) &&
(save_byte8 != lmc_wlevel_rank.s.byte4))
- {
- // try to calculate a workable delay using SW bytes 3 and 4 and HW byte 8
+ {
+ // try to calculate a workable delay using SW bytes 3 and 4 and HW byte 8
int test_byte8 = save_byte8;
int test_byte8_error;
int byte8_error = 0x1f;
int adder;
- int avg_bytes = divide_nint(lmc_wlevel_rank.s.byte3+lmc_wlevel_rank.s.byte4, 2);
+ int avg_bytes = divide_nint(lmc_wlevel_rank.s.byte3+lmc_wlevel_rank.s.byte4, 2);
for (adder = 0; adder<= 32; adder+=8) {
test_byte8_error = _abs((adder+save_byte8) - avg_bytes);
if (test_byte8_error < byte8_error) {
@@ -7898,8 +7885,8 @@ int init_octeon3_ddr3_interface(bdk_node_t node,
}
#if SW_WL_CHECK_PATCH
- // only do the check if we are not using measured VREF
- if (!measured_vref_flag) {
+ // only do the check if we are not using measured VREF
+ if (!measured_vref_flag) {
test_byte8 &= ~1; /* Use only even settings, rounding down... */
// do validity check on the calculated ECC delay value
@@ -7941,7 +7928,7 @@ int init_octeon3_ddr3_interface(bdk_node_t node,
byte_test_status[8] = WL_SOFTWARE; /* Estimated delay */
}
} else {
- byte_test_status[8] = WL_HARDWARE; /* H/W delay value */
+ byte_test_status[8] = WL_HARDWARE; /* H/W delay value */
lmc_wlevel_rank.s.byte8 = lmc_wlevel_rank.s.byte0; /* ECC is not used */
}
} else { /* if ((ddr_interface_bytemask & 0xff) == 0xff) */
@@ -7970,7 +7957,7 @@ int init_octeon3_ddr3_interface(bdk_node_t node,
/* Vref training loop is only used for DDR4 */
if (ddr_type != DDR4_DRAM)
- break;
+ break;
if (bytes_failed == 0) {
if (vref_values_count == 0) {
@@ -7981,148 +7968,148 @@ int init_octeon3_ddr3_interface(bdk_node_t node,
best_vref_values_count = vref_values_count;
best_vref_values_start = vref_values_start;
debug_print("N%d.LMC%d.R%d: Vref Training (%2d) : 0x%02x <----- ???? -----> 0x%02x\n",
- node, ddr_interface_num,
+ node, ddr_interface_num,
rankx, vref_value, best_vref_values_start,
best_vref_values_start+best_vref_values_count-1);
}
} else {
vref_values_count = 0;
- debug_print("N%d.LMC%d.R%d: Vref Training (%2d) : failed\n",
- node, ddr_interface_num,
- rankx, vref_value);
+ debug_print("N%d.LMC%d.R%d: Vref Training (%2d) : failed\n",
+ node, ddr_interface_num,
+ rankx, vref_value);
}
} /* for (vref_value=0; vref_value<VREF_LIMIT; ++vref_value) */
- /* Determine address of DRAM to test for pass 2 and final test of software write leveling. */
+ /* Determine address of DRAM to test for pass 2 and final test of software write leveling. */
rank_addr = active_rank * (1ull << (pbank_lsb - bunk_enable + (interfaces/2)));
- rank_addr |= (ddr_interface_num<<7); /* Map address into proper interface */
- rank_addr = bdk_numa_get_address(node, rank_addr);
- debug_print("N%d.LMC%d.R%d: Active Rank %d Address: 0x%lx\n",
- node, ddr_interface_num, rankx, active_rank, rank_addr);
+ rank_addr |= (ddr_interface_num<<7); /* Map address into proper interface */
+ rank_addr = bdk_numa_get_address(node, rank_addr);
+ debug_print("N%d.LMC%d.R%d: Active Rank %d Address: 0x%lx\n",
+ node, ddr_interface_num, rankx, active_rank, rank_addr);
- int errors;
+ int errors;
if (bytes_failed) {
#if !DISABLE_SW_WL_PASS_2
- ddr_print("N%d.LMC%d.R%d: Starting SW Write-leveling pass 2\n",
- node, ddr_interface_num, rankx);
+ ddr_print("N%d.LMC%d.R%d: Starting SW Write-leveling pass 2\n",
+ node, ddr_interface_num, rankx);
sw_wl_rank_status = WL_SOFTWARE;
/* If previous s/w fixups failed then retry using s/w write-leveling. */
if (wlevel_bitmask_errors == 0) {
- /* h/w succeeded but previous s/w fixups failed. So retry s/w. */
+ /* h/w succeeded but previous s/w fixups failed. So retry s/w. */
debug_print("N%d.LMC%d.R%d: Retrying software Write-Leveling.\n",
- node, ddr_interface_num, rankx);
+ node, ddr_interface_num, rankx);
}
- { // start parallel write-leveling block for delay low-order bits
- int byte_delay[8];
- int byte_passed[8];
- uint64_t bytemask;
- uint64_t bitmask;
+ { // start parallel write-leveling block for delay low-order bits
+ int byte_delay[8];
+ int byte_passed[8];
+ uint64_t bytemask;
+ uint64_t bitmask;
int wl_offset;
- int bytes_todo;
+ int bytes_todo;
- for (byte = 0; byte < 8; ++byte) {
- byte_passed[byte] = 0;
- }
+ for (byte = 0; byte < 8; ++byte) {
+ byte_passed[byte] = 0;
+ }
- bytes_todo = ddr_interface_bytemask;
+ bytes_todo = ddr_interface_bytemask;
for (wl_offset = sw_wlevel_offset; wl_offset >= 0; --wl_offset) {
- debug_print("Starting wl_offset for-loop: %d\n", wl_offset);
+ debug_print("Starting wl_offset for-loop: %d\n", wl_offset);
- bytemask = 0;
+ bytemask = 0;
- for (byte = 0; byte < 8; ++byte) {
- byte_delay[byte] = 0;
- if (!(bytes_todo & (1 << byte))) // this does not contain fully passed bytes
- continue;
+ for (byte = 0; byte < 8; ++byte) {
+ byte_delay[byte] = 0;
+ if (!(bytes_todo & (1 << byte))) // this does not contain fully passed bytes
+ continue;
- byte_passed[byte] = 0; // reset across passes if not fully passed
- update_wlevel_rank_struct(&lmc_wlevel_rank, byte, 0); // all delays start at 0
- bitmask = ((!ddr_interface_64b) && (byte == 4)) ? 0x0f: 0xff;
- bytemask |= bitmask << (8*byte); // set the bytes bits in the bytemask
- } /* for (byte = 0; byte < 8; ++byte) */
+ byte_passed[byte] = 0; // reset across passes if not fully passed
+ update_wlevel_rank_struct(&lmc_wlevel_rank, byte, 0); // all delays start at 0
+ bitmask = ((!ddr_interface_64b) && (byte == 4)) ? 0x0f: 0xff;
+ bytemask |= bitmask << (8*byte); // set the bytes bits in the bytemask
+ } /* for (byte = 0; byte < 8; ++byte) */
- while (bytemask != 0) { // start a pass if there is any byte lane to test
+ while (bytemask != 0) { // start a pass if there is any byte lane to test
- debug_print("Starting bytemask while-loop: 0x%lx\n", bytemask);
+ debug_print("Starting bytemask while-loop: 0x%lx\n", bytemask);
- // write this set of WL delays
- DRAM_CSR_WRITE(node, BDK_LMCX_WLEVEL_RANKX(ddr_interface_num, rankx), lmc_wlevel_rank.u);
- lmc_wlevel_rank.u = BDK_CSR_READ(node, BDK_LMCX_WLEVEL_RANKX(ddr_interface_num, rankx));
+ // write this set of WL delays
+ DRAM_CSR_WRITE(node, BDK_LMCX_WLEVEL_RANKX(ddr_interface_num, rankx), lmc_wlevel_rank.u);
+ lmc_wlevel_rank.u = BDK_CSR_READ(node, BDK_LMCX_WLEVEL_RANKX(ddr_interface_num, rankx));
- bdk_watchdog_poke();
+ bdk_watchdog_poke();
- // do the test
+ // do the test
if (sw_wlevel_hw)
errors = run_best_hw_patterns(node, ddr_interface_num, rank_addr,
DBTRAIN_TEST, NULL);
else
errors = test_dram_byte(node, ddr_interface_num, rank_addr, bytemask, NULL);
- debug_print("SWL pass 2: test_dram_byte returned 0x%x\n", errors);
-
- // check errors by byte
- for (byte = 0; byte < 8; ++byte) {
- if (!(bytes_todo & (1 << byte)))
- continue;
-
- delay = byte_delay[byte];
- if (errors & (1 << byte)) { // yes, an error
- debug_print(" byte %d delay %2d Errors\n", byte, delay);
- byte_passed[byte] = 0;
- } else { // no error
- byte_passed[byte] += 1;
- if (byte_passed[byte] == (1 + wl_offset)) { /* Look for consecutive working settings */
- debug_print(" byte %d delay %2d FULLY Passed\n", byte, delay);
- if (wl_offset == 1) {
- byte_test_status[byte] = WL_SOFTWARE;
- } else if (wl_offset == 0) {
- byte_test_status[byte] = WL_SOFTWARE1;
- }
- bytemask &= ~(0xffULL << (8*byte)); // test no longer, remove from byte mask this pass
- bytes_todo &= ~(1 << byte); // remove completely from concern
- continue; // on to the next byte, bypass delay updating!!
- } else {
- debug_print(" byte %d delay %2d Passed\n", byte, delay);
- }
- }
- // error or no, here we move to the next delay value for this byte, unless done all delays
- // only a byte that has "fully passed" will bypass around this,
- delay += 2;
- if (delay < 32) {
- update_wlevel_rank_struct(&lmc_wlevel_rank, byte, delay);
- debug_print(" byte %d delay %2d New\n", byte, delay);
- byte_delay[byte] = delay;
- } else {
- // reached max delay, done with this byte
- debug_print(" byte %d delay %2d Exhausted\n", byte, delay);
- bytemask &= ~(0xffULL << (8*byte)); // test no longer, remove from byte mask this pass
- }
- } /* for (byte = 0; byte < 8; ++byte) */
- debug_print("End of for-loop: bytemask 0x%lx\n", bytemask);
-
- } /* while (bytemask != 0) */
- } /* for (wl_offset = sw_wlevel_offset; wl_offset >= 0; --wl_offset) */
-
- for (byte = 0; byte < 8; ++byte) {
- // any bytes left in bytes_todo did not pass
- if (bytes_todo & (1 << byte)) {
- /* Last resort. Use Rlevel settings to estimate
- Wlevel if software write-leveling fails */
- debug_print("Using RLEVEL as WLEVEL estimate for byte %d\n", byte);
- lmc_rlevel_rank.u = BDK_CSR_READ(node, BDK_LMCX_RLEVEL_RANKX(ddr_interface_num, rankx));
- rlevel_to_wlevel(&lmc_rlevel_rank, &lmc_wlevel_rank, byte);
- }
- } /* for (byte = 0; byte < 8; ++byte) */
-
- sw_wl_failed = (bytes_todo != 0);
-
- } // end parallel write-leveling block for delay low-order bits
+ debug_print("SWL pass 2: test_dram_byte returned 0x%x\n", errors);
+
+ // check errors by byte
+ for (byte = 0; byte < 8; ++byte) {
+ if (!(bytes_todo & (1 << byte)))
+ continue;
+
+ delay = byte_delay[byte];
+ if (errors & (1 << byte)) { // yes, an error
+ debug_print(" byte %d delay %2d Errors\n", byte, delay);
+ byte_passed[byte] = 0;
+ } else { // no error
+ byte_passed[byte] += 1;
+ if (byte_passed[byte] == (1 + wl_offset)) { /* Look for consecutive working settings */
+ debug_print(" byte %d delay %2d FULLY Passed\n", byte, delay);
+ if (wl_offset == 1) {
+ byte_test_status[byte] = WL_SOFTWARE;
+ } else if (wl_offset == 0) {
+ byte_test_status[byte] = WL_SOFTWARE1;
+ }
+ bytemask &= ~(0xffULL << (8*byte)); // test no longer, remove from byte mask this pass
+ bytes_todo &= ~(1 << byte); // remove completely from concern
+ continue; // on to the next byte, bypass delay updating!!
+ } else {
+ debug_print(" byte %d delay %2d Passed\n", byte, delay);
+ }
+ }
+ // error or no, here we move to the next delay value for this byte, unless done all delays
+ // only a byte that has "fully passed" will bypass around this,
+ delay += 2;
+ if (delay < 32) {
+ update_wlevel_rank_struct(&lmc_wlevel_rank, byte, delay);
+ debug_print(" byte %d delay %2d New\n", byte, delay);
+ byte_delay[byte] = delay;
+ } else {
+ // reached max delay, done with this byte
+ debug_print(" byte %d delay %2d Exhausted\n", byte, delay);
+ bytemask &= ~(0xffULL << (8*byte)); // test no longer, remove from byte mask this pass
+ }
+ } /* for (byte = 0; byte < 8; ++byte) */
+ debug_print("End of for-loop: bytemask 0x%lx\n", bytemask);
+
+ } /* while (bytemask != 0) */
+ } /* for (wl_offset = sw_wlevel_offset; wl_offset >= 0; --wl_offset) */
+
+ for (byte = 0; byte < 8; ++byte) {
+ // any bytes left in bytes_todo did not pass
+ if (bytes_todo & (1 << byte)) {
+ /* Last resort. Use Rlevel settings to estimate
+ Wlevel if software write-leveling fails */
+ debug_print("Using RLEVEL as WLEVEL estimate for byte %d\n", byte);
+ lmc_rlevel_rank.u = BDK_CSR_READ(node, BDK_LMCX_RLEVEL_RANKX(ddr_interface_num, rankx));
+ rlevel_to_wlevel(&lmc_rlevel_rank, &lmc_wlevel_rank, byte);
+ }
+ } /* for (byte = 0; byte < 8; ++byte) */
+
+ sw_wl_failed = (bytes_todo != 0);
+
+ } // end parallel write-leveling block for delay low-order bits
if (use_ecc) {
/* ECC byte has to be estimated. Take the average of the two surrounding bytes. */
@@ -8141,29 +8128,29 @@ int init_octeon3_ddr3_interface(bdk_node_t node,
if ((ddr_interface_bytemask & (1 << byte)))
continue;
update_wlevel_rank_struct(&lmc_wlevel_rank, byte,
- lmc_wlevel_rank.s.byte0);
+ lmc_wlevel_rank.s.byte0);
byte_test_status[byte] = WL_SOFTWARE;
}
#else /* !DISABLE_SW_WL_PASS_2 */
- // FIXME? the big hammer, did not even try SW WL pass2, assume only chip reset will help
- ddr_print("N%d.LMC%d.R%d: S/W write-leveling pass 1 failed\n",
- node, ddr_interface_num, rankx);
- sw_wl_failed = 1;
+ // FIXME? the big hammer, did not even try SW WL pass2, assume only chip reset will help
+ ddr_print("N%d.LMC%d.R%d: S/W write-leveling pass 1 failed\n",
+ node, ddr_interface_num, rankx);
+ sw_wl_failed = 1;
#endif /* !DISABLE_SW_WL_PASS_2 */
} else { /* if (bytes_failed) */
- // SW WL pass 1 was OK, write the settings
- DRAM_CSR_WRITE(node, BDK_LMCX_WLEVEL_RANKX(ddr_interface_num, rankx), lmc_wlevel_rank.u);
- lmc_wlevel_rank.u = BDK_CSR_READ(node, BDK_LMCX_WLEVEL_RANKX(ddr_interface_num, rankx));
+ // SW WL pass 1 was OK, write the settings
+ DRAM_CSR_WRITE(node, BDK_LMCX_WLEVEL_RANKX(ddr_interface_num, rankx), lmc_wlevel_rank.u);
+ lmc_wlevel_rank.u = BDK_CSR_READ(node, BDK_LMCX_WLEVEL_RANKX(ddr_interface_num, rankx));
#if SW_WL_CHECK_PATCH
- // do validity check on the delay values by running the test 1 more time...
- // FIXME: we really need to check the ECC byte setting here as well,
- // so we need to enable ECC for this test!!!
- // if there are any errors, claim SW WL failure
- {
- uint64_t datamask = (ddr_interface_64b) ? 0xffffffffffffffffULL : 0x00000000ffffffffULL;
+ // do validity check on the delay values by running the test 1 more time...
+ // FIXME: we really need to check the ECC byte setting here as well,
+ // so we need to enable ECC for this test!!!
+ // if there are any errors, claim SW WL failure
+ {
+ uint64_t datamask = (ddr_interface_64b) ? 0xffffffffffffffffULL : 0x00000000ffffffffULL;
// do the test
if (sw_wlevel_hw) {
@@ -8177,18 +8164,18 @@ int init_octeon3_ddr3_interface(bdk_node_t node,
#endif
}
- if (errors) {
- ddr_print("N%d.LMC%d.R%d: Wlevel Rank Final Test errors 0x%x\n",
- node, ddr_interface_num, rankx, errors);
- sw_wl_failed = 1;
- }
- }
+ if (errors) {
+ ddr_print("N%d.LMC%d.R%d: Wlevel Rank Final Test errors 0x%x\n",
+ node, ddr_interface_num, rankx, errors);
+ sw_wl_failed = 1;
+ }
+ }
#endif /* SW_WL_CHECK_PATCH */
- } /* if (bytes_failed) */
+ } /* if (bytes_failed) */
- // FIXME? dump the WL settings, so we get more of a clue as to what happened where
- ddr_print("N%d.LMC%d.R%d: Wlevel Rank %#4x, 0x%016lX : %2d%3s %2d%3s %2d%3s %2d%3s %2d%3s %2d%3s %2d%3s %2d%3s %2d%3s %s\n",
+ // FIXME? dump the WL settings, so we get more of a clue as to what happened where
+ ddr_print("N%d.LMC%d.R%d: Wlevel Rank %#4x, 0x%016llX : %2d%3s %2d%3s %2d%3s %2d%3s %2d%3s %2d%3s %2d%3s %2d%3s %2d%3s %s\n",
node, ddr_interface_num, rankx,
lmc_wlevel_rank.s.status,
lmc_wlevel_rank.u,
@@ -8204,7 +8191,7 @@ int init_octeon3_ddr3_interface(bdk_node_t node,
(sw_wl_rank_status == WL_HARDWARE) ? "" : "(s)"
);
- // finally, check for fatal conditions: either chip reset right here, or return error flag
+ // finally, check for fatal conditions: either chip reset right here, or return error flag
if (((ddr_type == DDR4_DRAM) && (best_vref_values_count == 0)) || sw_wl_failed) {
if (!ddr_disable_chip_reset) { // do chip RESET
error_print("INFO: Short memory test indicates a retry is needed on N%d.LMC%d.R%d. Resetting node...\n",
@@ -8221,7 +8208,7 @@ int init_octeon3_ddr3_interface(bdk_node_t node,
active_rank++;
} /* for (rankx = 0; rankx < dimm_count * 4; rankx++) */
- // Finalize the write-leveling settings
+ // Finalize the write-leveling settings
for (rankx = 0; rankx < dimm_count * 4;rankx++) {
uint64_t value;
int parameter_set = 0;
@@ -8230,20 +8217,6 @@ int init_octeon3_ddr3_interface(bdk_node_t node,
lmc_wlevel_rank.u = BDK_CSR_READ(node, BDK_LMCX_WLEVEL_RANKX(ddr_interface_num, rankx));
- if (bdk_is_platform(BDK_PLATFORM_ASIM)) {
- parameter_set |= 1;
-
- lmc_wlevel_rank.s.byte8 = 0;
- lmc_wlevel_rank.s.byte7 = 0;
- lmc_wlevel_rank.s.byte6 = 0;
- lmc_wlevel_rank.s.byte5 = 0;
- lmc_wlevel_rank.s.byte4 = 0;
- lmc_wlevel_rank.s.byte3 = 0;
- lmc_wlevel_rank.s.byte2 = 0;
- lmc_wlevel_rank.s.byte1 = 0;
- lmc_wlevel_rank.s.byte0 = 0;
- }
-
for (i=0; i<9; ++i) {
if ((s = lookup_env_parameter("ddr%d_wlevel_rank%d_byte%d", ddr_interface_num, rankx, i)) != NULL) {
parameter_set |= 1;
@@ -8262,33 +8235,33 @@ int init_octeon3_ddr3_interface(bdk_node_t node,
if (parameter_set) {
DRAM_CSR_WRITE(node, BDK_LMCX_WLEVEL_RANKX(ddr_interface_num, rankx), lmc_wlevel_rank.u);
lmc_wlevel_rank.u = BDK_CSR_READ(node, BDK_LMCX_WLEVEL_RANKX(ddr_interface_num, rankx));
- display_WL(node, ddr_interface_num, lmc_wlevel_rank, rankx);
+ display_WL(node, ddr_interface_num, lmc_wlevel_rank, rankx);
}
#if WLEXTRAS_PATCH
- if ((rank_mask & 0x0F) != 0x0F) { // if there are unused entries to be filled
- if (rankx < 3) {
- debug_print("N%d.LMC%d.R%d: checking for WLEVEL_RANK unused entries.\n",
- node, ddr_interface_num, rankx);
- if (rankx == 0) { // if rank 0, write ranks 1 and 2 here if empty
- if (!(rank_mask & (1<<1))) { // check that rank 1 is empty
- DRAM_CSR_WRITE(node, BDK_LMCX_WLEVEL_RANKX(ddr_interface_num, 1), lmc_wlevel_rank.u);
- VB_PRT(VBL_DEV, "N%d.LMC%d.R%d: writing WLEVEL_RANK unused entry R%d.\n",
- node, ddr_interface_num, rankx, 1);
- }
- if (!(rank_mask & (1<<2))) { // check that rank 2 is empty
- VB_PRT(VBL_DEV, "N%d.LMC%d.R%d: writing WLEVEL_RANK unused entry R%d.\n",
- node, ddr_interface_num, rankx, 2);
- DRAM_CSR_WRITE(node, BDK_LMCX_WLEVEL_RANKX(ddr_interface_num, 2), lmc_wlevel_rank.u);
- }
- }
- // if rank 0, 1 or 2, write rank 3 here if empty
- if (!(rank_mask & (1<<3))) { // check that rank 3 is empty
- VB_PRT(VBL_DEV, "N%d.LMC%d.R%d: writing WLEVEL_RANK unused entry R%d.\n",
- node, ddr_interface_num, rankx, 3);
- DRAM_CSR_WRITE(node, BDK_LMCX_WLEVEL_RANKX(ddr_interface_num, 3), lmc_wlevel_rank.u);
- }
- }
- }
+ if ((rank_mask & 0x0F) != 0x0F) { // if there are unused entries to be filled
+ if (rankx < 3) {
+ debug_print("N%d.LMC%d.R%d: checking for WLEVEL_RANK unused entries.\n",
+ node, ddr_interface_num, rankx);
+ if (rankx == 0) { // if rank 0, write ranks 1 and 2 here if empty
+ if (!(rank_mask & (1<<1))) { // check that rank 1 is empty
+ DRAM_CSR_WRITE(node, BDK_LMCX_WLEVEL_RANKX(ddr_interface_num, 1), lmc_wlevel_rank.u);
+ VB_PRT(VBL_DEV, "N%d.LMC%d.R%d: writing WLEVEL_RANK unused entry R%d.\n",
+ node, ddr_interface_num, rankx, 1);
+ }
+ if (!(rank_mask & (1<<2))) { // check that rank 2 is empty
+ VB_PRT(VBL_DEV, "N%d.LMC%d.R%d: writing WLEVEL_RANK unused entry R%d.\n",
+ node, ddr_interface_num, rankx, 2);
+ DRAM_CSR_WRITE(node, BDK_LMCX_WLEVEL_RANKX(ddr_interface_num, 2), lmc_wlevel_rank.u);
+ }
+ }
+ // if rank 0, 1 or 2, write rank 3 here if empty
+ if (!(rank_mask & (1<<3))) { // check that rank 3 is empty
+ VB_PRT(VBL_DEV, "N%d.LMC%d.R%d: writing WLEVEL_RANK unused entry R%d.\n",
+ node, ddr_interface_num, rankx, 3);
+ DRAM_CSR_WRITE(node, BDK_LMCX_WLEVEL_RANKX(ddr_interface_num, 3), lmc_wlevel_rank.u);
+ }
+ }
+ }
#endif /* WLEXTRAS_PATCH */
} /* for (rankx = 0; rankx < dimm_count * 4;rankx++) */
@@ -8301,7 +8274,7 @@ int init_octeon3_ddr3_interface(bdk_node_t node,
#if USE_L2_WAYS_LIMIT
/* Restore the l2 set configuration */
- if ((s = lookup_env_parameter("limit_l2_ways")) != NULL) {
+ if ((s = lookup_env_parameter("limit_l2_ways")) != NULL) {
int ways = strtoul(s, NULL, 10);
limit_l2_ways(node, ways, 1);
} else {
@@ -8318,21 +8291,21 @@ int init_octeon3_ddr3_interface(bdk_node_t node,
}
#endif
-#if 1 // was #ifdef CAVIUM_ONLY
+#ifdef CAVIUM_ONLY
{
- int i;
+ int _i;
int setting[9];
bdk_lmcx_dll_ctl3_t ddr_dll_ctl3;
ddr_dll_ctl3.u = BDK_CSR_READ(node, BDK_LMCX_DLL_CTL3(ddr_interface_num));
- for (i=0; i<9; ++i) {
- SET_DDR_DLL_CTL3(dll90_byte_sel, ENCODE_DLL90_BYTE_SEL(i));
- DRAM_CSR_WRITE(node, BDK_LMCX_DLL_CTL3(ddr_interface_num), ddr_dll_ctl3.u);
+ for (_i=0; _i<9; ++_i) {
+ SET_DDR_DLL_CTL3(dll90_byte_sel, ENCODE_DLL90_BYTE_SEL(_i));
+ DRAM_CSR_WRITE(node, BDK_LMCX_DLL_CTL3(ddr_interface_num), ddr_dll_ctl3.u);
BDK_CSR_READ(node, BDK_LMCX_DLL_CTL3(ddr_interface_num));
ddr_dll_ctl3.u = BDK_CSR_READ(node, BDK_LMCX_DLL_CTL3(ddr_interface_num));
- setting[i] = GET_DDR_DLL_CTL3(dll90_setting);
- debug_print("%d. LMC%d_DLL_CTL3[%d] = %016lx %d\n", i, ddr_interface_num,
- GET_DDR_DLL_CTL3(dll90_byte_sel), ddr_dll_ctl3.u, setting[i]);
+ setting[_i] = GET_DDR_DLL_CTL3(dll90_setting);
+ debug_print("%d. LMC%d_DLL_CTL3[%d] = %016lx %d\n", _i, ddr_interface_num,
+ GET_DDR_DLL_CTL3(dll90_byte_sel), ddr_dll_ctl3.u, setting[_i]);
}
VB_PRT(VBL_DEV, "N%d.LMC%d: %-36s : %5d %5d %5d %5d %5d %5d %5d %5d %5d\n",
@@ -8340,7 +8313,7 @@ int init_octeon3_ddr3_interface(bdk_node_t node,
setting[8], setting[7], setting[6], setting[5], setting[4],
setting[3], setting[2], setting[1], setting[0]);
- //BDK_CSR_WRITE(node, BDK_LMCX_DLL_CTL3(ddr_interface_num), save_ddr_dll_ctl3.u);
+ //BDK_CSR_WRITE(node, BDK_LMCX_DLL_CTL3(ddr_interface_num), save_ddr_dll_ctl3.u);
}
#endif /* CAVIUM_ONLY */
@@ -8348,9 +8321,9 @@ int init_octeon3_ddr3_interface(bdk_node_t node,
// FIXME: no need to do these if we are going to auto-tune... ???
process_custom_dll_offsets(node, ddr_interface_num, "ddr_dll_write_offset",
- custom_lmc_config->dll_write_offset, "ddr%d_dll_write_offset_byte%d", 1);
+ custom_lmc_config->dll_write_offset, "ddr%d_dll_write_offset_byte%d", 1);
process_custom_dll_offsets(node, ddr_interface_num, "ddr_dll_read_offset",
- custom_lmc_config->dll_read_offset, "ddr%d_dll_read_offset_byte%d", 2);
+ custom_lmc_config->dll_read_offset, "ddr%d_dll_read_offset_byte%d", 2);
// we want to train write bit-deskew here...
if (! disable_deskew_training) {
@@ -8392,10 +8365,10 @@ int init_octeon3_ddr3_interface(bdk_node_t node,
#if ENABLE_SLOT_CTL_ACCESS
{
- bdk_lmcx_slot_ctl0_t lmc_slot_ctl0;
- bdk_lmcx_slot_ctl1_t lmc_slot_ctl1;
- bdk_lmcx_slot_ctl2_t lmc_slot_ctl2;
- bdk_lmcx_slot_ctl3_t lmc_slot_ctl3;
+ bdk_lmcx_slot_ctl0_t lmc_slot_ctl0;
+ bdk_lmcx_slot_ctl1_t lmc_slot_ctl1;
+ bdk_lmcx_slot_ctl2_t lmc_slot_ctl2;
+ bdk_lmcx_slot_ctl3_t lmc_slot_ctl3;
lmc_slot_ctl0.u = BDK_CSR_READ(node, BDK_LMCX_SLOT_CTL0(ddr_interface_num));
lmc_slot_ctl1.u = BDK_CSR_READ(node, BDK_LMCX_SLOT_CTL1(ddr_interface_num));
@@ -8407,35 +8380,35 @@ int init_octeon3_ddr3_interface(bdk_node_t node,
ddr_print("%-45s : 0x%016lx\n", "LMC_SLOT_CTL2", lmc_slot_ctl2.u);
ddr_print("%-45s : 0x%016lx\n", "LMC_SLOT_CTL3", lmc_slot_ctl3.u);
- // for now, look only for SLOT_CTL1 envvar for override of contents
- if ((s = lookup_env_parameter("ddr%d_slot_ctl1", ddr_interface_num)) != NULL) {
- int slot_ctl1_incr = strtoul(s, NULL, 0);
- // validate the value
- if ((slot_ctl1_incr < 0) || (slot_ctl1_incr > 3)) { // allow 0 for printing only
- error_print("ddr%d_slot_ctl1 illegal value (%d); must be 0-3\n",
- ddr_interface_num, slot_ctl1_incr);
- } else {
+ // for now, look only for SLOT_CTL1 envvar for override of contents
+ if ((s = lookup_env_parameter("ddr%d_slot_ctl1", ddr_interface_num)) != NULL) {
+ int slot_ctl1_incr = strtoul(s, NULL, 0);
+ // validate the value
+ if ((slot_ctl1_incr < 0) || (slot_ctl1_incr > 3)) { // allow 0 for printing only
+ error_print("ddr%d_slot_ctl1 illegal value (%d); must be 0-3\n",
+ ddr_interface_num, slot_ctl1_incr);
+ } else {
#define INCR(csr, chip, field, incr) \
- csr.chip.field = (csr.chip.field < (64 - incr)) ? (csr.chip.field + incr) : 63
-
- // only print original when we are changing it!
- if (slot_ctl1_incr)
- ddr_print("%-45s : 0x%016lx\n", "LMC_SLOT_CTL1", lmc_slot_ctl1.u);
-
- // modify all the SLOT_CTL1 fields by the increment, for now...
- // but make sure the value will not overflow!!!
- INCR(lmc_slot_ctl1, s, r2r_xrank_init, slot_ctl1_incr);
- INCR(lmc_slot_ctl1, s, r2w_xrank_init, slot_ctl1_incr);
- INCR(lmc_slot_ctl1, s, w2r_xrank_init, slot_ctl1_incr);
- INCR(lmc_slot_ctl1, s, w2w_xrank_init, slot_ctl1_incr);
- DRAM_CSR_WRITE(node, BDK_LMCX_SLOT_CTL1(ddr_interface_num), lmc_slot_ctl1.u);
- lmc_slot_ctl1.u = BDK_CSR_READ(node, BDK_LMCX_SLOT_CTL1(ddr_interface_num));
-
- // always print when we are changing it!
- printf("%-45s : 0x%016lx\n", "LMC_SLOT_CTL1", lmc_slot_ctl1.u);
- }
- }
+ csr.chip.field = (csr.chip.field < (64 - incr)) ? (csr.chip.field + incr) : 63
+
+ // only print original when we are changing it!
+ if (slot_ctl1_incr)
+ ddr_print("%-45s : 0x%016lx\n", "LMC_SLOT_CTL1", lmc_slot_ctl1.u);
+
+ // modify all the SLOT_CTL1 fields by the increment, for now...
+ // but make sure the value will not overflow!!!
+ INCR(lmc_slot_ctl1, s, r2r_xrank_init, slot_ctl1_incr);
+ INCR(lmc_slot_ctl1, s, r2w_xrank_init, slot_ctl1_incr);
+ INCR(lmc_slot_ctl1, s, w2r_xrank_init, slot_ctl1_incr);
+ INCR(lmc_slot_ctl1, s, w2w_xrank_init, slot_ctl1_incr);
+ DRAM_CSR_WRITE(node, BDK_LMCX_SLOT_CTL1(ddr_interface_num), lmc_slot_ctl1.u);
+ lmc_slot_ctl1.u = BDK_CSR_READ(node, BDK_LMCX_SLOT_CTL1(ddr_interface_num));
+
+ // always print when we are changing it!
+ printf("%-45s : 0x%016lx\n", "LMC_SLOT_CTL1", lmc_slot_ctl1.u);
+ }
+ }
}
#endif /* ENABLE_SLOT_CTL_ACCESS */
{
@@ -8449,18 +8422,9 @@ int init_octeon3_ddr3_interface(bdk_node_t node,
for (tad=0; tad<num_tads; tad++)
DRAM_CSR_WRITE(node, BDK_L2C_TADX_INT_W1C(tad), BDK_CSR_READ(node, BDK_L2C_TADX_INT_W1C(tad)));
- ddr_print("%-45s : 0x%08lx\n", "LMC_INT",
+ ddr_print("%-45s : 0x%08llx\n", "LMC_INT",
BDK_CSR_READ(node, BDK_LMCX_INT(ddr_interface_num)));
-#if 0
- // NOTE: this must be done for pass 2.x
- // must enable ECC interrupts to get ECC error info in LMCX_INT
- if (! CAVIUM_IS_MODEL(CAVIUM_CN88XX_PASS1_X)) { // added 81xx and 83xx
- DRAM_CSR_WRITE(node, BDK_LMCX_INT_ENA_W1S(ddr_interface_num), -1ULL);
- BDK_CSR_INIT(lmc_int_ena_w1s, node, BDK_LMCX_INT_ENA_W1S(ddr_interface_num));
- ddr_print("%-45s : 0x%08lx\n", "LMC_INT_ENA_W1S", lmc_int_ena_w1s.u);
- }
-#endif
}
// Now we can enable scrambling if desired...
@@ -8503,7 +8467,7 @@ int init_octeon3_ddr3_interface(bdk_node_t node,
lmc_scramble_cfg0.u = strtoull(s, NULL, 0);
lmc_control.s.scramble_ena = 1;
}
- ddr_print("%-45s : 0x%016lx\n", "LMC_SCRAMBLE_CFG0", lmc_scramble_cfg0.u);
+ ddr_print("%-45s : 0x%016llx\n", "LMC_SCRAMBLE_CFG0", lmc_scramble_cfg0.u);
DRAM_CSR_WRITE(node, BDK_LMCX_SCRAMBLE_CFG0(ddr_interface_num), lmc_scramble_cfg0.u);
@@ -8511,20 +8475,20 @@ int init_octeon3_ddr3_interface(bdk_node_t node,
lmc_scramble_cfg1.u = strtoull(s, NULL, 0);
lmc_control.s.scramble_ena = 1;
}
- ddr_print("%-45s : 0x%016lx\n", "LMC_SCRAMBLE_CFG1", lmc_scramble_cfg1.u);
+ ddr_print("%-45s : 0x%016llx\n", "LMC_SCRAMBLE_CFG1", lmc_scramble_cfg1.u);
DRAM_CSR_WRITE(node, BDK_LMCX_SCRAMBLE_CFG1(ddr_interface_num), lmc_scramble_cfg1.u);
if ((s = lookup_env_parameter_ull("ddr_scramble_cfg2")) != NULL) {
lmc_scramble_cfg2.u = strtoull(s, NULL, 0);
lmc_control.s.scramble_ena = 1;
}
- ddr_print("%-45s : 0x%016lx\n", "LMC_SCRAMBLE_CFG2", lmc_scramble_cfg2.u);
+ ddr_print("%-45s : 0x%016llx\n", "LMC_SCRAMBLE_CFG2", lmc_scramble_cfg2.u);
DRAM_CSR_WRITE(node, BDK_LMCX_SCRAMBLE_CFG2(ddr_interface_num), lmc_scramble_cfg2.u);
if ((s = lookup_env_parameter_ull("ddr_ns_ctl")) != NULL) {
lmc_ns_ctl.u = strtoull(s, NULL, 0);
}
- ddr_print("%-45s : 0x%016lx\n", "LMC_NS_CTL", lmc_ns_ctl.u);
+ ddr_print("%-45s : 0x%016llx\n", "LMC_NS_CTL", lmc_ns_ctl.u);
DRAM_CSR_WRITE(node, BDK_LMCX_NS_CTL(ddr_interface_num), lmc_ns_ctl.u);
DRAM_CSR_WRITE(node, BDK_LMCX_CONTROL(ddr_interface_num), lmc_control.u);
diff --git a/src/vendorcode/cavium/bdk/libdram/dram-init-ddr3.h b/src/vendorcode/cavium/bdk/libdram/dram-init-ddr3.h
index ba1060e5e0..2dc3df5b27 100644
--- a/src/vendorcode/cavium/bdk/libdram/dram-init-ddr3.h
+++ b/src/vendorcode/cavium/bdk/libdram/dram-init-ddr3.h
@@ -82,7 +82,7 @@ read_DAC_DBI_settings(int node, int ddr_interface_num,
int dac_or_dbi, int *settings);
extern void
display_DAC_DBI_settings(int node, int ddr_interface_num, int dac_or_dbi,
- int ecc_ena, int *settings, char *title);
+ int ecc_ena, int *settings, const char *title);
#define RODT_OHMS_COUNT 8
#define RTT_NOM_OHMS_COUNT 8
@@ -94,4 +94,5 @@ display_DAC_DBI_settings(int node, int ddr_interface_num, int dac_or_dbi,
extern uint64_t hertz_to_psecs(uint64_t hertz);
extern uint64_t psecs_to_mts(uint64_t psecs);
extern uint64_t mts_to_hertz(uint64_t mts);
-extern uint64_t pretty_psecs_to_mts(uint64_t psecs);
+//extern uint64_t pretty_psecs_to_mts(uint64_t psecs);
+extern unsigned long pretty_psecs_to_mts(uint64_t psecs); /* FIXME(dhendrix) */
diff --git a/src/vendorcode/cavium/bdk/libdram/dram-internal.h b/src/vendorcode/cavium/bdk/libdram/dram-internal.h
index 07fdbcbf54..0b4e8fb3da 100644
--- a/src/vendorcode/cavium/bdk/libdram/dram-internal.h
+++ b/src/vendorcode/cavium/bdk/libdram/dram-internal.h
@@ -46,7 +46,9 @@
* from the libdram directory
*/
-#include "libdram.h"
+/* FIXME(dhendrix): include path */
+//#include "libdram.h"
+#include <libdram/libdram.h>
#include "lib_octeon_shared.h"
#include "dram-print.h"
#include "dram-util.h"
diff --git a/src/vendorcode/cavium/bdk/libdram/dram-l2c.c b/src/vendorcode/cavium/bdk/libdram/dram-l2c.c
index 11112955b2..8dc57189e5 100644
--- a/src/vendorcode/cavium/bdk/libdram/dram-l2c.c
+++ b/src/vendorcode/cavium/bdk/libdram/dram-l2c.c
@@ -39,6 +39,10 @@
#include <bdk.h>
#include "dram-internal.h"
+/* FIXME(dhendrix): added */
+#include <libbdk-hal/bdk-l2c.h>
+#include <libbdk-hal/bdk-utils.h>
+
int limit_l2_ways(bdk_node_t node, int ways, int verbose)
{
int ways_max = bdk_l2c_get_num_assoc(node);
diff --git a/src/vendorcode/cavium/bdk/libdram/dram-print.h b/src/vendorcode/cavium/bdk/libdram/dram-print.h
index 94cdf92fbf..a29ba6bc4c 100644
--- a/src/vendorcode/cavium/bdk/libdram/dram-print.h
+++ b/src/vendorcode/cavium/bdk/libdram/dram-print.h
@@ -69,6 +69,8 @@ extern dram_verbosity_t dram_verbosity;
#define is_verbosity_special(level) (((int)(dram_verbosity & 0xf0) & (level)) != 0)
#define dram_is_verbose(level) (((level) & VBL_SPECIAL) ? is_verbosity_special(level) : is_verbosity_level(level))
+/* FIXME(dhendrix): printf... */
+#if 0
#define VB_PRT(level, format, ...) \
do { \
if (dram_is_verbose(level)) \
@@ -84,3 +86,20 @@ extern dram_verbosity_t dram_verbosity;
#else
#define debug_print(format, ...) do {} while (0)
#endif
+#endif
+#include <console/console.h>
+#define VB_PRT(level, format, ...) \
+ do { \
+ if (dram_is_verbose(level)) \
+ printk(BIOS_DEBUG, format, ##__VA_ARGS__); \
+ } while (0)
+
+#define ddr_print(format, ...) VB_PRT(VBL_NORM, format, ##__VA_ARGS__)
+
+#define error_print(format, ...) printk(BIOS_ERR, format, ##__VA_ARGS__)
+
+#ifdef DEBUG_DEBUG_PRINT
+ #define debug_print(format, ...) printk(BIOS_DEBUG, format, ##__VA_ARGS__)
+#else
+ #define debug_print(format, ...) do {} while (0)
+#endif
diff --git a/src/vendorcode/cavium/bdk/libdram/dram-spd.c b/src/vendorcode/cavium/bdk/libdram/dram-spd.c
index 3717ca1109..6498b85f2e 100644
--- a/src/vendorcode/cavium/bdk/libdram/dram-spd.c
+++ b/src/vendorcode/cavium/bdk/libdram/dram-spd.c
@@ -37,9 +37,16 @@
* ARISING OUT OF USE OR PERFORMANCE OF THE SOFTWARE LIES WITH YOU.
***********************license end**************************************/
#include <bdk.h>
-#include <ctype.h>
#include "dram-internal.h"
+#include <bdk-minimal.h>
+#include <libbdk-arch/bdk-warn.h>
+#include <libbdk-hal/bdk-config.h>
+#include <libbdk-hal/bdk-twsi.h>
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+
/**
* Read the entire contents of a DIMM SPD and store it in the device tree. The
* current DRAM config is also updated, so future SPD accesses used the cached
@@ -52,8 +59,12 @@
*
* @return Zero on success, negative on failure
*/
+static uint8_t spd_bufs[4 * 256]; /* FIXME(dhendrix): storage for SPD buffers, assume DDR4 */
int read_entire_spd(bdk_node_t node, dram_config_t *cfg, int lmc, int dimm)
{
+ /* FIXME(dhendrix): hack to get around using allocated mem */
+ assert(dimm < 4);
+
/* If pointer to data is provided, use it, otherwise read from SPD over twsi */
if (cfg->config[lmc].dimm_config_table[dimm].spd_ptr)
return 0;
@@ -69,13 +80,18 @@ int read_entire_spd(bdk_node_t node, dram_config_t *cfg, int lmc, int dimm)
int64_t dev_type = bdk_twsix_read_ia(node, bus, address, DDR4_SPD_KEY_BYTE_DEVICE_TYPE, 1, 1);
if (dev_type < 0)
return -1; /* No DIMM */
- int spd_size = (dev_type == 0x0c) ? 512 : 256;
-
- /* Allocate storage */
- uint32_t *spd_buf = malloc(spd_size);
- if (!spd_buf)
- return -1;
- uint32_t *ptr = spd_buf;
+ // FIXME: prudolph: Nobody needs 512 byte SPDs...
+ //int spd_size = (dev_type == 0x0c) ? 512 : 256;
+ int spd_size = 256;
+
+ /*
+ * FIXME: Assume DIMM doesn't support
+ * 'Hybrid Module Extended Function Parameters' aka only 256 Byte SPD,
+ * as the code below is broken ...
+ */
+ assert(spd_size == 256);
+ uint8_t *spd_buf = &spd_bufs[dimm * 256];
+ uint32_t *ptr = (uint32_t *)spd_buf;
for (int bank = 0; bank < (spd_size >> 8); bank++)
{
@@ -104,7 +120,9 @@ int read_entire_spd(bdk_node_t node, dram_config_t *cfg, int lmc, int dimm)
}
/* Store the SPD in the device tree */
- bdk_config_set_blob(spd_size, spd_buf, BDK_CONFIG_DDR_SPD_DATA, dimm, lmc, node);
+ /* FIXME(dhendrix): No need for this? cfg gets updated, so the caller
+ * (libdram_config()) has what it needs. */
+// bdk_config_set_blob(spd_size, spd_buf, BDK_CONFIG_DDR_SPD_DATA, dimm, lmc, node);
cfg->config[lmc].dimm_config_table[dimm].spd_ptr = (void*)spd_buf;
return 0;
@@ -350,14 +368,14 @@ static uint32_t get_dimm_checksum(bdk_node_t node, const dimm_config_t *dimm_con
static
void report_common_dimm(bdk_node_t node, const dimm_config_t *dimm_config, int dimm,
- const char **dimm_types, int ddr_type, char *volt_str,
+ const char **dimm_types, int ddr_type, const char *volt_str,
int ddr_interface_num, int num_ranks, int dram_width, int dimm_size_mb)
{
int spd_ecc;
unsigned spd_module_type;
uint32_t serial_number;
char part_number[21]; /* 20 bytes plus string terminator is big enough for either */
- char *sn_str;
+ const char *sn_str;
spd_module_type = get_dimm_module_type(node, dimm_config, ddr_type);
spd_ecc = get_dimm_ecc(node, dimm_config, ddr_type);
@@ -405,7 +423,7 @@ void report_ddr3_dimm(bdk_node_t node, const dimm_config_t *dimm_config,
int dram_width, int dimm_size_mb)
{
int spd_voltage;
- char *volt_str;
+ const char *volt_str;
spd_voltage = read_spd(node, dimm_config, DDR3_SPD_NOMINAL_VOLTAGE);
if ((spd_voltage == 0) || (spd_voltage & 3))
@@ -445,7 +463,7 @@ void report_ddr4_dimm(bdk_node_t node, const dimm_config_t *dimm_config,
int dram_width, int dimm_size_mb)
{
int spd_voltage;
- char *volt_str;
+ const char *volt_str;
spd_voltage = read_spd(node, dimm_config, DDR4_SPD_MODULE_NOMINAL_VOLTAGE);
if ((spd_voltage == 0x01) || (spd_voltage & 0x02))
diff --git a/src/vendorcode/cavium/bdk/libdram/dram-tune-ddr3.c b/src/vendorcode/cavium/bdk/libdram/dram-tune-ddr3.c
index e0e9d4442c..2c6a105dae 100644
--- a/src/vendorcode/cavium/bdk/libdram/dram-tune-ddr3.c
+++ b/src/vendorcode/cavium/bdk/libdram/dram-tune-ddr3.c
@@ -39,6 +39,13 @@
#include <bdk.h>
#include "dram-internal.h"
+#include <string.h>
+#include <lame_string.h> /* for strtoul */
+#include <libbdk-hal/bdk-atomic.h>
+#include <libbdk-hal/bdk-clock.h>
+#include <libbdk-hal/bdk-rng.h>
+#include <libbdk-os/bdk-init.h>
+
// if enhanced verbosity levels are defined, use them
#if defined(VB_PRT)
#define ddr_print2(format, ...) VB_PRT(VBL_FAE, format, ##__VA_ARGS__)
@@ -185,14 +192,14 @@ get_speed_bin(bdk_node_t node, int lmc)
// FIXME: is this reasonable speed "binning"?
if (mts_speed >= 1700) {
- if (mts_speed >= 2000)
- ret = 2;
- else
- ret = 1;
+ if (mts_speed >= 2000)
+ ret = 2;
+ else
+ ret = 1;
}
debug_print("N%d.LMC%d: %s: returning bin %d for MTS %d\n",
- node, lmc, __FUNCTION__, ret, mts_speed);
+ node, lmc, __FUNCTION__, ret, mts_speed);
return ret;
}
@@ -261,25 +268,25 @@ int dram_tuning_mem_xor(bdk_node_t node, int lmc, uint64_t p, uint64_t bitmask,
// add this loop to fill memory with the test pattern first
// loops are ordered so that only entire cachelines are written
for (ii = 0; ii < II_MAX; ii += II_INC) { // FIXME? extend the range of memory tested!!
- for (k = 0; k < K_MAX; k += K_INC) {
- for (j = 0; j < J_MAX; j += J_INC) {
- p1 = p + ii + k + j;
- p2 = p1 + p2offset;
- for (i = 0, ix = 0; i < I_MAX; i += I_INC, ix++) {
+ for (k = 0; k < K_MAX; k += K_INC) {
+ for (j = 0; j < J_MAX; j += J_INC) {
+ p1 = p + ii + k + j;
+ p2 = p1 + p2offset;
+ for (i = 0, ix = 0; i < I_MAX; i += I_INC, ix++) {
- v = dram_tune_test_pattern[ix];
- v1 = v; // write the same thing to both areas
+ v = dram_tune_test_pattern[ix];
+ v1 = v; // write the same thing to both areas
- __bdk_dram_write64(p1 + i, v);
- __bdk_dram_write64(p2 + i, v1);
+ __bdk_dram_write64(p1 + i, v);
+ __bdk_dram_write64(p2 + i, v1);
- }
+ }
#if ENABLE_WBIL2
- BDK_CACHE_WBI_L2(p1);
- BDK_CACHE_WBI_L2(p2);
+ BDK_CACHE_WBI_L2(p1);
+ BDK_CACHE_WBI_L2(p2);
#endif
- }
- }
+ }
+ }
} /* for (ii = 0; ii < (1ULL << 31); ii += (1ULL << 29)) */
#endif
@@ -291,12 +298,12 @@ int dram_tuning_mem_xor(bdk_node_t node, int lmc, uint64_t p, uint64_t bitmask,
// loops are ordered so that only a single 64-bit slot is written to each cacheline at one time,
// then the cachelines are forced out; this should maximize read/write traffic
for (ii = 0; ii < II_MAX; ii += II_INC) { // FIXME? extend the range of memory tested!!
- for (k = 0; k < K_MAX; k += K_INC) {
- for (i = 0; i < I_MAX; i += I_INC) {
- for (j = 0; j < J_MAX; j += J_INC) {
+ for (k = 0; k < K_MAX; k += K_INC) {
+ for (i = 0; i < I_MAX; i += I_INC) {
+ for (j = 0; j < J_MAX; j += J_INC) {
- p1 = p + ii + k + j;
- p2 = p1 + p2offset;
+ p1 = p + ii + k + j;
+ p2 = p1 + p2offset;
#if ENABLE_PREFETCH
if (j < (J_MAX - J_INC)) {
@@ -304,20 +311,20 @@ int dram_tuning_mem_xor(bdk_node_t node, int lmc, uint64_t p, uint64_t bitmask,
BDK_PREFETCH(p2 + J_INC, BDK_CACHE_LINE_SIZE);
}
#endif
-
- v = pattern1 * (p1 + i);
- v1 = v; // write the same thing to both areas
- __bdk_dram_write64(p1 + i, v);
- __bdk_dram_write64(p2 + i, v1);
+ v = pattern1 * (p1 + i);
+ v1 = v; // write the same thing to both areas
+
+ __bdk_dram_write64(p1 + i, v);
+ __bdk_dram_write64(p2 + i, v1);
#if ENABLE_WBIL2
- BDK_CACHE_WBI_L2(p1);
- BDK_CACHE_WBI_L2(p2);
+ BDK_CACHE_WBI_L2(p1);
+ BDK_CACHE_WBI_L2(p2);
#endif
- }
- }
- }
+ }
+ }
+ }
} /* for (ii = 0; ii < (1ULL << 31); ii += (1ULL << 29)) */
BDK_DCACHE_INVALIDATE;
@@ -329,24 +336,24 @@ int dram_tuning_mem_xor(bdk_node_t node, int lmc, uint64_t p, uint64_t bitmask,
for (int burst = 0; burst < 1/* was: dram_tune_use_bursts*/; burst++)
{
- uint64_t this_pattern = bdk_rng_get_random64();
- pattern2 ^= this_pattern;
+ uint64_t this_pattern = bdk_rng_get_random64();
+ pattern2 ^= this_pattern;
/* XOR the data with a random value, applying the change to both
* memory areas.
*/
#if ENABLE_PREFETCH
- BDK_PREFETCH(p , BDK_CACHE_LINE_SIZE);
- BDK_PREFETCH(p + p2offset, BDK_CACHE_LINE_SIZE);
+ BDK_PREFETCH(p , BDK_CACHE_LINE_SIZE);
+ BDK_PREFETCH(p + p2offset, BDK_CACHE_LINE_SIZE);
#endif
- for (ii = 0; ii < II_MAX; ii += II_INC) { // FIXME? extend the range of memory tested!!
- for (k = 0; k < K_MAX; k += K_INC) {
- for (i = 0; i < I_MAX; i += I_INC) { // FIXME: rearranged, did not make much difference?
- for (j = 0; j < J_MAX; j += J_INC) {
+ for (ii = 0; ii < II_MAX; ii += II_INC) { // FIXME? extend the range of memory tested!!
+ for (k = 0; k < K_MAX; k += K_INC) {
+ for (i = 0; i < I_MAX; i += I_INC) { // FIXME: rearranged, did not make much difference?
+ for (j = 0; j < J_MAX; j += J_INC) {
- p1 = p + ii + k + j;
- p2 = p1 + p2offset;
+ p1 = p + ii + k + j;
+ p2 = p1 + p2offset;
#if ENABLE_PREFETCH
if (j < (J_MAX - J_INC)) {
@@ -354,26 +361,26 @@ int dram_tuning_mem_xor(bdk_node_t node, int lmc, uint64_t p, uint64_t bitmask,
BDK_PREFETCH(p2 + J_INC, BDK_CACHE_LINE_SIZE);
}
#endif
-
- v = __bdk_dram_read64(p1 + i) ^ this_pattern;
- v1 = __bdk_dram_read64(p2 + i) ^ this_pattern;
+
+ v = __bdk_dram_read64(p1 + i) ^ this_pattern;
+ v1 = __bdk_dram_read64(p2 + i) ^ this_pattern;
#if ENABLE_WBIL2
- BDK_CACHE_INV_L2(p1);
- BDK_CACHE_INV_L2(p2);
+ BDK_CACHE_INV_L2(p1);
+ BDK_CACHE_INV_L2(p2);
#endif
- __bdk_dram_write64(p1 + i, v);
- __bdk_dram_write64(p2 + i, v1);
+ __bdk_dram_write64(p1 + i, v);
+ __bdk_dram_write64(p2 + i, v1);
#if ENABLE_WBIL2
- BDK_CACHE_WBI_L2(p1);
- BDK_CACHE_WBI_L2(p2);
+ BDK_CACHE_WBI_L2(p1);
+ BDK_CACHE_WBI_L2(p2);
#endif
- }
- }
- }
- } /* for (ii = 0; ii < (1ULL << 31); ii += (1ULL << 29)) */
+ }
+ }
+ }
+ } /* for (ii = 0; ii < (1ULL << 31); ii += (1ULL << 29)) */
BDK_DCACHE_INVALIDATE;
@@ -381,8 +388,8 @@ int dram_tuning_mem_xor(bdk_node_t node, int lmc, uint64_t p, uint64_t bitmask,
node, lmc);
#if ENABLE_PREFETCH
- BDK_PREFETCH(p , BDK_CACHE_LINE_SIZE);
- BDK_PREFETCH(p + p2offset, BDK_CACHE_LINE_SIZE);
+ BDK_PREFETCH(p , BDK_CACHE_LINE_SIZE);
+ BDK_PREFETCH(p + p2offset, BDK_CACHE_LINE_SIZE);
#endif
/* Look for differences in the areas. If there is a mismatch, reset
@@ -390,18 +397,18 @@ int dram_tuning_mem_xor(bdk_node_t node, int lmc, uint64_t p, uint64_t bitmask,
* means that on all subsequent passes the pair of locations remain
* out of sync giving spurious errors.
*/
- // FIXME: change the loop order so that an entire cache line is compared at one time
- // FIXME: this is so that a read error that occurs *anywhere* on the cacheline will be caught,
- // FIXME: rather than comparing only 1 cacheline slot at a time, where an error on a different
- // FIXME: slot will be missed that time around
- // Does the above make sense?
+ // FIXME: change the loop order so that an entire cache line is compared at one time
+ // FIXME: this is so that a read error that occurs *anywhere* on the cacheline will be caught,
+ // FIXME: rather than comparing only 1 cacheline slot at a time, where an error on a different
+ // FIXME: slot will be missed that time around
+ // Does the above make sense?
- for (ii = 0; ii < II_MAX; ii += II_INC) { // FIXME? extend the range of memory tested!!
- for (k = 0; k < K_MAX; k += K_INC) {
- for (j = 0; j < J_MAX; j += J_INC) {
+ for (ii = 0; ii < II_MAX; ii += II_INC) { // FIXME? extend the range of memory tested!!
+ for (k = 0; k < K_MAX; k += K_INC) {
+ for (j = 0; j < J_MAX; j += J_INC) {
- p1 = p + ii + k + j;
- p2 = p1 + p2offset;
+ p1 = p + ii + k + j;
+ p2 = p1 + p2offset;
#if ENABLE_PREFETCH
if (j < (J_MAX - J_INC)) {
@@ -409,15 +416,15 @@ int dram_tuning_mem_xor(bdk_node_t node, int lmc, uint64_t p, uint64_t bitmask,
BDK_PREFETCH(p2 + J_INC, BDK_CACHE_LINE_SIZE);
}
#endif
-
- // process entire cachelines in the innermost loop
- for (i = 0; i < I_MAX; i += I_INC) {
- v = ((p1 + i) * pattern1) ^ pattern2; // FIXME: this should predict what we find...???
- d1 = __bdk_dram_read64(p1 + i);
- d2 = __bdk_dram_read64(p2 + i);
+ // process entire cachelines in the innermost loop
+ for (i = 0; i < I_MAX; i += I_INC) {
+
+ v = ((p1 + i) * pattern1) ^ pattern2; // FIXME: this should predict what we find...???
+ d1 = __bdk_dram_read64(p1 + i);
+ d2 = __bdk_dram_read64(p2 + i);
- xor = ((d1 ^ v) | (d2 ^ v)) & datamask; // union of error bits only in active byte lanes
+ xor = ((d1 ^ v) | (d2 ^ v)) & datamask; // union of error bits only in active byte lanes
if (!xor)
continue;
@@ -426,32 +433,32 @@ int dram_tuning_mem_xor(bdk_node_t node, int lmc, uint64_t p, uint64_t bitmask,
bad_bits[0] |= xor;
//bad_bits[1] |= ~mpr_data1 & 0xffUL; // cannot do ECC here
- int bybit = 1;
- uint64_t bymsk = 0xffULL; // start in byte lane 0
- while (xor != 0) {
- debug_print("ERROR(%03d): [0x%016lX] [0x%016lX] expected 0x%016lX d1 %016lX d2 %016lX\n",
- burst, p1, p2, v, d1, d2);
- if (xor & bymsk) { // error(s) in this lane
- errors |= bybit; // set the byte error bit
- xor &= ~bymsk; // clear byte lane in error bits
- datamask &= ~bymsk; // clear the byte lane in the mask
+ int bybit = 1;
+ uint64_t bymsk = 0xffULL; // start in byte lane 0
+ while (xor != 0) {
+ debug_print("ERROR(%03d): [0x%016lX] [0x%016lX] expected 0x%016lX d1 %016lX d2 %016lX\n",
+ burst, p1, p2, v, d1, d2);
+ if (xor & bymsk) { // error(s) in this lane
+ errors |= bybit; // set the byte error bit
+ xor &= ~bymsk; // clear byte lane in error bits
+ datamask &= ~bymsk; // clear the byte lane in the mask
#if EXIT_WHEN_ALL_LANES_HAVE_ERRORS
- if (datamask == 0) { // nothing left to do
- return errors; // completely done when errors found in all byte lanes in datamask
- }
+ if (datamask == 0) { // nothing left to do
+ return errors; // completely done when errors found in all byte lanes in datamask
+ }
#endif /* EXIT_WHEN_ALL_LANES_HAVE_ERRORS */
- }
- bymsk <<= 8; // move mask into next byte lane
- bybit <<= 1; // move bit into next byte position
- }
- }
+ }
+ bymsk <<= 8; // move mask into next byte lane
+ bybit <<= 1; // move bit into next byte position
+ }
+ }
#if ENABLE_WBIL2
- BDK_CACHE_WBI_L2(p1);
- BDK_CACHE_WBI_L2(p2);
+ BDK_CACHE_WBI_L2(p1);
+ BDK_CACHE_WBI_L2(p2);
#endif
- }
- }
- } /* for (ii = 0; ii < (1ULL << 31); ii += (1ULL << 29)) */
+ }
+ }
+ } /* for (ii = 0; ii < (1ULL << 31); ii += (1ULL << 29)) */
debug_print("N%d.LMC%d: dram_tuning_mem_xor: done TEST loop\n",
node, lmc);
@@ -476,278 +483,6 @@ int dram_tuning_mem_xor(bdk_node_t node, int lmc, uint64_t p, uint64_t bitmask,
#define EXTRACT(v, lsb, width) (((v) >> (lsb)) & ((1ull << (width)) - 1))
#define LMCNO(address, xbits) (EXTRACT(address, 7, xbits) ^ EXTRACT(address, 20, xbits) ^ EXTRACT(address, 12, xbits))
-static int dram_tuning_mem_xor2(uint64_t p, uint64_t bitmask, int xbits)
-{
- uint64_t p1, p2, d1, d2;
- uint64_t v, vpred;
- uint64_t p2offset = dram_tune_rank_offset; // FIXME?
- uint64_t datamask;
- uint64_t xor;
- uint64_t ii;
- uint64_t pattern1 = bdk_rng_get_random64();
- uint64_t pattern2 = 0;
- int errors = 0;
- int errs_by_lmc[4] = { 0,0,0,0 };
- int lmc;
- uint64_t vbase, vincr;
-
- // Byte lanes may be clear in the mask to indicate no testing on that lane.
- datamask = bitmask;
-
- /* Add offset to both test regions to not clobber boot stuff
- * when running from L2 for NAND boot.
- */
- p += AREA_BASE_OFFSET; // make sure base is out of the way of boot
-
- // move the multiplies outside the loop
- vbase = p * pattern1;
- vincr = 8 * pattern1;
-
-#define II_INC (1ULL << 3)
-#define II_MAX (1ULL << 22) // stop where the core ID bits start
-
- // walk the memory areas by 8-byte words
- v = vbase;
- for (ii = 0; ii < II_MAX; ii += II_INC) {
-
- p1 = p + ii;
- p2 = p1 + p2offset;
-
- __bdk_dram_write64(p1, v);
- __bdk_dram_write64(p2, v);
-
- v += vincr;
- }
-
- __bdk_dram_flush_to_mem_range(p , p + II_MAX);
- __bdk_dram_flush_to_mem_range(p + p2offset, p + p2offset + II_MAX);
- BDK_DCACHE_INVALIDATE;
-
- /* Make a series of passes over the memory areas. */
-
- for (int burst = 0; burst < dram_tune_use_bursts; burst++)
- {
- uint64_t this_pattern = bdk_rng_get_random64();
- pattern2 ^= this_pattern;
-
- /* XOR the data with a random value, applying the change to both
- * memory areas.
- */
-#if 0
- BDK_PREFETCH(p , BDK_CACHE_LINE_SIZE);
- BDK_PREFETCH(p + p2offset, BDK_CACHE_LINE_SIZE);
-#endif
- for (ii = 0; ii < II_MAX; ii += II_INC) { // FIXME? extend the range of memory tested!!
-
- p1 = p + ii;
- p2 = p1 + p2offset;
-
- d1 = __bdk_dram_read64(p1) ^ this_pattern;
- d2 = __bdk_dram_read64(p2) ^ this_pattern;
-
- __bdk_dram_write64(p1, d1);
- __bdk_dram_write64(p2, d2);
-
- }
- __bdk_dram_flush_to_mem_range(p , p + II_MAX);
- __bdk_dram_flush_to_mem_range(p + p2offset, p + p2offset + II_MAX);
- BDK_DCACHE_INVALIDATE;
-
- /* Look for differences in the areas. If there is a mismatch, reset
- * both memory locations with the same pattern. Failing to do so
- * means that on all subsequent passes the pair of locations remain
- * out of sync giving spurious errors.
- */
-#if 0
- BDK_PREFETCH(p , BDK_CACHE_LINE_SIZE);
- BDK_PREFETCH(p + p2offset, BDK_CACHE_LINE_SIZE);
-#endif
- vpred = vbase;
- for (ii = 0; ii < II_MAX; ii += II_INC) {
-
- p1 = p + ii;
- p2 = p1 + p2offset;
-
- v = vpred ^ pattern2; // this should predict what we find...
- d1 = __bdk_dram_read64(p1);
- d2 = __bdk_dram_read64(p2);
- vpred += vincr;
-
- xor = ((d1 ^ v) | (d2 ^ v)) & datamask; // union of error bits only in active byte lanes
- if (!xor) // no errors
- continue;
-
- lmc = LMCNO(p1, xbits); // FIXME: LMC should be SAME for p1 and p2!!!
- if (lmc != (int)LMCNO(p2, xbits)) {
- printf("ERROR: LMCs for addresses [0x%016lX] (%lld) and [0x%016lX] (%lld) differ!!!\n",
- p1, LMCNO(p1, xbits), p2, LMCNO(p2, xbits));
- }
- int bybit = 1;
- uint64_t bymsk = 0xffULL; // start in byte lane 0
- while (xor != 0) {
- debug_print("ERROR(%03d): [0x%016lX] [0x%016lX] expected 0x%016lX d1 %016lX d2 %016lX\n",
- burst, p1, p2, v, d1, d2);
- if (xor & bymsk) { // error(s) in this lane
- errs_by_lmc[lmc] |= bybit; // set the byte error bit in the LMCs errors
- errors |= bybit; // set the byte error bit
- xor &= ~bymsk; // clear byte lane in error bits
- //datamask &= ~bymsk; // clear the byte lane in the mask
- }
- bymsk <<= 8; // move mask into next byte lane
- bybit <<= 1; // move bit into next byte position
- } /* while (xor != 0) */
- } /* for (ii = 0; ii < II_MAX; ii += II_INC) */
- } /* for (int burst = 0; burst < dram_tune_use_bursts; burst++) */
-
- // update the global LMC error states
- for (lmc = 0; lmc < 4; lmc++) {
- if (errs_by_lmc[lmc]) {
- bdk_atomic_fetch_and_bset64_nosync(&test_dram_byte_lmc_errs[lmc], errs_by_lmc[lmc]);
- }
- }
-
- return errors;
-}
-
-#if 0
-static int dram_tuning_mem_rows(uint64_t p, uint64_t bitmask)
-{
- uint64_t p1, p2, d1, d2;
- uint64_t v, v1;
- uint64_t p2offset = dram_tune_rank_offset; // FIXME?
- uint64_t datamask;
- uint64_t xor;
- int i, j, k, ii;
- int errors = 0;
- int index;
- uint64_t pattern1 = 0; // FIXME: maybe this could be from a table?
- uint64_t pattern2;
-
- // Byte lanes may be clear in the mask to indicate no testing on that lane.
- datamask = bitmask;
-
- /* Add offset to both test regions to not clobber boot stuff
- * when running from L2 for NAND boot.
- */
- p += 0x10000000; // FIXME? was: 0x4000000; // make sure base is out of the way of cores for tuning
-
- pattern2 = pattern1;
- for (k = 0; k < (1 << 20); k += (1 << 14)) {
- for (j = 0; j < (1 << 12); j += (1 << 9)) {
- for (i = 0; i < (1 << 7); i += 8) {
- index = i + j + k;
- p1 = p + index;
- p2 = p1 + p2offset;
-
- v = pattern2;
- v1 = v; // write the same thing to same slot in both cachelines
- pattern2 = ~pattern2; // flip bits for next slots
-
- __bdk_dram_write64(p1, v);
- __bdk_dram_write64(p2, v1);
- }
-#if 1
- BDK_CACHE_WBI_L2(p1);
- BDK_CACHE_WBI_L2(p2);
-#endif
- }
- }
-
-#if 0
- __bdk_dram_flush_to_mem_range(p, p + (1ULL << 20)); // max_addr is start + where k stops...
- __bdk_dram_flush_to_mem_range(p + p2offset, p + p2offset + (1ULL << 20)); // max_addr is start + where k stops...
-#endif
- BDK_DCACHE_INVALIDATE;
-
- /* Make a series of passes over the memory areas. */
-
- for (int burst = 0; burst < dram_tune_use_bursts; burst++)
- {
- /* just read and flip the bits applying the change to both
- * memory areas.
- */
- for (k = 0; k < (1 << 20); k += (1 << 14)) {
- for (j = 0; j < (1 << 12); j += (1 << 9)) {
- for (i = 0; i < (1 << 7); i += 8) {
- index = i + j + k;
- p1 = p + index;
- p2 = p1 + p2offset;
-
- v = ~__bdk_dram_read64(p1);
- v1 = ~__bdk_dram_read64(p2);
-
- __bdk_dram_write64(p1, v);
- __bdk_dram_write64(p2, v1);
- }
-#if 1
- BDK_CACHE_WBI_L2(p1);
- BDK_CACHE_WBI_L2(p2);
-#endif
- }
- }
-
-#if 0
- __bdk_dram_flush_to_mem_range(p, p + (1ULL << 20)); // max_addr is start + where k stops...
- __bdk_dram_flush_to_mem_range(p + p2offset, p + p2offset + (1ULL << 20)); // max_addr is start + where k stops...
-#endif
- BDK_DCACHE_INVALIDATE;
-
- /* Look for differences in the areas. If there is a mismatch, reset
- * both memory locations with the same pattern. Failing to do so
- * means that on all subsequent passes the pair of locations remain
- * out of sync giving spurious errors.
- */
-
- // FIXME: change the loop order so that an entire cache line is compared at one time
- // FIXME: this is so that a read error that occurs *anywhere* on the cacheline will be caught,
- // FIXME: rather than comparing only 1 cacheline slot at a time, where an error on a different
- // FIXME: slot will be missed that time around
- // Does the above make sense?
-
- pattern2 = ~pattern1; // slots have been flipped by the above loop
-
- for (k = 0; k < (1 << 20); k += (1 << 14)) {
- for (j = 0; j < (1 << 12); j += (1 << 9)) {
- for (i = 0; i < (1 << 7); i += 8) {
- index = i + j + k;
- p1 = p + index;
- p2 = p1 + p2offset;
-
- v = pattern2; // FIXME: this should predict what we find...???
- d1 = __bdk_dram_read64(p1);
- d2 = __bdk_dram_read64(p2);
- pattern2 = ~pattern2; // flip for next slot
-
- xor = ((d1 ^ v) | (d2 ^ v)) & datamask; // union of error bits only in active byte lanes
-
- int bybit = 1;
- uint64_t bymsk = 0xffULL; // start in byte lane 0
- while (xor != 0) {
- debug_print("ERROR(%03d): [0x%016lX] [0x%016lX] expected 0x%016lX d1 %016lX d2 %016lX\n",
- burst, p1, p2, v, d1, d2);
- if (xor & bymsk) { // error(s) in this lane
- errors |= bybit; // set the byte error bit
- xor &= ~bymsk; // clear byte lane in error bits
- datamask &= ~bymsk; // clear the byte lane in the mask
-#if EXIT_WHEN_ALL_LANES_HAVE_ERRORS
- if (datamask == 0) { // nothing left to do
- return errors; // completely done when errors found in all byte lanes in datamask
- }
-#endif /* EXIT_WHEN_ALL_LANES_HAVE_ERRORS */
- }
- bymsk <<= 8; // move mask into next byte lane
- bybit <<= 1; // move bit into next byte position
- }
- }
- }
- }
- pattern1 = ~pattern1; // flip the starting pattern for the next burst
-
- } /* for (int burst = 0; burst < dram_tune_use_bursts; burst++) */
- return errors;
-}
-#endif
-
// cores to use
#define DEFAULT_USE_CORES 44 // FIXME: was (1 << CORE_BITS)
int dram_tune_use_cores = DEFAULT_USE_CORES; // max cores to use, override available
@@ -763,109 +498,6 @@ typedef struct
uint64_t byte_mask;
} test_dram_byte_info_t;
-static void dram_tuning_thread(int arg, void *arg1)
-{
- test_dram_byte_info_t *test_info = arg1;
- int core = arg;
- uint64_t errs;
- bdk_node_t node = test_info->node;
- int num_lmcs, lmc;
-#if 0
- num_lmcs = test_info->num_lmcs;
- // map core numbers into hopefully equal groups per LMC
- lmc = core % num_lmcs;
-#else
- // FIXME: this code should allow running all the cores on a single LMC...
- // if incoming num_lmcs > 0, then use as normal; if < 0 remap to a single LMC
- if (test_info->num_lmcs >= 0) {
- num_lmcs = test_info->num_lmcs;
- // map core numbers into hopefully equal groups per LMC
- lmc = core % num_lmcs;
- } else {
- num_lmcs = 1;
- // incoming num_lmcs is (desired LMC - 10)
- lmc = 10 + test_info->num_lmcs;
- }
-#endif
- uint64_t base_address = 0/* was: (lmc << 7); now done by callee */;
- uint64_t bytemask = test_info->byte_mask;
-
- /* Figure out our work memory range.
- *
- * Note: base_address above just provides the physical offset which determines
- * specific LMC portions of the address space and does not have the node bits set.
- */
- //was: base_address = bdk_numa_get_address(node, base_address); // map to node // now done by callee
- base_address |= (core << CORE_SHIFT); // FIXME: also put full core into address
- if (dram_tune_dimm_offset) { // if multi-slot in some way, choose a DIMM for the core
- base_address |= (core & (1 << (num_lmcs >> 1))) ? dram_tune_dimm_offset : 0;
- }
-
- debug_print("Node %d, core %d, Testing area 1 at 0x%011lx, area 2 at 0x%011lx\n",
- node, core, base_address + AREA_BASE_OFFSET,
- base_address + AREA_BASE_OFFSET + dram_tune_rank_offset);
-
- errs = dram_tuning_mem_xor(node, lmc, base_address, bytemask, NULL);
- //errs = dram_tuning_mem_rows(base_address, bytemask);
-
- /* Report that we're done */
- debug_print("Core %d on LMC %d node %d done with test_dram_byte with 0x%lx errs\n",
- core, lmc, node, errs);
-
- if (errs) {
- bdk_atomic_fetch_and_bset64_nosync(&test_dram_byte_threads_errs, errs);
- bdk_atomic_fetch_and_bset64_nosync(&test_dram_byte_lmc_errs[lmc], errs);
- }
-
- bdk_atomic_add64_nosync(&test_dram_byte_threads_done, 1);
-
- return;
-}
-
-static void dram_tuning_thread2(int arg, void *arg1)
-{
- test_dram_byte_info_t *test_info = arg1;
- int core = arg;
- uint64_t errs;
- bdk_node_t node = test_info->node;
- int num_lmcs = test_info->num_lmcs;
-
- uint64_t base_address = 0; //
- uint64_t bytemask = test_info->byte_mask;
-
- /* Figure out our work memory range.
- *
- * Note: base_address above just provides the physical offset which determines
- * specific portions of the address space and does not have the node bits set.
- */
- base_address = bdk_numa_get_address(node, base_address); // map to node
- base_address |= (core << CORE_SHIFT); // FIXME: also put full core into address
- if (dram_tune_dimm_offset) { // if multi-slot in some way, choose a DIMM for the core
- base_address |= (core & 1) ? dram_tune_dimm_offset : 0;
- }
-
- debug_print("Node %d, core %d, Testing area 1 at 0x%011lx, area 2 at 0x%011lx\n",
- node, core, base_address + AREA_BASE_OFFSET,
- base_address + AREA_BASE_OFFSET + dram_tune_rank_offset);
-
- errs = dram_tuning_mem_xor2(base_address, bytemask, (num_lmcs >> 1)); // 4->2, 2->1, 1->0
- //errs = dram_tuning_mem_rows(base_address, bytemask);
-
- /* Report that we're done */
- debug_print("Core %d on LMC %d node %d done with test_dram_byte with 0x%lx errs\n",
- core, lmc, node, errs);
-
- if (errs) {
- bdk_atomic_fetch_and_bset64_nosync(&test_dram_byte_threads_errs, errs);
- // FIXME: this will have been done already in the called test routine
- //bdk_atomic_fetch_and_bset64_nosync(&test_dram_byte_lmc_errs[lmc], errs);
- }
-
- bdk_atomic_add64_nosync(&test_dram_byte_threads_done, 1);
-
- return;
-}
-
static int dram_tune_use_xor2 = 1; // FIXME: do NOT default to original mem_xor (LMC-based) code
static int
@@ -874,7 +506,6 @@ run_dram_tuning_threads(bdk_node_t node, int num_lmcs, uint64_t bytemask)
test_dram_byte_info_t test_dram_byte_info;
test_dram_byte_info_t *test_info = &test_dram_byte_info;
int total_count = 0;
- __dram_tuning_thread_t thread_p = (dram_tune_use_xor2) ? dram_tuning_thread2 : dram_tuning_thread;
test_info->node = node;
test_info->num_lmcs = num_lmcs;
@@ -890,20 +521,14 @@ run_dram_tuning_threads(bdk_node_t node, int num_lmcs, uint64_t bytemask)
/* Start threads for cores on the node */
if (bdk_numa_exists(node)) {
- debug_print("Starting %d threads for test_dram_byte\n", dram_tune_use_cores);
- for (int core = 0; core < dram_tune_use_cores; core++) {
- if (bdk_thread_create(node, 0, thread_p, core, (void *)test_info, 0)) {
- bdk_error("Failed to create thread %d for test_dram_byte\n", core);
- } else {
- total_count++;
- }
- }
+ /* FIXME(dhendrix): We shouldn't hit this. */
+ die("bdk_numa_exists() is non-zero\n");
}
#if 0
/* Wait for threads to finish */
while (bdk_atomic_get64(&test_dram_byte_threads_done) < total_count)
- bdk_thread_yield();
+ bdk_thread_yield();
#else
#define TIMEOUT_SECS 5 // FIXME: long enough so a pass for a given setting will not print
/* Wait for threads to finish, with progress */
@@ -912,7 +537,7 @@ run_dram_tuning_threads(bdk_node_t node, int num_lmcs, uint64_t bytemask)
uint64_t period = bdk_clock_get_rate(bdk_numa_local(), BDK_CLOCK_TIME) * TIMEOUT_SECS; // FIXME?
uint64_t timeout = bdk_clock_get_count(BDK_CLOCK_TIME) + period;
do {
- bdk_thread_yield();
+// bdk_thread_yield(); /* FIXME(dhendrix): don't yield... */
cur_count = bdk_atomic_get64(&test_dram_byte_threads_done);
cur_time = bdk_clock_get_count(BDK_CLOCK_TIME);
if (cur_time >= timeout) {
@@ -927,136 +552,10 @@ run_dram_tuning_threads(bdk_node_t node, int num_lmcs, uint64_t bytemask)
}
/* These variables count the number of ECC errors. They should only be accessed atomically */
-extern int64_t __bdk_dram_ecc_single_bit_errors[];
+/* FIXME(dhendrix): redundant declaration in original BDK sources */
+//extern int64_t __bdk_dram_ecc_single_bit_errors[];
extern int64_t __bdk_dram_ecc_double_bit_errors[];
-#if 0
-// make the tuning test callable as a standalone
-int
-bdk_run_dram_tuning_test(int node)
-{
- int num_lmcs = __bdk_dram_get_num_lmc(node);
- const char *s;
- int lmc, byte;
- int errors;
- uint64_t start_dram_dclk[4], start_dram_ops[4];
- int save_use_bursts;
-
- // check for the cores on this node, abort if not more than 1 // FIXME?
- dram_tune_max_cores = bdk_get_num_running_cores(node);
- if (dram_tune_max_cores < 2) {
- //bdk_init_cores(node, 0);
- printf("N%d: ERROR: not enough cores to run the DRAM tuning test.\n", node);
- return 0;
- }
-
- // but use only a certain number of cores, at most what is available
- if ((s = getenv("ddr_tune_use_cores")) != NULL) {
- dram_tune_use_cores = strtoul(s, NULL, 0);
- if (dram_tune_use_cores <= 0) // allow 0 or negative to mean all
- dram_tune_use_cores = dram_tune_max_cores;
- }
- if (dram_tune_use_cores > dram_tune_max_cores)
- dram_tune_use_cores = dram_tune_max_cores;
-
- // save the original bursts, so we can replace it with a better number for just testing
- save_use_bursts = dram_tune_use_bursts;
- dram_tune_use_bursts = 1500; // FIXME: hard code bursts for the test here...
-
- // allow override of the test repeats (bursts) per thread create
- if ((s = getenv("ddr_tune_use_bursts")) != NULL) {
- dram_tune_use_bursts = strtoul(s, NULL, 10);
- }
-
- // allow override of the test mem_xor algorithm
- if ((s = getenv("ddr_tune_use_xor2")) != NULL) {
- dram_tune_use_xor2 = !!strtoul(s, NULL, 10);
- }
-
- // FIXME? consult LMC0 only
- BDK_CSR_INIT(lmcx_config, node, BDK_LMCX_CONFIG(0));
- if (lmcx_config.s.rank_ena) { // replace the default offset when there is more than 1 rank...
- dram_tune_rank_offset = 1ull << (28 + lmcx_config.s.pbank_lsb - lmcx_config.s.rank_ena + (num_lmcs/2));
- ddr_print("N%d: run_dram_tuning_test: changing rank offset to 0x%lx\n", node, dram_tune_rank_offset);
- }
- if (lmcx_config.s.init_status & 0x0c) { // bit 2 or 3 set indicates 2 DIMMs
- dram_tune_dimm_offset = 1ull << (28 + lmcx_config.s.pbank_lsb + (num_lmcs/2));
- ddr_print("N%d: run_dram_tuning_test: changing dimm offset to 0x%lx\n", node, dram_tune_dimm_offset);
- }
- int ddr_interface_64b = !lmcx_config.s.mode32b;
-
- // construct the bytemask
- int bytes_todo = (ddr_interface_64b) ? 0xff : 0x0f; // FIXME: hack?
- uint64_t bytemask = 0;
- for (byte = 0; byte < 8; ++byte) {
- uint64_t bitmask;
- if (bytes_todo & (1 << byte)) {
- bitmask = ((!ddr_interface_64b) && (byte == 4)) ? 0x0f: 0xff;
- bytemask |= bitmask << (8*byte); // set the bytes bits in the bytemask
- }
- } /* for (byte = 0; byte < 8; ++byte) */
-
- // print current working values
- ddr_print("N%d: run_dram_tuning_test: max %d cores, use %d cores, use %d bursts.\n",
- node, dram_tune_max_cores, dram_tune_use_cores, dram_tune_use_bursts);
-
- // do the setup on active LMCs
- for (lmc = 0; lmc < num_lmcs; lmc++) {
- // record start cycle CSRs here for utilization measure
- start_dram_dclk[lmc] = BDK_CSR_READ(node, BDK_LMCX_DCLK_CNT(lmc));
- start_dram_ops[lmc] = BDK_CSR_READ(node, BDK_LMCX_OPS_CNT(lmc));
-#if 0
- bdk_atomic_set64(&__bdk_dram_ecc_single_bit_errors[lmc], 0);
- bdk_atomic_set64(&__bdk_dram_ecc_double_bit_errors[lmc], 0);
-#else
- __bdk_dram_ecc_single_bit_errors[lmc] = 0;
- __bdk_dram_ecc_double_bit_errors[lmc] = 0;
-#endif
- } /* for (lmc = 0; lmc < num_lmcs; lmc++) */
-
- bdk_watchdog_poke();
-
- // run the test(s)
- // only 1 call should be enough, let the bursts, etc, control the load...
- errors = run_dram_tuning_threads(node, num_lmcs, bytemask);
-
- /* Check ECC error counters after the test */
- int64_t ecc_single = 0;
- int64_t ecc_double = 0;
- int64_t ecc_single_errs[4];
- int64_t ecc_double_errs[4];
-
- // finally, print the utilizations all together, and sum the ECC errors
- for (lmc = 0; lmc < num_lmcs; lmc++) {
- uint64_t dclk_diff = BDK_CSR_READ(node, BDK_LMCX_DCLK_CNT(lmc)) - start_dram_dclk[lmc];
- uint64_t ops_diff = BDK_CSR_READ(node, BDK_LMCX_OPS_CNT(lmc)) - start_dram_ops[lmc];
- uint64_t percent_x10 = ops_diff * 1000 / dclk_diff;
- printf("N%d.LMC%d: ops %lu, cycles %lu, used %lu.%lu%%\n",
- node, lmc, ops_diff, dclk_diff, percent_x10 / 10, percent_x10 % 10);
-
- ecc_single += (ecc_single_errs[lmc] = bdk_atomic_get64(&__bdk_dram_ecc_single_bit_errors[lmc]));
- ecc_double += (ecc_double_errs[lmc] = bdk_atomic_get64(&__bdk_dram_ecc_double_bit_errors[lmc]));
- } /* for (lmc = 0; lmc < num_lmcs; lmc++) */
-
- /* Always print any ECC errors */
- if (ecc_single || ecc_double) {
- printf("Test \"%s\": ECC errors, %ld/%ld/%ld/%ld corrected, %ld/%ld/%ld/%ld uncorrected\n",
- "DRAM Tuning Test",
- ecc_single_errs[0], ecc_single_errs[1], ecc_single_errs[2], ecc_single_errs[3],
- ecc_double_errs[0], ecc_double_errs[1], ecc_double_errs[2], ecc_double_errs[3]);
- }
- if (errors || ecc_double || ecc_single) {
- printf("Test \"%s\": FAIL: %ld single, %ld double, %d compare errors\n",
- "DRAM Tuning Test", ecc_single, ecc_double, errors);
- }
-
- // restore bursts
- dram_tune_use_bursts = save_use_bursts;
-
- return (errors + ecc_double + ecc_single);
-}
-#endif /* 0 */
-
#define DEFAULT_SAMPLE_GRAN 3 // sample for errors every N offset values
#define MIN_BYTE_OFFSET -63
#define MAX_BYTE_OFFSET +63
@@ -1064,8 +563,8 @@ int dram_tune_use_gran = DEFAULT_SAMPLE_GRAN;
static int
auto_set_dll_offset(bdk_node_t node, int dll_offset_mode,
- int num_lmcs, int ddr_interface_64b,
- int do_tune)
+ int num_lmcs, int ddr_interface_64b,
+ int do_tune)
{
int byte_offset;
//unsigned short result[9];
@@ -1081,17 +580,17 @@ auto_set_dll_offset(bdk_node_t node, int dll_offset_mode,
uint64_t start_dram_ops[4], stop_dram_ops[4];
int errors, tot_errors;
int lmc;
- char *mode_str = (dll_offset_mode == 2) ? "Read" : "Write";
+ const char *mode_str = (dll_offset_mode == 2) ? "Read" : "Write"; /* FIXME(dhendrix): const */
int mode_is_read = (dll_offset_mode == 2);
- char *mode_blk = (dll_offset_mode == 2) ? " " : "";
+ const char *mode_blk = (dll_offset_mode == 2) ? " " : ""; /* FIXME(dhendrix): const */
int start_offset, end_offset, incr_offset;
int speed_bin = get_speed_bin(node, 0); // FIXME: just get from LMC0?
int low_risk_count = 0, needs_review_count = 0;
if (dram_tune_use_gran != DEFAULT_SAMPLE_GRAN) {
- ddr_print2("N%d: Changing sample granularity from %d to %d\n",
- node, DEFAULT_SAMPLE_GRAN, dram_tune_use_gran);
+ ddr_print2("N%d: Changing sample granularity from %d to %d\n",
+ node, DEFAULT_SAMPLE_GRAN, dram_tune_use_gran);
}
// ensure sample is taken at 0
start_offset = MIN_BYTE_OFFSET - (MIN_BYTE_OFFSET % dram_tune_use_gran);
@@ -1109,12 +608,14 @@ auto_set_dll_offset(bdk_node_t node, int dll_offset_mode,
// FIXME? consult LMC0 only
BDK_CSR_INIT(lmcx_config, node, BDK_LMCX_CONFIG(0));
if (lmcx_config.s.rank_ena) { // replace the default offset when there is more than 1 rank...
- dram_tune_rank_offset = 1ull << (28 + lmcx_config.s.pbank_lsb - lmcx_config.s.rank_ena + (num_lmcs/2));
- ddr_print2("N%d: Tuning multiple ranks per DIMM (rank offset 0x%lx).\n", node, dram_tune_rank_offset);
+ dram_tune_rank_offset = 1ull << (28 + lmcx_config.s.pbank_lsb - lmcx_config.s.rank_ena + (num_lmcs/2));
+ /* FIXME(dhendrix): %lx --> %llx */
+ ddr_print2("N%d: Tuning multiple ranks per DIMM (rank offset 0x%llx).\n", node, dram_tune_rank_offset);
}
if (lmcx_config.s.init_status & 0x0c) { // bit 2 or 3 set indicates 2 DIMMs
- dram_tune_dimm_offset = 1ull << (28 + lmcx_config.s.pbank_lsb + (num_lmcs/2));
- ddr_print2("N%d: Tuning multiple DIMMs per channel (DIMM offset 0x%lx)\n", node, dram_tune_dimm_offset);
+ dram_tune_dimm_offset = 1ull << (28 + lmcx_config.s.pbank_lsb + (num_lmcs/2));
+ /* FIXME(dhendrix): %lx --> %llx */
+ ddr_print2("N%d: Tuning multiple DIMMs per channel (DIMM offset 0x%llx)\n", node, dram_tune_dimm_offset);
}
// FIXME? do this for LMC0 only
@@ -1125,76 +626,76 @@ auto_set_dll_offset(bdk_node_t node, int dll_offset_mode,
int bytes_todo = (ddr_interface_64b) ? 0xff : 0x0f;
uint64_t bytemask = 0;
for (byte = 0; byte < 8; ++byte) {
- if (bytes_todo & (1 << byte)) {
- bytemask |= 0xfful << (8*byte); // set the bytes bits in the bytemask
- }
+ if (bytes_todo & (1 << byte)) {
+ bytemask |= 0xfful << (8*byte); // set the bytes bits in the bytemask
+ }
} /* for (byte = 0; byte < 8; ++byte) */
// now loop through selected legal values for the DLL byte offset...
for (byte_offset = start_offset; byte_offset <= end_offset; byte_offset += incr_offset) {
- // do the setup on active LMCs
- for (lmc = 0; lmc < num_lmcs; lmc++) {
- change_dll_offset_enable(node, lmc, 0);
-
- // set all byte lanes at once
- load_dll_offset(node, lmc, dll_offset_mode, byte_offset, 10 /* All bytes at once */);
- // but then clear the ECC byte lane so it should be neutral for the test...
- load_dll_offset(node, lmc, dll_offset_mode, 0, 8);
-
- change_dll_offset_enable(node, lmc, 1);
-
- // record start cycle CSRs here for utilization measure
- start_dram_dclk[lmc] = BDK_CSR_READ(node, BDK_LMCX_DCLK_CNT(lmc));
- start_dram_ops[lmc] = BDK_CSR_READ(node, BDK_LMCX_OPS_CNT(lmc));
- } /* for (lmc = 0; lmc < num_lmcs; lmc++) */
-
- bdk_watchdog_poke();
-
- // run the test(s)
- // only 1 call should be enough, let the bursts, etc, control the load...
- tot_errors = run_dram_tuning_threads(node, num_lmcs, bytemask);
-
- for (lmc = 0; lmc < num_lmcs; lmc++) {
- // record stop cycle CSRs here for utilization measure
- stop_dram_dclk[lmc] = BDK_CSR_READ(node, BDK_LMCX_DCLK_CNT(lmc));
- stop_dram_ops[lmc] = BDK_CSR_READ(node, BDK_LMCX_OPS_CNT(lmc));
-
- // accumulate...
- ops_sum[lmc] += stop_dram_ops[lmc] - start_dram_ops[lmc];
- dclk_sum[lmc] += stop_dram_dclk[lmc] - start_dram_dclk[lmc];
-
- errors = test_dram_byte_lmc_errs[lmc];
-
- // check errors by byte, but not ECC
- for (byte = 0; byte < 8; ++byte) {
- if (!(bytes_todo & (1 << byte))) // is this byte lane to be done
- continue; // no
-
- byte_delay_windows[lmc][byte] <<= 1; // always put in a zero
- if (errors & (1 << byte)) { // yes, an error in this byte lane
- byte_delay_count[lmc][byte] = 0; // stop now always
- } else { // no error in this byte lane
- if (byte_delay_count[lmc][byte] == 0) { // first success, set run start
- byte_delay_start[lmc][byte] = byte_offset;
- }
- byte_delay_count[lmc][byte] += incr_offset; // bump run length
-
- if (byte_delay_count[lmc][byte] > byte_delay_best_count[lmc][byte]) {
- byte_delay_best_count[lmc][byte] = byte_delay_count[lmc][byte];
- byte_delay_best_start[lmc][byte] = byte_delay_start[lmc][byte];
- }
- byte_delay_windows[lmc][byte] |= 1ULL; // for pass, put in a 1
- }
- } /* for (byte = 0; byte < 8; ++byte) */
-
- // only print when there are errors and verbose...
- if (errors) {
- debug_print("DLL %s Offset Test %3d: errors 0x%x\n",
- mode_str, byte_offset, errors);
- }
- } /* for (lmc = 0; lmc < num_lmcs; lmc++) */
+ // do the setup on active LMCs
+ for (lmc = 0; lmc < num_lmcs; lmc++) {
+ change_dll_offset_enable(node, lmc, 0);
+
+ // set all byte lanes at once
+ load_dll_offset(node, lmc, dll_offset_mode, byte_offset, 10 /* All bytes at once */);
+ // but then clear the ECC byte lane so it should be neutral for the test...
+ load_dll_offset(node, lmc, dll_offset_mode, 0, 8);
+
+ change_dll_offset_enable(node, lmc, 1);
+
+ // record start cycle CSRs here for utilization measure
+ start_dram_dclk[lmc] = BDK_CSR_READ(node, BDK_LMCX_DCLK_CNT(lmc));
+ start_dram_ops[lmc] = BDK_CSR_READ(node, BDK_LMCX_OPS_CNT(lmc));
+ } /* for (lmc = 0; lmc < num_lmcs; lmc++) */
+
+ bdk_watchdog_poke();
+
+ // run the test(s)
+ // only 1 call should be enough, let the bursts, etc, control the load...
+ tot_errors = run_dram_tuning_threads(node, num_lmcs, bytemask);
+
+ for (lmc = 0; lmc < num_lmcs; lmc++) {
+ // record stop cycle CSRs here for utilization measure
+ stop_dram_dclk[lmc] = BDK_CSR_READ(node, BDK_LMCX_DCLK_CNT(lmc));
+ stop_dram_ops[lmc] = BDK_CSR_READ(node, BDK_LMCX_OPS_CNT(lmc));
+
+ // accumulate...
+ ops_sum[lmc] += stop_dram_ops[lmc] - start_dram_ops[lmc];
+ dclk_sum[lmc] += stop_dram_dclk[lmc] - start_dram_dclk[lmc];
+
+ errors = test_dram_byte_lmc_errs[lmc];
+
+ // check errors by byte, but not ECC
+ for (byte = 0; byte < 8; ++byte) {
+ if (!(bytes_todo & (1 << byte))) // is this byte lane to be done
+ continue; // no
+
+ byte_delay_windows[lmc][byte] <<= 1; // always put in a zero
+ if (errors & (1 << byte)) { // yes, an error in this byte lane
+ byte_delay_count[lmc][byte] = 0; // stop now always
+ } else { // no error in this byte lane
+ if (byte_delay_count[lmc][byte] == 0) { // first success, set run start
+ byte_delay_start[lmc][byte] = byte_offset;
+ }
+ byte_delay_count[lmc][byte] += incr_offset; // bump run length
+
+ if (byte_delay_count[lmc][byte] > byte_delay_best_count[lmc][byte]) {
+ byte_delay_best_count[lmc][byte] = byte_delay_count[lmc][byte];
+ byte_delay_best_start[lmc][byte] = byte_delay_start[lmc][byte];
+ }
+ byte_delay_windows[lmc][byte] |= 1ULL; // for pass, put in a 1
+ }
+ } /* for (byte = 0; byte < 8; ++byte) */
+
+ // only print when there are errors and verbose...
+ if (errors) {
+ debug_print("DLL %s Offset Test %3d: errors 0x%x\n",
+ mode_str, byte_offset, errors);
+ }
+ } /* for (lmc = 0; lmc < num_lmcs; lmc++) */
} /* for (byte_offset=-63; byte_offset<63; byte_offset += incr_offset) */
@@ -1202,153 +703,154 @@ auto_set_dll_offset(bdk_node_t node, int dll_offset_mode,
// only when margining...
if (!do_tune) {
- printf(" \n");
- printf("-------------------------------------\n");
+ printf(" \n");
+ printf("-------------------------------------\n");
#if 0
- uint32_t mts_speed = (libdram_get_freq_from_pll(node, 0) * 2) / 1000000; // FIXME: sample LMC0
- printf("N%d: Starting %s Timing Margining for %d MT/s.\n", node, mode_str, mts_speed);
+ uint32_t mts_speed = (libdram_get_freq_from_pll(node, 0) * 2) / 1000000; // FIXME: sample LMC0
+ printf("N%d: Starting %s Timing Margining for %d MT/s.\n", node, mode_str, mts_speed);
#else
- printf("N%d: Starting %s Timing Margining.\n", node, mode_str);
+ printf("N%d: Starting %s Timing Margining.\n", node, mode_str);
#endif
- printf(" \n");
+ printf(" \n");
} /* if (!do_tune) */
for (lmc = 0; lmc < num_lmcs; lmc++) {
#if 1
- // FIXME FIXME
- // FIXME: this just makes ECC always show 0
- byte_delay_best_start[lmc][8] = start_offset;
- byte_delay_best_count[lmc][8] = end_offset - start_offset + incr_offset;
+ // FIXME FIXME
+ // FIXME: this just makes ECC always show 0
+ byte_delay_best_start[lmc][8] = start_offset;
+ byte_delay_best_count[lmc][8] = end_offset - start_offset + incr_offset;
#endif
- // disable offsets while we load...
- change_dll_offset_enable(node, lmc, 0);
-
- // only when margining...
- if (!do_tune) {
- // print the heading
- printf(" \n");
- printf("N%d.LMC%d: %s Timing Margin %s : ", node, lmc, mode_str, mode_blk);
- printf(" ECC/8 ");
- for (byte = 7; byte >= 0; byte--) {
- printf(" Byte %d ", byte);
- }
- printf("\n");
- } /* if (!do_tune) */
-
- // print and load the offset values
- // print the windows bit arrays
- // only when margining...
- if (!do_tune) {
+ // disable offsets while we load...
+ change_dll_offset_enable(node, lmc, 0);
+
+ // only when margining...
+ if (!do_tune) {
+ // print the heading
+ printf(" \n");
+ printf("N%d.LMC%d: %s Timing Margin %s : ", node, lmc, mode_str, mode_blk);
+ printf(" ECC/8 ");
+ for (byte = 7; byte >= 0; byte--) {
+ printf(" Byte %d ", byte);
+ }
+ printf("\n");
+ } /* if (!do_tune) */
+
+ // print and load the offset values
+ // print the windows bit arrays
+ // only when margining...
+ if (!do_tune) {
printf("N%d.LMC%d: DLL %s Offset Amount %s : ", node, lmc, mode_str, mode_blk);
} else {
ddr_print("N%d.LMC%d: SW DLL %s Offset Amount %s : ", node, lmc, mode_str, mode_blk);
}
- for (byte = 8; byte >= 0; --byte) { // print in "normal" reverse index order
+ for (byte = 8; byte >= 0; --byte) { // print in "normal" reverse index order
- int count = byte_delay_best_count[lmc][byte];
- if (count == 0)
- count = incr_offset; // should make non-tested ECC byte come out 0
-
- byte_offset = byte_delay_best_start[lmc][byte] +
- ((count - incr_offset) / 2); // adj by incr
+ int count = byte_delay_best_count[lmc][byte];
+ if (count == 0)
+ count = incr_offset; // should make non-tested ECC byte come out 0
- if (!do_tune) { // do counting and special flag if margining
+ byte_offset = byte_delay_best_start[lmc][byte] +
+ ((count - incr_offset) / 2); // adj by incr
+
+ if (!do_tune) { // do counting and special flag if margining
int will_need_review = !is_low_risk_winlen(speed_bin, (count - incr_offset)) &&
- !is_low_risk_offset(speed_bin, byte_offset);
+ !is_low_risk_offset(speed_bin, byte_offset);
printf("%10d%c", byte_offset, (will_need_review) ? '<' :' ');
- if (will_need_review)
- needs_review_count++;
- else
- low_risk_count++;
- } else { // if just tuning, make the printout less lengthy
+ if (will_need_review)
+ needs_review_count++;
+ else
+ low_risk_count++;
+ } else { // if just tuning, make the printout less lengthy
ddr_print("%5d ", byte_offset);
}
- // FIXME? should we be able to override this?
- if (mode_is_read) // for READ offsets, always store what we found
- load_dll_offset(node, lmc, dll_offset_mode, byte_offset, byte);
- else // for WRITE offsets, always store 0
- load_dll_offset(node, lmc, dll_offset_mode, 0, byte);
+ // FIXME? should we be able to override this?
+ if (mode_is_read) // for READ offsets, always store what we found
+ load_dll_offset(node, lmc, dll_offset_mode, byte_offset, byte);
+ else // for WRITE offsets, always store 0
+ load_dll_offset(node, lmc, dll_offset_mode, 0, byte);
- }
- if (!do_tune) {
+ }
+ if (!do_tune) {
printf("\n");
} else {
ddr_print("\n");
}
- // re-enable the offsets now that we are done loading
- change_dll_offset_enable(node, lmc, 1);
-
- // only when margining...
- if (!do_tune) {
- // print the window sizes
- printf("N%d.LMC%d: DLL %s Window Length %s : ", node, lmc, mode_str, mode_blk);
- for (byte = 8; byte >= 0; --byte) { // print in "normal" reverse index order
- int count = byte_delay_best_count[lmc][byte];
- if (count == 0)
- count = incr_offset; // should make non-tested ECC byte come out 0
-
- // do this again since the "needs review" test is an AND...
- byte_offset = byte_delay_best_start[lmc][byte] +
- ((count - incr_offset) / 2); // adj by incr
-
- int will_need_review = !is_low_risk_winlen(speed_bin, (count - incr_offset)) &&
- !is_low_risk_offset(speed_bin, byte_offset);
-
- printf("%10d%c", count - incr_offset, (will_need_review) ? '<' :' ');
- }
- printf("\n");
-
- // print the window extents
- printf("N%d.LMC%d: DLL %s Window Bounds %s : ", node, lmc, mode_str, mode_blk);
- for (byte = 8; byte >= 0; --byte) { // print in "normal" reverse index order
- int start = byte_delay_best_start[lmc][byte];
- int count = byte_delay_best_count[lmc][byte];
- if (count == 0)
- count = incr_offset; // should make non-tested ECC byte come out 0
- printf(" %3d to%3d ", start,
- start + count - incr_offset);
- }
- printf("\n");
+ // re-enable the offsets now that we are done loading
+ change_dll_offset_enable(node, lmc, 1);
+
+ // only when margining...
+ if (!do_tune) {
+ // print the window sizes
+ printf("N%d.LMC%d: DLL %s Window Length %s : ", node, lmc, mode_str, mode_blk);
+ for (byte = 8; byte >= 0; --byte) { // print in "normal" reverse index order
+ int count = byte_delay_best_count[lmc][byte];
+ if (count == 0)
+ count = incr_offset; // should make non-tested ECC byte come out 0
+
+ // do this again since the "needs review" test is an AND...
+ byte_offset = byte_delay_best_start[lmc][byte] +
+ ((count - incr_offset) / 2); // adj by incr
+
+ int will_need_review = !is_low_risk_winlen(speed_bin, (count - incr_offset)) &&
+ !is_low_risk_offset(speed_bin, byte_offset);
+
+ printf("%10d%c", count - incr_offset, (will_need_review) ? '<' :' ');
+ }
+ printf("\n");
+
+ // print the window extents
+ printf("N%d.LMC%d: DLL %s Window Bounds %s : ", node, lmc, mode_str, mode_blk);
+ for (byte = 8; byte >= 0; --byte) { // print in "normal" reverse index order
+ int start = byte_delay_best_start[lmc][byte];
+ int count = byte_delay_best_count[lmc][byte];
+ if (count == 0)
+ count = incr_offset; // should make non-tested ECC byte come out 0
+ printf(" %3d to%3d ", start,
+ start + count - incr_offset);
+ }
+ printf("\n");
#if 0
- // FIXME: should have a way to force these out...
- // print the windows bit arrays
- printf("N%d.LMC%d: DLL %s Window Bitmap%s : ", node, lmc, mode_str, mode_blk);
- for (byte = 8; byte >= 0; --byte) { // print in "normal" reverse index order
- printf("%010lx ", byte_delay_windows[lmc][byte]);
- }
- printf("\n");
+ // FIXME: should have a way to force these out...
+ // print the windows bit arrays
+ printf("N%d.LMC%d: DLL %s Window Bitmap%s : ", node, lmc, mode_str, mode_blk);
+ for (byte = 8; byte >= 0; --byte) { // print in "normal" reverse index order
+ printf("%010lx ", byte_delay_windows[lmc][byte]);
+ }
+ printf("\n");
#endif
- } /* if (!do_tune) */
+ } /* if (!do_tune) */
} /* for (lmc = 0; lmc < num_lmcs; lmc++) */
// only when margining...
if (!do_tune) {
- // print the Summary line(s) here
- printf(" \n");
- printf("N%d: %s Timing Margining Summary : %s ", node, mode_str,
- (needs_review_count > 0) ? "Needs Review" : "Low Risk");
- if (needs_review_count > 0)
- printf("(%d)", needs_review_count);
- printf("\n");
-
- // FIXME??? want to print here: "N0: %s Offsets have been applied already"
-
- printf("-------------------------------------\n");
- printf(" \n");
+ // print the Summary line(s) here
+ printf(" \n");
+ printf("N%d: %s Timing Margining Summary : %s ", node, mode_str,
+ (needs_review_count > 0) ? "Needs Review" : "Low Risk");
+ if (needs_review_count > 0)
+ printf("(%d)", needs_review_count);
+ printf("\n");
+
+ // FIXME??? want to print here: "N0: %s Offsets have been applied already"
+
+ printf("-------------------------------------\n");
+ printf(" \n");
} /* if (!do_tune) */
// FIXME: we probably want this only when doing verbose...
// finally, print the utilizations all together
for (lmc = 0; lmc < num_lmcs; lmc++) {
- uint64_t percent_x10 = ops_sum[lmc] * 1000 / dclk_sum[lmc];
- ddr_print2("N%d.LMC%d: ops %lu, cycles %lu, used %lu.%lu%%\n",
- node, lmc, ops_sum[lmc], dclk_sum[lmc], percent_x10 / 10, percent_x10 % 10);
+ uint64_t percent_x10 = ops_sum[lmc] * 1000 / dclk_sum[lmc];
+ /* FIXME(dhendrix): %lu --> %llu */
+ ddr_print2("N%d.LMC%d: ops %llu, cycles %llu, used %llu.%llu%%\n",
+ node, lmc, ops_sum[lmc], dclk_sum[lmc], percent_x10 / 10, percent_x10 % 10);
} /* for (lmc = 0; lmc < num_lmcs; lmc++) */
// FIXME: only when verbose, or only when there are errors?
@@ -1359,7 +861,7 @@ auto_set_dll_offset(bdk_node_t node, int dll_offset_mode,
tot_errors = run_dram_tuning_threads(node, num_lmcs, bytemask);
debug_print("N%d: %s: Finished running test one last time\n", node, __FUNCTION__);
if (tot_errors)
- ddr_print2("%s Timing Final Test: errors 0x%x\n", mode_str, tot_errors);
+ ddr_print2("%s Timing Final Test: errors 0x%x\n", mode_str, tot_errors);
return (do_tune) ? tot_errors : !!(needs_review_count > 0);
}
@@ -1389,28 +891,30 @@ int perform_dll_offset_tuning(bdk_node_t node, int dll_offset_mode, int do_tune)
// enable any non-running cores on this node
orig_coremask = bdk_get_running_coremask(node);
- ddr_print4("N%d: %s: Starting cores (mask was 0x%lx)\n",
- node, __FUNCTION__, orig_coremask);
- bdk_init_cores(node, ~0ULL & ~orig_coremask);
+ /* FIXME(dhendrix): %lx --> %llx */
+ ddr_print4("N%d: %s: Starting cores (mask was 0x%llx)\n",
+ node, __FUNCTION__, orig_coremask);
+ /* FIXME(dhendrix): don't call bdk_init_cores(). */
+// bdk_init_cores(node, ~0ULL & ~orig_coremask);
dram_tune_max_cores = bdk_get_num_running_cores(node);
// but use only a certain number of cores, at most what is available
if ((s = getenv("ddr_tune_use_cores")) != NULL) {
- dram_tune_use_cores = strtoul(s, NULL, 0);
- if (dram_tune_use_cores <= 0) // allow 0 or negative to mean all
- dram_tune_use_cores = dram_tune_max_cores;
+ dram_tune_use_cores = strtoul(s, NULL, 0);
+ if (dram_tune_use_cores <= 0) // allow 0 or negative to mean all
+ dram_tune_use_cores = dram_tune_max_cores;
}
if (dram_tune_use_cores > dram_tune_max_cores)
- dram_tune_use_cores = dram_tune_max_cores;
+ dram_tune_use_cores = dram_tune_max_cores;
// see if we want to do the tuning more than once per LMC...
if ((s = getenv("ddr_tune_use_loops"))) {
- loops = strtoul(s, NULL, 0);
+ loops = strtoul(s, NULL, 0);
}
// see if we want to change the granularity of the byte_offset sampling
if ((s = getenv("ddr_tune_use_gran"))) {
- dram_tune_use_gran = strtoul(s, NULL, 0);
+ dram_tune_use_gran = strtoul(s, NULL, 0);
}
// allow override of the test repeats (bursts) per thread create
@@ -1422,9 +926,9 @@ int perform_dll_offset_tuning(bdk_node_t node, int dll_offset_mode, int do_tune)
// allow override of Read ODT setting just during the tuning run(s)
if ((s = getenv("ddr_tune_use_rodt")) != NULL) {
int temp = strtoul(s, NULL, 10);
- // validity check
- if (temp >= 0 && temp <= 7)
- dram_tune_use_rodt = temp;
+ // validity check
+ if (temp >= 0 && temp <= 7)
+ dram_tune_use_rodt = temp;
}
#endif
@@ -1432,13 +936,13 @@ int perform_dll_offset_tuning(bdk_node_t node, int dll_offset_mode, int do_tune)
// allow override of the test pattern
// FIXME: a bit simplistic...
if ((s = getenv("ddr_tune_use_pattern")) != NULL) {
- int patno = strtoul(s, NULL, 10);
- if (patno == 2)
- dram_tune_test_pattern = test_pattern_2;
- else if (patno == 3)
- dram_tune_test_pattern = test_pattern_3;
- else // all other values use default
- dram_tune_test_pattern = test_pattern_1;
+ int patno = strtoul(s, NULL, 10);
+ if (patno == 2)
+ dram_tune_test_pattern = test_pattern_2;
+ else if (patno == 3)
+ dram_tune_test_pattern = test_pattern_3;
+ else // all other values use default
+ dram_tune_test_pattern = test_pattern_1;
}
#endif
@@ -1449,24 +953,24 @@ int perform_dll_offset_tuning(bdk_node_t node, int dll_offset_mode, int do_tune)
// print current working values
ddr_print2("N%d: Tuning will use %d cores of max %d cores, and use %d repeats.\n",
- node, dram_tune_use_cores, dram_tune_max_cores,
- dram_tune_use_bursts);
+ node, dram_tune_use_cores, dram_tune_max_cores,
+ dram_tune_use_bursts);
#if USE_L2_WAYS_LIMIT
// see if L2 ways are limited
if ((s = lookup_env_parameter("limit_l2_ways")) != NULL) {
- ways = strtoul(s, NULL, 10);
- ways_print = 1;
+ ways = strtoul(s, NULL, 10);
+ ways_print = 1;
} else {
- ways = bdk_l2c_get_num_assoc(node);
+ ways = bdk_l2c_get_num_assoc(node);
}
#endif
#if 0
// if RODT is to be overridden during tuning, note change
if (dram_tune_use_rodt >= 0) {
- ddr_print("N%d: using RODT %d for tuning.\n",
- node, dram_tune_use_rodt);
+ ddr_print("N%d: using RODT %d for tuning.\n",
+ node, dram_tune_use_rodt);
}
#endif
@@ -1479,21 +983,21 @@ int perform_dll_offset_tuning(bdk_node_t node, int dll_offset_mode, int do_tune)
for (lmc = 0; lmc < num_lmcs; lmc++) {
#if 0
- // if RODT change, save old and set new here...
- if (dram_tune_use_rodt >= 0) {
- comp_ctl2.u = BDK_CSR_READ(node, BDK_LMCX_COMP_CTL2(lmc));
- save_rodt[lmc] = comp_ctl2.s.rodt_ctl;
- comp_ctl2.s.rodt_ctl = dram_tune_use_rodt;
- DRAM_CSR_WRITE(node, BDK_LMCX_COMP_CTL2(lmc), comp_ctl2.u);
- BDK_CSR_READ(node, BDK_LMCX_COMP_CTL2(lmc));
- }
+ // if RODT change, save old and set new here...
+ if (dram_tune_use_rodt >= 0) {
+ comp_ctl2.u = BDK_CSR_READ(node, BDK_LMCX_COMP_CTL2(lmc));
+ save_rodt[lmc] = comp_ctl2.s.rodt_ctl;
+ comp_ctl2.s.rodt_ctl = dram_tune_use_rodt;
+ DRAM_CSR_WRITE(node, BDK_LMCX_COMP_CTL2(lmc), comp_ctl2.u);
+ BDK_CSR_READ(node, BDK_LMCX_COMP_CTL2(lmc));
+ }
#endif
- /* Disable ECC for DRAM tests */
- lmc_config.u = BDK_CSR_READ(node, BDK_LMCX_CONFIG(lmc));
- save_ecc_ena[lmc] = lmc_config.s.ecc_ena;
- lmc_config.s.ecc_ena = 0;
- DRAM_CSR_WRITE(node, BDK_LMCX_CONFIG(lmc), lmc_config.u);
- lmc_config.u = BDK_CSR_READ(node, BDK_LMCX_CONFIG(lmc));
+ /* Disable ECC for DRAM tests */
+ lmc_config.u = BDK_CSR_READ(node, BDK_LMCX_CONFIG(lmc));
+ save_ecc_ena[lmc] = lmc_config.s.ecc_ena;
+ lmc_config.s.ecc_ena = 0;
+ DRAM_CSR_WRITE(node, BDK_LMCX_CONFIG(lmc), lmc_config.u);
+ lmc_config.u = BDK_CSR_READ(node, BDK_LMCX_CONFIG(lmc));
} /* for (lmc = 0; lmc < num_lmcs; lmc++) */
@@ -1505,8 +1009,8 @@ int perform_dll_offset_tuning(bdk_node_t node, int dll_offset_mode, int do_tune)
// testing is done on all LMCs simultaneously
// FIXME: for now, loop here to show what happens multiple times
for (loop = 0; loop < loops; loop++) {
- /* Perform DLL offset tuning */
- errs = auto_set_dll_offset(node, dll_offset_mode, num_lmcs, ddr_interface_64b, do_tune);
+ /* Perform DLL offset tuning */
+ errs = auto_set_dll_offset(node, dll_offset_mode, num_lmcs, ddr_interface_64b, do_tune);
}
#if USE_L2_WAYS_LIMIT
@@ -1518,21 +1022,21 @@ int perform_dll_offset_tuning(bdk_node_t node, int dll_offset_mode, int do_tune)
debug_print("N%d: %s: starting LMCs cleanup.\n", node, __FUNCTION__);
for (lmc = 0; lmc < num_lmcs; lmc++) {
- /* Restore ECC for DRAM tests */
- lmc_config.u = BDK_CSR_READ(node, BDK_LMCX_CONFIG(lmc));
- lmc_config.s.ecc_ena = save_ecc_ena[lmc];
- DRAM_CSR_WRITE(node, BDK_LMCX_CONFIG(lmc), lmc_config.u);
- lmc_config.u = BDK_CSR_READ(node, BDK_LMCX_CONFIG(lmc));
+ /* Restore ECC for DRAM tests */
+ lmc_config.u = BDK_CSR_READ(node, BDK_LMCX_CONFIG(lmc));
+ lmc_config.s.ecc_ena = save_ecc_ena[lmc];
+ DRAM_CSR_WRITE(node, BDK_LMCX_CONFIG(lmc), lmc_config.u);
+ lmc_config.u = BDK_CSR_READ(node, BDK_LMCX_CONFIG(lmc));
#if 0
- // if RODT change, restore old here...
- if (dram_tune_use_rodt >= 0) {
- comp_ctl2.u = BDK_CSR_READ(node, BDK_LMCX_COMP_CTL2(lmc));
- comp_ctl2.s.rodt_ctl = save_rodt[lmc];
- DRAM_CSR_WRITE(node, BDK_LMCX_COMP_CTL2(lmc), comp_ctl2.u);
- BDK_CSR_READ(node, BDK_LMCX_COMP_CTL2(lmc));
- }
+ // if RODT change, restore old here...
+ if (dram_tune_use_rodt >= 0) {
+ comp_ctl2.u = BDK_CSR_READ(node, BDK_LMCX_COMP_CTL2(lmc));
+ comp_ctl2.s.rodt_ctl = save_rodt[lmc];
+ DRAM_CSR_WRITE(node, BDK_LMCX_COMP_CTL2(lmc), comp_ctl2.u);
+ BDK_CSR_READ(node, BDK_LMCX_COMP_CTL2(lmc));
+ }
#endif
- // finally, see if there are any read offset overrides after tuning
+ // finally, see if there are any read offset overrides after tuning
// FIXME: provide a way to do write offsets also??
if (dll_offset_mode == 2) {
for (int by = 0; by < 9; by++) {
@@ -1551,20 +1055,24 @@ int perform_dll_offset_tuning(bdk_node_t node, int dll_offset_mode, int do_tune)
#if 0
// if RODT was overridden during tuning, note restore
if (dram_tune_use_rodt >= 0) {
- ddr_print("N%d: restoring RODT %d after tuning.\n",
- node, save_rodt[0]); // FIXME? use LMC0
+ ddr_print("N%d: restoring RODT %d after tuning.\n",
+ node, save_rodt[0]); // FIXME? use LMC0
}
#endif
// put any cores on this node, that were not running at the start, back into reset
- uint64_t reset_coremask = bdk_get_running_coremask(node) & ~orig_coremask;
+ /* FIXME(dhendrix): don't reset cores... */
+// uint64_t reset_coremask = bdk_get_running_coremask(node) & ~orig_coremask;
+ uint64_t reset_coremask = 0;
if (reset_coremask) {
- ddr_print4("N%d: %s: Stopping cores 0x%lx\n", node, __FUNCTION__,
- reset_coremask);
- bdk_reset_cores(node, reset_coremask);
+ /* FIXME(dhendrix): %lx --> %llx */
+ ddr_print4("N%d: %s: Stopping cores 0x%llx\n", node, __FUNCTION__,
+ reset_coremask);
+ bdk_reset_cores(node, reset_coremask);
} else {
- ddr_print4("N%d: %s: leaving cores set to 0x%lx\n", node, __FUNCTION__,
- orig_coremask);
+ /* FIXME(dhendrix): %lx --> %llx */
+ ddr_print4("N%d: %s: leaving cores set to 0x%llx\n", node, __FUNCTION__,
+ orig_coremask);
}
return errs;
@@ -1656,7 +1164,8 @@ setup_lfsr_pattern(bdk_node_t node, int lmc, uint64_t data)
DRAM_CSR_WRITE(node, BDK_LMCX_CHAR_CTL(lmc), char_ctl.u);
}
-int
+/* FIXME(dhendrix): made static to avoid need for prototype */
+static int
choose_best_hw_patterns(bdk_node_t node, int lmc, int mode)
{
int new_mode = mode;
@@ -1705,7 +1214,7 @@ run_best_hw_patterns(bdk_node_t node, int lmc, uint64_t phys_addr,
if (mode == DBTRAIN_LFSR) {
setup_lfsr_pattern(node, lmc, 0);
errors = test_dram_byte_hw(node, lmc, phys_addr, mode, xor_data);
- VB_PRT(VBL_DEV2, "%s: LFSR at A:0x%012lx errors 0x%x\n",
+ VB_PRT(VBL_DEV2, "%s: LFSR at A:0x%012llx errors 0x%x\n",
__FUNCTION__, phys_addr, errors);
} else {
for (pattern = 0; pattern < NUM_BYTE_PATTERNS; pattern++) {
@@ -1714,7 +1223,7 @@ run_best_hw_patterns(bdk_node_t node, int lmc, uint64_t phys_addr,
errs = test_dram_byte_hw(node, lmc, phys_addr, mode, xor_data);
- VB_PRT(VBL_DEV2, "%s: PATTERN %d at A:0x%012lx errors 0x%x\n",
+ VB_PRT(VBL_DEV2, "%s: PATTERN %d at A:0x%012llx errors 0x%x\n",
__FUNCTION__, pattern, phys_addr, errs);
errors |= errs;
@@ -1738,7 +1247,7 @@ hw_assist_test_dll_offset(bdk_node_t node, int dll_offset_mode,
int pattern;
const uint64_t *pattern_p;
int byte;
- char *mode_str = (dll_offset_mode == 2) ? "Read" : "Write";
+ const char *mode_str = (dll_offset_mode == 2) ? "Read" : "Write";
int pat_best_offset[9];
uint64_t phys_addr;
int pat_beg, pat_end;
@@ -1769,7 +1278,7 @@ hw_assist_test_dll_offset(bdk_node_t node, int dll_offset_mode,
memset(new_best_offset, 0, sizeof(new_best_offset));
for (pattern = 0; pattern < NUM_BYTE_PATTERNS; pattern++) {
- memset(pat_best_offset, 0, sizeof(pat_best_offset));
+ memset(pat_best_offset, 0, sizeof(pat_best_offset));
if (mode == DBTRAIN_TEST) {
pattern_p = byte_patterns[pattern];
@@ -1778,47 +1287,47 @@ hw_assist_test_dll_offset(bdk_node_t node, int dll_offset_mode,
setup_lfsr_pattern(node, lmc, 0);
}
- // now loop through all legal values for the DLL byte offset...
+ // now loop through all legal values for the DLL byte offset...
#define BYTE_OFFSET_INCR 3 // FIXME: make this tunable?
- tot_errors = 0;
+ tot_errors = 0;
- memset(rank_delay_count, 0, sizeof(rank_delay_count));
- memset(rank_delay_start, 0, sizeof(rank_delay_start));
- memset(rank_delay_best_count, 0, sizeof(rank_delay_best_count));
- memset(rank_delay_best_start, 0, sizeof(rank_delay_best_start));
+ memset(rank_delay_count, 0, sizeof(rank_delay_count));
+ memset(rank_delay_start, 0, sizeof(rank_delay_start));
+ memset(rank_delay_best_count, 0, sizeof(rank_delay_best_count));
+ memset(rank_delay_best_start, 0, sizeof(rank_delay_best_start));
- for (byte_offset = -63; byte_offset < 64; byte_offset += BYTE_OFFSET_INCR) {
+ for (byte_offset = -63; byte_offset < 64; byte_offset += BYTE_OFFSET_INCR) {
- // do the setup on the active LMC
- // set the bytelanes DLL offsets
- change_dll_offset_enable(node, lmc, 0);
- load_dll_offset(node, lmc, dll_offset_mode, byte_offset, bytelane); // FIXME? bytelane?
- change_dll_offset_enable(node, lmc, 1);
+ // do the setup on the active LMC
+ // set the bytelanes DLL offsets
+ change_dll_offset_enable(node, lmc, 0);
+ load_dll_offset(node, lmc, dll_offset_mode, byte_offset, bytelane); // FIXME? bytelane?
+ change_dll_offset_enable(node, lmc, 1);
- bdk_watchdog_poke();
+ bdk_watchdog_poke();
- // run the test on each rank
- // only 1 call per rank should be enough, let the bursts, loops, etc, control the load...
-
- off_errors = 0; // errors for this byte_offset, all ranks
+ // run the test on each rank
+ // only 1 call per rank should be enough, let the bursts, loops, etc, control the load...
+
+ off_errors = 0; // errors for this byte_offset, all ranks
active_ranks = 0;
- for (rankx = 0; rankx < 4; rankx++) {
+ for (rankx = 0; rankx < 4; rankx++) {
if (!(rank_mask & (1 << rankx)))
continue;
- phys_addr = hw_rank_offset * active_ranks;
- // FIXME: now done by test_dram_byte_hw()
+ phys_addr = hw_rank_offset * active_ranks;
+ // FIXME: now done by test_dram_byte_hw()
//phys_addr |= (lmc << 7);
//phys_addr = bdk_numa_get_address(node, phys_addr); // map to node
active_ranks++;
// NOTE: return is a now a bitmask of the erroring bytelanes..
- errors[rankx] = test_dram_byte_hw(node, lmc, phys_addr, mode, NULL);
+ errors[rankx] = test_dram_byte_hw(node, lmc, phys_addr, mode, NULL);
for (byte = byte_lo; byte <= byte_hi; byte++) { // do bytelane(s)
@@ -1826,7 +1335,7 @@ hw_assist_test_dll_offset(bdk_node_t node, int dll_offset_mode,
if (errors[rankx] & (1 << byte)) { // yes, an error in the byte lane in this rank
off_errors |= (1 << byte);
- ddr_print5("N%d.LMC%d.R%d: Bytelane %d DLL %s Offset Test %3d: Address 0x%012lx errors 0x%x\n",
+ ddr_print5("N%d.LMC%d.R%d: Bytelane %d DLL %s Offset Test %3d: Address 0x%012llx errors 0x%x\n",
node, lmc, rankx, bytelane, mode_str,
byte_offset, phys_addr, errors[rankx]);
@@ -1854,13 +1363,13 @@ hw_assist_test_dll_offset(bdk_node_t node, int dll_offset_mode,
}
}
} /* for (byte = byte_lo; byte <= byte_hi; byte++) */
- } /* for (rankx = 0; rankx < 4; rankx++) */
+ } /* for (rankx = 0; rankx < 4; rankx++) */
- tot_errors |= off_errors;
+ tot_errors |= off_errors;
- } /* for (byte_offset = -63; byte_offset < 64; byte_offset += BYTE_OFFSET_INCR) */
+ } /* for (byte_offset = -63; byte_offset < 64; byte_offset += BYTE_OFFSET_INCR) */
- // now choose the best byte_offsets for this pattern according to the best windows of the tested ranks
+ // now choose the best byte_offsets for this pattern according to the best windows of the tested ranks
// calculate offset by constructing an average window from the rank windows
for (byte = byte_lo; byte <= byte_hi; byte++) {
@@ -1928,7 +1437,7 @@ hw_assist_test_dll_offset(bdk_node_t node, int dll_offset_mode,
// print whether there are errors or not, but only when verbose...
tot_errors = run_test_dram_byte_threads(node, num_lmcs, bytemask);
printf("N%d.LMC%d: Bytelane %d DLL %s Offset Final Test: errors 0x%x\n",
- node, lmc, bytelane, mode_str, tot_errors);
+ node, lmc, bytelane, mode_str, tot_errors);
#endif
}
@@ -1946,7 +1455,7 @@ int perform_HW_dll_offset_tuning(bdk_node_t node, int dll_offset_mode, int bytel
// see if we want to do the tuning more than once per LMC...
if ((s = getenv("ddr_tune_ecc_loops"))) {
- loops = strtoul(s, NULL, 0);
+ loops = strtoul(s, NULL, 0);
}
// allow override of the test repeats (bursts)
@@ -1956,8 +1465,8 @@ int perform_HW_dll_offset_tuning(bdk_node_t node, int dll_offset_mode, int bytel
// print current working values
ddr_print2("N%d: H/W Tuning for bytelane %d will use %d loops, %d bursts, and %d patterns.\n",
- node, bytelane, loops, dram_tune_byte_bursts,
- NUM_BYTE_PATTERNS);
+ node, bytelane, loops, dram_tune_byte_bursts,
+ NUM_BYTE_PATTERNS);
// FIXME? get flag from LMC0 only
lmc_config.u = BDK_CSR_READ(node, BDK_LMCX_CONFIG(0));
@@ -1966,42 +1475,42 @@ int perform_HW_dll_offset_tuning(bdk_node_t node, int dll_offset_mode, int bytel
for (lmc = 0; lmc < num_lmcs; lmc++) {
- ddr_print4("N%d: H/W Tuning: starting LMC%d bytelane %d tune.\n", node, lmc, bytelane);
-
- /* Enable ECC for the HW tests */
- // NOTE: we do enable ECC, but the HW tests used will not generate "visible" errors
- lmc_config.u = BDK_CSR_READ(node, BDK_LMCX_CONFIG(lmc));
- save_ecc_ena[lmc] = lmc_config.s.ecc_ena;
- lmc_config.s.ecc_ena = 1;
- DRAM_CSR_WRITE(node, BDK_LMCX_CONFIG(lmc), lmc_config.u);
- lmc_config.u = BDK_CSR_READ(node, BDK_LMCX_CONFIG(lmc));
-
- // testing is done on a single LMC at a time
- // FIXME: for now, loop here to show what happens multiple times
- for (loop = 0; loop < loops; loop++) {
- /* Perform DLL offset tuning */
- //auto_set_dll_offset(node, 1 /* 1=write */, lmc, bytelane);
- hw_assist_test_dll_offset(node, 2 /* 2=read */, lmc, bytelane);
- }
-
- // perform cleanup on active LMC
- ddr_print4("N%d: H/W Tuning: finishing LMC%d bytelane %d tune.\n", node, lmc, bytelane);
-
- /* Restore ECC for DRAM tests */
- lmc_config.u = BDK_CSR_READ(node, BDK_LMCX_CONFIG(lmc));
- lmc_config.s.ecc_ena = save_ecc_ena[lmc];
- DRAM_CSR_WRITE(node, BDK_LMCX_CONFIG(lmc), lmc_config.u);
- lmc_config.u = BDK_CSR_READ(node, BDK_LMCX_CONFIG(lmc));
-
- // finally, see if there are any read offset overrides after tuning
- for (int by = 0; by < 9; by++) {
- if ((s = lookup_env_parameter("ddr%d_tune_byte%d", lmc, by)) != NULL) {
- int dllro = strtoul(s, NULL, 10);
- change_dll_offset_enable(node, lmc, 0);
- load_dll_offset(node, lmc, 2 /* 2=read */, dllro, by);
- change_dll_offset_enable(node, lmc, 1);
- }
- }
+ ddr_print4("N%d: H/W Tuning: starting LMC%d bytelane %d tune.\n", node, lmc, bytelane);
+
+ /* Enable ECC for the HW tests */
+ // NOTE: we do enable ECC, but the HW tests used will not generate "visible" errors
+ lmc_config.u = BDK_CSR_READ(node, BDK_LMCX_CONFIG(lmc));
+ save_ecc_ena[lmc] = lmc_config.s.ecc_ena;
+ lmc_config.s.ecc_ena = 1;
+ DRAM_CSR_WRITE(node, BDK_LMCX_CONFIG(lmc), lmc_config.u);
+ lmc_config.u = BDK_CSR_READ(node, BDK_LMCX_CONFIG(lmc));
+
+ // testing is done on a single LMC at a time
+ // FIXME: for now, loop here to show what happens multiple times
+ for (loop = 0; loop < loops; loop++) {
+ /* Perform DLL offset tuning */
+ //auto_set_dll_offset(node, 1 /* 1=write */, lmc, bytelane);
+ hw_assist_test_dll_offset(node, 2 /* 2=read */, lmc, bytelane);
+ }
+
+ // perform cleanup on active LMC
+ ddr_print4("N%d: H/W Tuning: finishing LMC%d bytelane %d tune.\n", node, lmc, bytelane);
+
+ /* Restore ECC for DRAM tests */
+ lmc_config.u = BDK_CSR_READ(node, BDK_LMCX_CONFIG(lmc));
+ lmc_config.s.ecc_ena = save_ecc_ena[lmc];
+ DRAM_CSR_WRITE(node, BDK_LMCX_CONFIG(lmc), lmc_config.u);
+ lmc_config.u = BDK_CSR_READ(node, BDK_LMCX_CONFIG(lmc));
+
+ // finally, see if there are any read offset overrides after tuning
+ for (int by = 0; by < 9; by++) {
+ if ((s = lookup_env_parameter("ddr%d_tune_byte%d", lmc, by)) != NULL) {
+ int dllro = strtoul(s, NULL, 10);
+ change_dll_offset_enable(node, lmc, 0);
+ load_dll_offset(node, lmc, 2 /* 2=read */, dllro, by);
+ change_dll_offset_enable(node, lmc, 1);
+ }
+ }
} /* for (lmc = 0; lmc < num_lmcs; lmc++) */
diff --git a/src/vendorcode/cavium/bdk/libdram/dram-util.h b/src/vendorcode/cavium/bdk/libdram/dram-util.h
index f8ab6c1552..c9a96ba5ae 100644
--- a/src/vendorcode/cavium/bdk/libdram/dram-util.h
+++ b/src/vendorcode/cavium/bdk/libdram/dram-util.h
@@ -42,6 +42,8 @@
* are not meant for users's of the libdram API.
*/
+#if 0
+/* FIXME(dhendrix): min/max are defined in stdlib.h */
/**
* Standard min(a,b) macro
*/
@@ -56,6 +58,7 @@
#define max(X, Y) \
({ typeof (X) __x = (X); typeof(Y) __y = (Y); \
(__x > __y) ? __x : __y; })
+#endif
/**
* Absolute value of an integer
diff --git a/src/vendorcode/cavium/bdk/libdram/lib_octeon_shared.c b/src/vendorcode/cavium/bdk/libdram/lib_octeon_shared.c
index cdc799744f..747c0e8767 100644
--- a/src/vendorcode/cavium/bdk/libdram/lib_octeon_shared.c
+++ b/src/vendorcode/cavium/bdk/libdram/lib_octeon_shared.c
@@ -43,6 +43,10 @@
#include "libbdk-arch/bdk-csrs-l2c.h"
#include "dram-internal.h"
+#include "dram-env.h"
+#include <libbdk-hal/bdk-rng.h>
+#include <lame_string.h>
+
/* Define DDR_DEBUG to debug the DDR interface. This also enables the
** output necessary for review by Cavium Inc., Inc. */
/* #define DDR_DEBUG */
@@ -166,8 +170,8 @@ static int init_octeon_dram_interface(bdk_node_t node,
}
}
- error_print("N%d.LMC%d Configuration Completed: %d MB\n",
- node, ddr_interface_num, mem_size_mbytes);
+ printf("N%d.LMC%d Configuration Completed: %d MB\n",
+ node, ddr_interface_num, mem_size_mbytes);
return mem_size_mbytes;
}
@@ -503,7 +507,7 @@ int test_dram_byte_hw(bdk_node_t node, int ddr_interface_num,
errors = 0;
bdk_dram_address_extract_info(p, &node_address, &lmc, &dimm, &prank, &lrank, &bank, &row, &col);
- VB_PRT(VBL_DEV2, "test_dram_byte_hw: START at A:0x%012lx, N%d L%d D%d R%d/%d B%1x Row:%05x Col:%05x\n",
+ VB_PRT(VBL_DEV2, "test_dram_byte_hw: START at A:0x%012llx, N%d L%d D%d R%d/%d B%1x Row:%05x Col:%05x\n",
p, node_address, lmc, dimm, prank, lrank, bank, row, col);
// only check once per call, and ignore if no match...
@@ -540,7 +544,7 @@ int test_dram_byte_hw(bdk_node_t node, int ddr_interface_num,
p1 = p + k;
bdk_dram_address_extract_info(p1, &node_address, &lmc, &dimm, &prank, &lrank, &bank, &row, &col);
- VB_PRT(VBL_DEV3, "test_dram_byte_hw: NEXT interation at A:0x%012lx, N%d L%d D%d R%d/%d B%1x Row:%05x Col:%05x\n",
+ VB_PRT(VBL_DEV3, "test_dram_byte_hw: NEXT interation at A:0x%012llx, N%d L%d D%d R%d/%d B%1x Row:%05x Col:%05x\n",
p1, node_address, lmc, dimm, prank, lrank, bank, row, col);
/*
@@ -1013,7 +1017,7 @@ int initialize_ddr_clock(bdk_node_t node,
// always write LMC0 CSR, it must be active
DRAM_CSR_WRITE(node, BDK_LMCX_DDR_PLL_CTL(0), ddr_pll_ctl.u);
- ddr_print("%-45s : 0x%016lx\n", "LMC0: DDR_PLL_CTL", ddr_pll_ctl.u);
+ ddr_print("%-45s : 0x%016llx\n", "LMC0: DDR_PLL_CTL", ddr_pll_ctl.u);
// only when LMC1 is active
// NOTE: 81xx has only 1 LMC, and 83xx can operate in 1-LMC mode
@@ -1030,7 +1034,7 @@ int initialize_ddr_clock(bdk_node_t node,
// always write LMC1 CSR when it is active
DRAM_CSR_WRITE(node, BDK_LMCX_DDR_PLL_CTL(1), ddr_pll_ctl.u);
- ddr_print("%-45s : 0x%016lx\n", "LMC1: DDR_PLL_CTL", ddr_pll_ctl.u);
+ ddr_print("%-45s : 0x%016llx\n", "LMC1: DDR_PLL_CTL", ddr_pll_ctl.u);
}
/*
@@ -1107,7 +1111,7 @@ int initialize_ddr_clock(bdk_node_t node,
if (clkf > max_clkf) continue; /* PLL requires clkf to be limited */
if (_abs(error) > _abs(best_error)) continue;
- VB_PRT(VBL_TME, "clkr: %2lu, en[%d]: %2d, clkf: %4lu, pll_MHz: %4lu, ddr_hertz: %8lu, error: %8ld\n",
+ VB_PRT(VBL_TME, "clkr: %2llu, en[%d]: %2d, clkf: %4llu, pll_MHz: %4llu, ddr_hertz: %8llu, error: %8lld\n",
clkr, save_en_idx, _en[save_en_idx], clkf, pll_MHz, calculated_ddr_hertz, error);
/* Favor the highest PLL frequency. */
@@ -1143,7 +1147,7 @@ int initialize_ddr_clock(bdk_node_t node,
best_error = ddr_hertz - best_calculated_ddr_hertz;
}
- ddr_print("clkr: %2lu, en[%d]: %2d, clkf: %4lu, pll_MHz: %4lu, ddr_hertz: %8lu, error: %8ld <==\n",
+ ddr_print("clkr: %2llu, en[%d]: %2d, clkf: %4llu, pll_MHz: %4llu, ddr_hertz: %8llu, error: %8lld <==\n",
best_clkr, best_en_idx, _en[best_en_idx], best_clkf, best_pll_MHz,
best_calculated_ddr_hertz, best_error);
@@ -1177,7 +1181,7 @@ int initialize_ddr_clock(bdk_node_t node,
// make sure we preserve any settings already there
ddr_pll_ctl.u = BDK_CSR_READ(node, BDK_LMCX_DDR_PLL_CTL(loop_interface_num));
- ddr_print("LMC%d: DDR_PLL_CTL : 0x%016lx\n",
+ ddr_print("LMC%d: DDR_PLL_CTL : 0x%016llx\n",
loop_interface_num, ddr_pll_ctl.u);
ddr_pll_ctl.cn83xx.ddr_ps_en = best_en_idx;
@@ -1187,7 +1191,7 @@ int initialize_ddr_clock(bdk_node_t node,
ddr_pll_ctl.cn83xx.bwadj = new_bwadj;
DRAM_CSR_WRITE(node, BDK_LMCX_DDR_PLL_CTL(loop_interface_num), ddr_pll_ctl.u);
- ddr_print("LMC%d: DDR_PLL_CTL : 0x%016lx\n",
+ ddr_print("LMC%d: DDR_PLL_CTL : 0x%016llx\n",
loop_interface_num, ddr_pll_ctl.u);
}
}
@@ -1579,7 +1583,7 @@ int initialize_ddr_clock(bdk_node_t node,
lmc_phy_ctl.u = BDK_CSR_READ(node, BDK_LMCX_PHY_CTL(loop_interface_num));
lmc_phy_ctl.cn83xx.lv_mode = (~loop_interface_num) & 1; /* Odd LMCs = 0, Even LMCs = 1 */
- ddr_print("LMC%d: PHY_CTL : 0x%016lx\n",
+ ddr_print("LMC%d: PHY_CTL : 0x%016llx\n",
loop_interface_num, lmc_phy_ctl.u);
DRAM_CSR_WRITE(node, BDK_LMCX_PHY_CTL(loop_interface_num), lmc_phy_ctl.u);
}
@@ -1860,7 +1864,7 @@ restart_training:
// NOTE: return is a bitmask of the erroring bytelanes - we only print it
errors = test_dram_byte_hw(node, lmc, phys_addr, DBTRAIN_DBI, NULL);
- ddr_print("N%d.LMC%d: DBI switchover: TEST: rank %d, phys_addr 0x%lx, errors 0x%x.\n",
+ ddr_print("N%d.LMC%d: DBI switchover: TEST: rank %d, phys_addr 0x%llx, errors 0x%x.\n",
node, lmc, rankx, phys_addr, errors);
// NEXT - check for locking
@@ -1895,7 +1899,7 @@ restart_training:
// end of DBI switchover
///////////////////////////////////////////////////////////
-uint32_t measure_octeon_ddr_clock(bdk_node_t node,
+static uint32_t measure_octeon_ddr_clock(bdk_node_t node,
const ddr_configuration_t *ddr_configuration,
uint32_t cpu_hertz,
uint32_t ddr_hertz,
@@ -1926,17 +1930,14 @@ uint32_t measure_octeon_ddr_clock(bdk_node_t node,
core_clocks = bdk_clock_get_count(BDK_CLOCK_TIME) - core_clocks;
calc_ddr_hertz = ddr_clocks * bdk_clock_get_rate(bdk_numa_local(), BDK_CLOCK_TIME) / core_clocks;
- /* Asim doesn't have a DDR clock, force the measurement to be correct */
- if (bdk_is_platform(BDK_PLATFORM_ASIM))
- calc_ddr_hertz = ddr_hertz;
-
- ddr_print("LMC%d: Measured DDR clock: %lu, cpu clock: %u, ddr clocks: %lu\n",
+ ddr_print("LMC%d: Measured DDR clock: %llu, cpu clock: %u, ddr clocks: %llu\n",
ddr_interface_num, calc_ddr_hertz, cpu_hertz, ddr_clocks);
/* Check for unreasonable settings. */
if (calc_ddr_hertz == 0) {
error_print("DDR clock misconfigured. Exiting.\n");
- exit(1);
+ /* FIXME(dhendrix): We don't exit() in coreboot */
+// exit(1);
}
return calc_ddr_hertz;
}
diff --git a/src/vendorcode/cavium/bdk/libdram/libdram-config-load.c b/src/vendorcode/cavium/bdk/libdram/libdram-config-load.c
index 5173290187..76b5ddc57d 100644
--- a/src/vendorcode/cavium/bdk/libdram/libdram-config-load.c
+++ b/src/vendorcode/cavium/bdk/libdram/libdram-config-load.c
@@ -38,6 +38,14 @@
***********************license end**************************************/
#include <bdk.h>
+/* FIXME(dhendrix): added */
+#include <console/console.h> /* for die() */
+#include <string.h>
+#include <libbdk-arch/bdk-model.h>
+#include <libbdk-hal/bdk-config.h>
+#include <soc/twsi.h>
+#include <device/i2c_simple.h>
+
/**
* Load a "odt_*rank_config" structure
*
@@ -157,10 +165,12 @@ const dram_config_t *libdram_config_load(bdk_node_t node)
}
else
{
+#if 0
int spd_size;
const void *spd_data = bdk_config_get_blob(&spd_size, BDK_CONFIG_DDR_SPD_DATA, dimm, lmc, node);
if (spd_data && spd_size)
cfg->config[lmc].dimm_config_table[dimm].spd_ptr = spd_data;
+#endif
}
}
}
diff --git a/src/vendorcode/cavium/bdk/libdram/libdram.c b/src/vendorcode/cavium/bdk/libdram/libdram.c
index b19486694c..551ba24c42 100644
--- a/src/vendorcode/cavium/bdk/libdram/libdram.c
+++ b/src/vendorcode/cavium/bdk/libdram/libdram.c
@@ -36,9 +36,20 @@
* 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_fus.h"
+#include <libbdk-arch/bdk-csrs-mio_fus.h>
+#include <libbdk-dram/bdk-dram-config.h>
+#include <libbdk-hal/bdk-config.h>
+#include <libbdk-hal/bdk-gpio.h>
+#include <libbdk-hal/bdk-l2c.h>
+#include <libbdk-hal/bdk-utils.h>
+#include <libbdk-os/bdk-init.h>
+#include <libdram/libdram-config.h>
#include "dram-internal.h"
+#include <stddef.h> /* for NULL */
+#include <lame_string.h> /* for strtol() and friends */
+
/* This global variable is accessed through dram_is_verbose() to determine
the verbosity level. Use that function instead of setting it directly */
@@ -55,35 +66,33 @@ dram_config_t __libdram_global_cfg;
static void bdk_dram_clear_mem(bdk_node_t node)
{
- if (!bdk_is_platform(BDK_PLATFORM_ASIM)) {
- uint64_t mbytes = bdk_dram_get_size_mbytes(node);
- uint64_t skip = (node == bdk_numa_master()) ? bdk_dram_get_top_of_bdk() : 0;
- uint64_t len = (mbytes << 20) - skip;
-
- BDK_TRACE(DRAM, "N%d: Clearing DRAM\n", node);
- if (skip)
- {
- /* All memory below skip may contain valid data, so we can't clear
- it. We still need to make sure all cache lines in this area are
- fully dirty so that ECC bits will be updated on store. A single
- write to the cache line isn't good enough because partial LMC
- writes may be enabled */
- ddr_print("N%d: Rewriting DRAM: start 0 length 0x%lx\n", node, skip);
- volatile uint64_t *ptr = bdk_phys_to_ptr(bdk_numa_get_address(node, 8));
- /* The above pointer got address 8 to avoid NULL pointer checking
- in bdk_phys_to_ptr(). Correct it here */
- ptr--;
- uint64_t *end = bdk_phys_to_ptr(bdk_numa_get_address(node, skip));
- while (ptr < end)
- {
- *ptr = *ptr;
- ptr++;
- }
- }
- ddr_print("N%d: Clearing DRAM: start 0x%lx length 0x%lx\n", node, skip, len);
- bdk_zero_memory(bdk_phys_to_ptr(bdk_numa_get_address(node, skip)), len);
- BDK_TRACE(DRAM, "N%d: DRAM clear complete\n", node);
- }
+ uint64_t mbytes = bdk_dram_get_size_mbytes(node);
+ uint64_t skip = (node == bdk_numa_master()) ? bdk_dram_get_top_of_bdk() : 0;
+ uint64_t len = (mbytes << 20) - skip;
+
+ BDK_TRACE(DRAM, "N%d: Clearing DRAM\n", node);
+ if (skip)
+ {
+ /* All memory below skip may contain valid data, so we can't clear
+ it. We still need to make sure all cache lines in this area are
+ fully dirty so that ECC bits will be updated on store. A single
+ write to the cache line isn't good enough because partial LMC
+ writes may be enabled */
+ ddr_print("N%d: Rewriting DRAM: start 0 length 0x%llx\n", node, skip);
+ volatile uint64_t *ptr = bdk_phys_to_ptr(bdk_numa_get_address(node, 8));
+ /* The above pointer got address 8 to avoid NULL pointer checking
+ in bdk_phys_to_ptr(). Correct it here */
+ ptr--;
+ uint64_t *end = bdk_phys_to_ptr(bdk_numa_get_address(node, skip));
+ while (ptr < end)
+ {
+ *ptr = *ptr;
+ ptr++;
+ }
+ }
+ ddr_print("N%d: Clearing DRAM: start 0x%llx length 0x%llx\n", node, skip, len);
+ bdk_zero_memory(bdk_phys_to_ptr(bdk_numa_get_address(node, skip)), len);
+ BDK_TRACE(DRAM, "N%d: DRAM clear complete\n", node);
}
static void bdk_dram_clear_ecc(bdk_node_t node)
@@ -110,7 +119,7 @@ static void bdk_dram_enable_ecc_reporting(bdk_node_t node)
if (! CAVIUM_IS_MODEL(CAVIUM_CN88XX_PASS1_X)) { // added 81xx and 83xx
DRAM_CSR_WRITE(node, BDK_LMCX_INT_ENA_W1S(lmc), -1ULL);
BDK_CSR_INIT(lmc_int_ena_w1s, node, BDK_LMCX_INT_ENA_W1S(lmc));
- ddr_print("N%d.LMC%d: %-36s : 0x%08lx\n",
+ ddr_print("N%d.LMC%d: %-36s : 0x%08llx\n",
node, lmc, "LMC_INT_ENA_W1S", lmc_int_ena_w1s.u);
}
}
@@ -130,7 +139,7 @@ static void bdk_dram_disable_ecc_reporting(bdk_node_t node)
if (! CAVIUM_IS_MODEL(CAVIUM_CN88XX_PASS1_X)) { // added 81xx and 83xx
DRAM_CSR_WRITE(node, BDK_LMCX_INT_ENA_W1C(lmc), -1ULL);
BDK_CSR_INIT(lmc_int_ena_w1c, node, BDK_LMCX_INT_ENA_W1C(lmc));
- ddr_print("N%d.LMC%d: %-36s : 0x%08lx\n",
+ ddr_print("N%d.LMC%d: %-36s : 0x%08llx\n",
node, lmc, "LMC_INT_ENA_W1C", lmc_int_ena_w1c.u);
}
}
@@ -171,14 +180,15 @@ static int bdk_libdram_tune_node(int node)
// Automatically tune the data byte DLL write offsets
// allow override of default setting
str = getenv("ddr_tune_write_offsets");
+ str = NULL;
if (str)
do_dllwo = !!strtoul(str, NULL, 0);
if (do_dllwo) {
- BDK_TRACE(DRAM, "N%d: Starting DLL Write Offset Tuning for LMCs\n", node);
- errs = perform_dll_offset_tuning(node, /* write */1, /* tune */1);
- BDK_TRACE(DRAM, "N%d: Finished DLL Write Offset Tuning for LMCs, %d errors)\n",
- node, errs);
- tot_errs += errs;
+ BDK_TRACE(DRAM, "N%d: Starting DLL Write Offset Tuning for LMCs\n", node);
+ errs = perform_dll_offset_tuning(node, /* write */1, /* tune */1);
+ BDK_TRACE(DRAM, "N%d: Finished DLL Write Offset Tuning for LMCs, %d errors)\n",
+ node, errs);
+ tot_errs += errs;
}
// disabled by default for now, does not seem to be needed much?
@@ -287,9 +297,6 @@ static int bdk_libdram_maybe_tune_node(int node)
*/
int libdram_config(int node, const dram_config_t *dram_config, int ddr_clock_override)
{
- if (bdk_is_platform(BDK_PLATFORM_ASIM))
- return bdk_dram_get_size_mbytes(node);
-
/* Boards may need to mux the TWSI connection between THUNDERX and the BMC.
This allows the BMC to monitor DIMM temeratures and health */
int gpio_select = bdk_config_get_int(BDK_CONFIG_DRAM_CONFIG_GPIO);
@@ -446,7 +453,7 @@ int libdram_tune(int node)
// the only way this entry point should be called is from a MENU item,
// so, enable any non-running cores on this node, and leave them
// running at the end...
- ddr_print("N%d: %s: Starting cores (mask was 0x%lx)\n",
+ ddr_print("N%d: %s: Starting cores (mask was 0x%llx)\n",
node, __FUNCTION__, bdk_get_running_coremask(node));
bdk_init_cores(node, ~0ULL);
@@ -600,7 +607,7 @@ int libdram_margin_read_timing(int node)
int libdram_margin(int node)
{
int ret_rt, ret_wt, ret_rv, ret_wv;
- char *risk[2] = { "Low Risk", "Needs Review" };
+ const char *risk[2] = { "Low Risk", "Needs Review" };
int l2c_is_locked = bdk_l2c_is_locked(node);
// for now, no margining on 81xx, until we can reduce the dynamic runtime size...
@@ -614,7 +621,7 @@ int libdram_margin(int node)
// the only way this entry point should be called is from a MENU item,
// so, enable any non-running cores on this node, and leave them
// running at the end...
- ddr_print("N%d: %s: Starting cores (mask was 0x%lx)\n",
+ ddr_print("N%d: %s: Starting cores (mask was 0x%llx)\n",
node, __FUNCTION__, bdk_get_running_coremask(node));
bdk_init_cores(node, ~0ULL);
@@ -712,7 +719,7 @@ uint32_t libdram_get_freq_from_pll(int node, int lmc)
#ifndef DRAM_CSR_WRITE_INLINE
void dram_csr_write(bdk_node_t node, const char *csr_name, bdk_csr_type_t type, int busnum, int size, uint64_t address, uint64_t value)
{
- VB_PRT(VBL_CSRS, "N%d: DDR Config %s[%016lx] => %016lx\n", node, csr_name, address, value);
+ VB_PRT(VBL_CSRS, "N%d: DDR Config %s[%016llx] => %016llx\n", node, csr_name, address, value);
bdk_csr_write(node, type, busnum, size, address, value);
}
#endif