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>
This commit is contained in:
David Hendricks
2018-03-09 14:30:38 -08:00
committed by Philipp Deppenwiese
parent d837e66007
commit 7d48ac5c7d
153 changed files with 166930 additions and 9914 deletions

View File

@ -2,3 +2,4 @@ subdirs-y += amd
subdirs-y += google
subdirs-y += intel
subdirs-y += siemens
subdirs-y += cavium

View File

@ -0,0 +1,70 @@
##
## This file is part of the coreboot project.
##
## Copyright 2017-present Facebook, Inc.
##
## This program is free software; you can redistribute it and/or modify
## it under the terms of the GNU General Public License as published by
## the Free Software Foundation; version 2 of the License.
##
## This program is distributed in the hope that it will be useful,
## but WITHOUT ANY WARRANTY; without even the implied warranty of
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
## GNU General Public License for more details.
##
config CAVIUM_BDK
def_bool n
select HAVE_DEBUG_RAM_SETUP
help
Build Cavium's BDK in romstage.
if CAVIUM_BDK
menu "BDK"
config CAVIUM_BDK_VERBOSE_INIT
bool "Enable verbose init"
depends on CAVIUM_BDK
help
Build Cavium's BDK with verbose init code.
config CAVIUM_BDK_VERBOSE_DRAM
bool "Enable verbose dram init"
default y if DEBUG_RAM_SETUP
depends on CAVIUM_BDK
help
Build Cavium's BDK with verbose dram init code.
config CAVIUM_BDK_VERBOSE_DRAM_TEST
bool "Enable verbose raminit tests"
depends on CAVIUM_BDK
help
Build Cavium's BDK with verbose DRAM testing code.
config CAVIUM_BDK_VERBOSE_QLM
bool "Enable verbose qlm init"
depends on CAVIUM_BDK
help
Build Cavium's BDK with verbose QLM code.
config CAVIUM_BDK_VERBOSE_PCIE_CONFIG
bool "Enable verbose pcie config"
depends on CAVIUM_BDK
help
Build Cavium's BDK with verbose PCIe config code.
config CAVIUM_BDK_VERBOSE_PCIE
bool "Enable verbose pcie init"
depends on CAVIUM_BDK
help
Build Cavium's BDK with verbose PCIe code.
config CAVIUM_BDK_VERBOSE_PHY
bool "Enable verbose phy init"
depends on CAVIUM_BDK
help
Build Cavium's BDK with verbose PHY code.
endmenu
endif

View File

@ -0,0 +1,92 @@
##
## This file is part of the coreboot project.
##
## Copyright 2017-present Facebook, Inc.
##
## This program is free software; you can redistribute it and/or modify
## it under the terms of the GNU General Public License as published by
## the Free Software Foundation; version 2 of the License.
##
## This program is distributed in the hope that it will be useful,
## but WITHOUT ANY WARRANTY; without even the implied warranty of
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
## GNU General Public License for more details.
##
ifeq ($(CONFIG_CAVIUM_BDK),y)
romstage-y += bdk/libbdk-arch/bdk-csr.c
romstage-y += bdk/libbdk-arch/bdk-model.c
romstage-y += bdk/libbdk-arch/bdk-numa.c
romstage-y += bdk/libbdk-boot/bdk-boot-status.c
romstage-y += bdk/libbdk-dram/bdk-dram-address.c
romstage-y += bdk/libbdk-dram/bdk-dram-config.c
romstage-y += bdk/libbdk-dram/bdk-dram-size.c
romstage-y += bdk/libbdk-dram/bdk-dram-test.c
romstage-y += bdk/libbdk-dram/bdk-dram-test-addrbus.c
romstage-y += bdk/libbdk-dram/bdk-dram-test-databus.c
romstage-y += bdk/libbdk-dram/bdk-dram-test-fastscan.c
romstage-y += bdk/libbdk-dram/bdk-dram-test-patfil.c
romstage-y += bdk/libbdk-driver/bdk-driver-rnm.c
romstage-y += bdk/libbdk-hal/bdk-clock.c
romstage-y += bdk/libbdk-hal/bdk-config.c
romstage-y += bdk/libbdk-hal/bdk-gpio.c
romstage-y += bdk/libbdk-hal/bdk-l2c.c
romstage-y += bdk/libbdk-os/bdk-init.c
romstage-y += bdk/libbdk-trust/bdk-trust.c
romstage-y += bdk/libdram/dram-env.c
romstage-y += bdk/libdram/dram-init-ddr3.c
romstage-y += bdk/libdram/dram-l2c.c
romstage-y += bdk/libdram/dram-spd.c
romstage-y += bdk/libdram/dram-tune-ddr3.c
romstage-y += bdk/libdram/lib_octeon_shared.c
romstage-y += bdk/libdram/libdram.c
romstage-y += bdk/libdram/libdram-config-load.c
romstage-y += bdk/libbdk-hal/bdk-access.c
# FIXME: Get rid of lame_string.c
romstage-y += bdk/lame_string.c
CPPFLAGS_common += -Isrc/vendorcode/cavium/include/bdk
# For bdk_dram_get_size_mbytes()
ramstage-y += bdk/libbdk-dram/bdk-dram-size.c
ramstage-y += bdk/libbdk-hal/bdk-config.c
ramstage-y += bdk/libbdk-hal/bdk-qlm.c
ramstage-y += bdk/libbdk-hal/bdk-pcie-cn8xxx.c
ramstage-y += bdk/libbdk-hal/bdk-pcie.c
ramstage-y += bdk/libbdk-hal/bdk-gpio.c
ramstage-y += bdk/libbdk-hal/bdk-ecam-io.c
ramstage-y += bdk/libbdk-hal/bdk-usb.c
ramstage-y += bdk/libbdk-hal/bdk-access.c
ramstage-y += bdk/libbdk-arch/bdk-csr.c
ramstage-y += bdk/libbdk-arch/bdk-model.c
ramstage-y += bdk/libbdk-arch/bdk-numa.c
ramstage-y += bdk/libbdk-hal/qlm/bdk-qlm-common.c
ramstage-y += bdk/libbdk-hal/qlm/bdk-qlm-errata-cn8xxx.c
ramstage-y += bdk/libbdk-hal/qlm/bdk-qlm-common-sata.c
ramstage-y += bdk/libbdk-hal/qlm/bdk-qlm-margin-cn8xxx.c
ramstage-y += bdk/libbdk-boot/bdk-boot-qlm.c
ramstage-y += bdk/libbdk-boot/bdk-boot-pcie.c
ramstage-y += bdk/libbdk-boot/bdk-boot-usb.c
ramstage-y += bdk/libbdk-boot/bdk-boot-gpio.c
ramstage-y += bdk/libbdk-boot/bdk-boot.c
ramstage-y += bdk/libbdk-hal/if/bdk-if-phy.c
ramstage-y += bdk/libbdk-hal/if/bdk-if-phy-marvell.c
ramstage-y += bdk/libbdk-hal/if/bdk-if-phy-vetesse-8514.c
ramstage-y += bdk/libbdk-hal/if/bdk-if-phy-vetesse.c
ramstage-y += bdk/libbdk-driver/bdk-driver-mdio.c
ramstage-y += bdk/libbdk-driver/bdk-driver-rnm.c
ramstage-y += bdk/libbdk-hal/device/bdk-device.c
ramstage-y += bdk/libbdk-hal/bdk-ecam.c
# FIXME: Get rid of lame_string.c
ramstage-y += bdk/lame_string.c
ramstage-$(CONFIG_SOC_CAVIUM_CN81XX) += bdk/libbdk-hal/qlm/bdk-qlm-cn81xx.c
endif

View File

@ -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;
}

View File

@ -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)
{

View File

@ -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];
}

View File

@ -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;
}

View File

@ -36,47 +36,35 @@
* 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"
/**
* @file
*
* Functions for information about the run platform.
*
* <hr>$Revision: 49448 $<hr>
* @addtogroup hal
* @{
* Configure GPIO on all nodes as part of booting
*/
/**
* This typedef defines the possible platforms for the BDK. The
* numbers represent fuse setting in Fuses[197:195].
*/
typedef enum
void bdk_boot_gpio(void)
{
BDK_PLATFORM_HW = 0,
BDK_PLATFORM_EMULATOR = 1,
BDK_PLATFORM_RTL = 2,
BDK_PLATFORM_ASIM = 3,
} bdk_platform_t;
/**
* Check which platform we are currently running on. This allows a BDK binary to
* run on various platforms without a recompile.
*
* @param platform Platform to check for
*
* @return Non zero if we are on the platform
*/
static inline int bdk_is_platform(bdk_platform_t platform) __attribute__ ((pure, always_inline));
static inline int bdk_is_platform(bdk_platform_t platform)
const int NUM_GPIO = bdk_gpio_get_num();
for (bdk_node_t n = BDK_NODE_0; n < BDK_NUMA_MAX_NODES; n++)
{
extern bdk_platform_t __bdk_platform;
return (__bdk_platform == platform);
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);
}
}
}
}
/**
* Call to initialize the platform state
*/
extern void __bdk_platform_init();
/** @} */

View File

@ -36,19 +36,33 @@
* 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"
/**
* @file
*
* Boot services for BGX
*
* @addtogroup boot
* @{
* Configure PCIe on all nodes as part of booting
*/
/**
* Configure BGX on all nodes as part of booting
*/
extern void bdk_boot_bgx(void);
/** @} */
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);
}
}
}
}
}

View File

@ -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();
}

View File

@ -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

View File

@ -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)
/* Initialize USB, ready for standard XHCI driver */
for (bdk_node_t n = BDK_NODE_0; n < BDK_NUMA_MAX_NODES; n++)
{
__bdk_platform = BDK_PLATFORM_ASIM;
}
else
if (bdk_numa_exists(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;
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);
}
}
}
}

View File

@ -36,51 +36,63 @@
* 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"
/**
* @file
*
* Functions for displaying and retrieving infomration about the
* boot environment
*
* @addtogroup boot
* @{
* 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);
}
/**
* Display information about strapping and other hard configuration items for
* the specified node
*
* @param node Node to display
*/
void bdk_boot_info_strapping(bdk_node_t node);
bdk_ecam_scan_all(n);
bdk_mdio_init(n);
bdk_qlm_init(n);
bdk_rng_init(n);
}
}
/**
* Return a string containing information about the chip's manufacture wafer
*
* @param node Node to query
*
* @return Static string, reused on each call
*/
const char* bdk_boot_info_wafer(bdk_node_t node);
bdk_boot_gpio();
bdk_boot_usb();
bdk_boot_qlm();
bdk_boot_pcie();
/**
* Return a string containing the chip's unique serial number
*
* @param node Node to query
*
* @return Static string, reused on each call
*/
const char* bdk_boot_info_serial(bdk_node_t node);
/**
* Return a string containing the chip's unique ID
*
* @param node Node to query
*
* @return Static string, reused on each call
*/
const char* bdk_boot_info_unique_id(bdk_node_t node);
/** @} */
/* 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);
}
}
}

View File

@ -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;
}

View File

@ -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);
@ -72,22 +74,6 @@ int bdk_dram_config(int node, int ddr_clock_override)
return mbytes;
}
/**
* 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
*
@ -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)
{

View File

@ -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
@ -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;
@ -191,13 +190,6 @@ uint64_t bdk_dram_get_size_mbytes(int node)
uint64_t memsize = 0;
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
@ -207,7 +199,6 @@ uint64_t bdk_dram_get_size_mbytes(int node)
uint64_t rank_size = 1ull << (28 + lmcx_config.s.pbank_lsb - lmcx_config.s.rank_ena);
memsize += rank_size * num_ranks;
}
}
return memsize >> 20;
}

View File

@ -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)

View File

@ -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;

View File

@ -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)

View File

@ -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);

View File

@ -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,12 +226,12 @@ 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",
bdk_error("Start address is larger than the amount of memory: 0x%011llx versus 0x%011llx\n",
start_address, max_address);
return -1;
}
@ -260,7 +268,7 @@ 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",
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 */
@ -337,7 +345,7 @@ static int __bdk_dram_run_test(const dram_test_info_t *test_info, uint64_t start
/* 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);
}
@ -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);
}
}
@ -548,6 +546,8 @@ int bdk_dram_test(int test, uint64_t start_address, uint64_t length, bdk_dram_te
}
/* 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,13 +576,13 @@ 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",
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",
printf("Test \"%s\": FAIL: %lld single, %lld double, %d compare errors\n",
name, ecc_single, ecc_double, errors);
}
else
@ -718,7 +712,7 @@ void __bdk_dram_report_error2(uint64_t address1, uint64_t data1, uint64_t addres
__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"
bdk_error("compare: data1: 0x%016llx, xor: 0x%016llx%s\n"
" %s\n %s\n",
data1, data1 ^ data2, failbuf,
buffer1, buffer2);
@ -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);
}

View File

@ -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;
}

View File

@ -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);
/**
@ -83,19 +88,6 @@ uint64_t bdk_rng_get_random64(void)
return bdk_read64_uint64(bdk_numa_get_address(bdk_numa_local(), BDK_RNM_RANDOM));
}
/**
* 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
*
@ -103,13 +95,20 @@ static int probe(bdk_device_t *device)
*
* @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,
};

View File

@ -36,24 +36,35 @@
* 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"
/**
* @file
* Perform a soft reset of the chip
*
* Functions for identifying BDK build version.
*
* <hr>$Revision$<hr>
* @return
*/
extern const char bdk_version_str[];
/**
* Return BDK version string
*
* @return BDK version string
*/
static inline const char *bdk_version_string(void)
void bdk_reset_chip(bdk_node_t node)
{
return bdk_version_str;
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);
}

View File

@ -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:

File diff suppressed because it is too large Load Diff

View File

@ -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));
}

View File

@ -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;
}

View File

@ -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 */

View File

@ -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;
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -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);
}

View File

@ -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;
}

File diff suppressed because it is too large Load Diff

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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);
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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

View File

@ -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;
}

File diff suppressed because it is too large Load Diff

View File

@ -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;
}

File diff suppressed because it is too large Load Diff

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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));
}

View File

@ -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);
}
}

View File

@ -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;
}

View File

@ -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;

View File

@ -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

View File

@ -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,8 +138,8 @@ 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;
@ -141,13 +149,13 @@ Get_Deskew_Settings(bdk_node_t node, int ddr_interface_num, deskew_data_t *dskda
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 {
@ -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);
}
@ -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);
@ -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,
@ -1875,7 +1883,7 @@ static void do_display_RL(bdk_node_t node, int ddr_interface_num,
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 ";
@ -1987,7 +1995,7 @@ 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) {
@ -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),
@ -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) {
/* 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,8 +2329,7 @@ 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);
@ -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;
@ -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;
@ -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);
@ -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);
}
@ -3254,9 +3265,6 @@ 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)
@ -3264,7 +3272,6 @@ int init_octeon3_ddr3_interface(bdk_node_t node,
if (s != NULL) {
wlevel_loops = strtoul(s, NULL, 0);
}
}
bunk_enable = (num_ranks > 1);
@ -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;
}
@ -3837,7 +3844,7 @@ int init_octeon3_ddr3_interface(bdk_node_t node,
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);
}
@ -3950,7 +3957,7 @@ int init_octeon3_ddr3_interface(bdk_node_t node,
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);
}
@ -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,7 +4062,7 @@ 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
@ -4074,7 +4081,7 @@ int init_octeon3_ddr3_interface(bdk_node_t node,
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
@ -4082,7 +4089,7 @@ int init_octeon3_ddr3_interface(bdk_node_t node,
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("TIMING_PARAMS1 : 0x%016llx\n", lmc_timing_params1.u);
DRAM_CSR_WRITE(node, BDK_LMCX_TIMING_PARAMS1(ddr_interface_num), lmc_timing_params1.u);
}
}
@ -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,7 +4415,7 @@ 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 */
@ -4461,7 +4468,7 @@ int init_octeon3_ddr3_interface(bdk_node_t node,
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);
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,7 +4561,7 @@ 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);
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;
@ -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);
}
@ -4950,7 +4957,7 @@ int init_octeon3_ddr3_interface(bdk_node_t node,
lmc_dimm_ctl.s.tcws = strtoul(s, NULL, 0);
}
ddr_print("LMC DIMM_CTL : 0x%016lx\n", 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,
@ -4959,7 +4966,7 @@ int init_octeon3_ddr3_interface(bdk_node_t node,
/* 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);
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 */
@ -4992,7 +4999,7 @@ int init_octeon3_ddr3_interface(bdk_node_t node,
lmc_dimm_ctl.s.tcws = strtoul(s, NULL, 0);
}
ddr_print("LMC DIMM_CTL : 0x%016lx\n", 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,
@ -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);
}
@ -5245,7 +5252,7 @@ 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);
@ -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);
}
}
@ -5570,8 +5577,7 @@ int init_octeon3_ddr3_interface(bdk_node_t node,
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),
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");
@ -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);
}
}
@ -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);
@ -6217,8 +6220,7 @@ int init_octeon3_ddr3_interface(bdk_node_t node,
/* read-leveling */
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),
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");
@ -6246,8 +6248,7 @@ int init_octeon3_ddr3_interface(bdk_node_t node,
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),
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");
@ -6275,8 +6276,7 @@ int init_octeon3_ddr3_interface(bdk_node_t node,
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),
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");
@ -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) {
@ -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++) {
@ -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
@ -7718,7 +7705,7 @@ 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
@ -8188,7 +8175,7 @@ int init_octeon3_ddr3_interface(bdk_node_t node,
} /* 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",
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,
@ -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;
@ -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));
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",
@ -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);

View File

@ -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) */

View File

@ -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"

View File

@ -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);

View File

@ -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

View File

@ -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;
// FIXME: prudolph: Nobody needs 512 byte SPDs...
//int spd_size = (dev_type == 0x0c) ? 512 : 256;
int spd_size = 256;
/* Allocate storage */
uint32_t *spd_buf = malloc(spd_size);
if (!spd_buf)
return -1;
uint32_t *ptr = spd_buf;
/*
* 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))

View File

@ -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__)
@ -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,14 +521,8 @@ 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
@ -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
@ -1081,9 +580,9 @@ 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?
@ -1110,11 +609,13 @@ auto_set_dll_offset(bdk_node_t node, int dll_offset_mode,
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);
/* 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);
/* 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
@ -1347,7 +848,8 @@ auto_set_dll_offset(bdk_node_t node, int dll_offset_mode,
// 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",
/* 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++) */
@ -1389,9 +891,11 @@ 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",
/* FIXME(dhendrix): %lx --> %llx */
ddr_print4("N%d: %s: Starting cores (mask was 0x%llx)\n",
node, __FUNCTION__, orig_coremask);
bdk_init_cores(node, ~0ULL & ~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
@ -1557,13 +1061,17 @@ int perform_dll_offset_tuning(bdk_node_t node, int dll_offset_mode, int do_tune)
#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__,
/* 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__,
/* FIXME(dhendrix): %lx --> %llx */
ddr_print4("N%d: %s: leaving cores set to 0x%llx\n", node, __FUNCTION__,
orig_coremask);
}
@ -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;
@ -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]);

View File

@ -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

View File

@ -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,7 +170,7 @@ static int init_octeon_dram_interface(bdk_node_t node,
}
}
error_print("N%d.LMC%d Configuration Completed: %d MB\n",
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;
}

View File

@ -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
}
}
}

View File

@ -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,7 +66,6 @@ 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;
@ -68,7 +78,7 @@ static void bdk_dram_clear_mem(bdk_node_t node)
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);
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 */
@ -80,11 +90,10 @@ static void bdk_dram_clear_mem(bdk_node_t node)
ptr++;
}
}
ddr_print("N%d: Clearing DRAM: start 0x%lx length 0x%lx\n", node, skip, len);
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,6 +180,7 @@ 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) {
@ -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

View File

@ -0,0 +1,20 @@
/*
* This file is part of the coreboot project.
*
* Copyright 2017-present Facebook, Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*/
struct bdk_devicetree_key_value {
const char *key;
const char *value;
};

View File

@ -0,0 +1,60 @@
/*
* This file is part of the coreboot project.
*
* Copyright (c) 2003-2017 Cavium Inc. (support@cavium.com). All rights
* reserved.
* Copyright 2017-present Facebook, Inc.
*
* SPDX-License-Identifier: BSD-3-Clause
*
* bdk-minimal.h: Subset of bdk.h used by coreboot
*/
#ifndef __SOC_CAVIUM_COMMON_BDK_MINIMAL_H__
#define __SOC_CAVIUM_COMMON_BDK_MINIMAL_H__
#include <console/console.h> /* for printk */
#include <endian.h>
#include <stddef.h> /* for NULL */
#include <libbdk-hal/bdk-access.h>
#define bdk_le16_to_cpu(x) le16_to_cpu(x)
#define bdk_le32_to_cpu(x) le32_to_cpu(x)
#define bdk_le64_to_cpu(x) le64_to_cpu(x)
#define bdk_be16_to_cpu(x) be16_to_cpu(x)
#define bdk_be32_to_cpu(x) be32_to_cpu(x)
#define bdk_be64_to_cpu(x) be64_to_cpu(x)
#define bdk_cpu_to_le16(x) cpu_to_le16(x)
#define bdk_cpu_to_le32(x) cpu_to_le32(x)
#define bdk_cpu_to_le64(x) cpu_to_le64(x)
#define __BYTE_ORDER __BYTE_ORDER__
/* Watch out for __BIG_ENDIAN. coreboot usually checks if it's defined at all
* but the Cavium BDK checks its value. */
#define __BIG_ENDIAN 4321
#define printf(format, ...) printk(BIOS_DEBUG, format, ##__VA_ARGS__)
#define puts(str) printk(BIOS_INFO, str)
#define fflush(x) /* output gets flushed automatically */
/* careful, the ordering matters for some headers */
#include <libbdk-arch/bdk-warn.h>
#include <libbdk-arch/bdk-asm.h>
#include <libbdk-arch/bdk-model.h>
#include <libbdk-arch/bdk-numa.h>
#include <libbdk-arch/bdk-require.h>
#include <libbdk-arch/bdk-csr.h>
#include <libbdk-os/bdk-thread.h>
/* FIXME: experiment to see if including the universe here will solve some
* current build issues... */
#include <libbdk-arch/bdk-arch.h>
#include <libbdk-boot/bdk-boot.h>
#include <libbdk-dram/bdk-dram.h>
#include <libdram/libdram.h>
static inline char *getenv(const char *name) { return NULL; }
#endif /* !__SOC_CAVIUM_COMMON_BDK_MINIMAL_H__ */

View File

@ -1,80 +1,18 @@
#ifndef __BDK_H__
#define __BDK_H__
/***********************license start***********************************
* Copyright (c) 2003-2017 Cavium Inc. (support@cavium.com). All rights
* reserved.
/*
* This file is part of the coreboot project.
*
* Copyright 2017-present Facebook, Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
* SPDX-License-Identifier: BSD-3-Clause
*
* * 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**************************************/
/**
* @file
*
* Master include file for all BDK function.
*
* <hr>$Revision: 49448 $<hr>
* bdk.h: This is a stub for BDK compatibility. The real bdk.h is an uber-
* header that pulls in everything. For our purposes we'll create a minimal
* version that includes only the stuff we need.
*/
#include <stdint.h>
#include <stdbool.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include <stdio.h>
#include "../libbdk-arch/bdk-arch.h"
#include "../libbdk-os/bdk-os.h"
#include "../libfatfs/ff.h"
#include "../libfatfs/diskio.h"
#ifndef BDK_BUILD_HOST
#include "../libbdk-hal/bdk-hal.h"
#include "../libbdk-boot/bdk-boot.h"
#include "../libbdk-dram/bdk-dram.h"
#include "../libbdk-driver/bdk-driver.h"
#include "../libbdk-trust/bdk-trust.h"
#include "../libdram/libdram.h"
#include "bdk-functions.h"
#endif
#include "../libbdk-lua/bdk-lua.h"
#include "../libbdk-bist/bist.h"
#ifndef __SOC_CAVIUM_COMMON_BDK_H__
#define __SOC_CAVIUM_COMMON_BDK_H__
/**
* @mainpage
*
* This document goes through the internal details of the BDK. Its purpose is
* to serve as a API reference for people writing applications. Users of the
* BDK's binary applications do not need these details.
*/
#include "bdk-minimal.h"
#endif
#endif /* !__SOC_CAVIUM_COMMON_BDK_H__ */

View File

@ -0,0 +1,19 @@
/*
* This file is part of the coreboot project.
*
* Copyright 2018-present Facebook, Inc.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef __LAME_STRING_H__
#define __LAME_STRING_H__
long int strtol(const char *nptr, char **endptr, int base);
long long int strtoll(const char *nptr, char **endptr, int base);
unsigned long int strtoul(const char *nptr, char **endptr, int base);
unsigned long long int strtoull(const char *nptr, char **endptr, int base);
int str_to_hex(const char *str, int64_t *val);
int str_to_int(const char *str, int64_t *val);
#endif

View File

@ -48,24 +48,24 @@
* <hr>$Revision: 49448 $<hr>
*/
#include <arch/byteorder.h>
#ifndef __BYTE_ORDER
#if !defined(__ORDER_BIG_ENDIAN__) || !defined(__ORDER_LITTLE_ENDIAN__) || !defined(__BYTE_ORDER__)
#error Unable to determine Endian mode
#elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
#define __BYTE_ORDER __ORDER_BIG_ENDIAN__
#define BDK_LITTLE_ENDIAN_STRUCT __attribute__ ((scalar_storage_order("little-endian")))
#elif __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
#define __BYTE_ORDER __ORDER_LITTLE_ENDIAN__
#define BDK_LITTLE_ENDIAN_STRUCT
#else
#error Unable to determine Endian mode
#if (__LITTLE_ENDIAN)
#define __BYTE_ORDER __LITTLE_ENDIAN
#elif defined(__BIG_ENDIAN)
#define __BYTE_ORDER __BIG_ENDIAN
#endif
#define __BIG_ENDIAN __ORDER_BIG_ENDIAN__
#define __LITTLE_ENDIAN __ORDER_LITTLE_ENDIAN__
#endif
#ifndef __LITTLE_ENDIAN
#define __LITTLE_ENDIAN 1234
#endif
#ifndef __BIG_ENDIAN
#define __BIG_ENDIAN 4321
#endif
#include "bdk-require.h"
#include "bdk-swap.h"
#ifndef BDK_BUILD_HOST
#include "bdk-asm.h"
#endif
@ -76,10 +76,8 @@
#include "bdk-lmt.h"
#endif
#include "bdk-warn.h"
#include "bdk-version.h"
#ifndef BDK_BUILD_HOST
#include "bdk-fuse.h"
#include "bdk-platform.h"
#endif
#endif

View File

@ -1,3 +1,5 @@
#ifndef __CB_BDK_CSR_H__
#define __CB_BDK_CSR_H__
/***********************license start***********************************
* Copyright (c) 2003-2017 Cavium Inc. (support@cavium.com). All rights
* reserved.
@ -37,6 +39,9 @@
* ARISING OUT OF USE OR PERFORMANCE OF THE SOFTWARE LIES WITH YOU.
***********************license end**************************************/
//#include <libbdk-arch/bdk-csrs-rst.h> /* FIXME: circular dependency with this header */
#include <libbdk-hal/bdk-clock.h> /* FIXME(dhendrix): added */
/**
* @file
*
@ -106,7 +111,7 @@ extern int bdk_csr_write_by_name(bdk_node_t node, const char *name, uint64_t val
extern int __bdk_csr_lookup_index(const char *name, int params[]);
extern int bdk_csr_get_name(const char *last_name, char *buffer);
struct bdk_readline_tab;
extern struct bdk_readline_tab *__bdk_csr_get_tab_complete() BDK_WEAK;
extern struct bdk_readline_tab *__bdk_csr_get_tab_complete(void) BDK_WEAK;
extern uint64_t bdk_sysreg_read(int node, int core, uint64_t regnum);
extern void bdk_sysreg_write(int node, int core, uint64_t regnum, uint64_t value);
@ -125,10 +130,11 @@ extern void bdk_sysreg_write(int node, int core, uint64_t regnum, uint64_t value
*
* @return The value of the CSR
*/
/* FIXME(dhendrix): Moved __bdk_csr_read_slow out of the function body... */
extern uint64_t __bdk_csr_read_slow(bdk_node_t node, bdk_csr_type_t type, int busnum, int size, uint64_t address);
static inline uint64_t bdk_csr_read(bdk_node_t node, bdk_csr_type_t type, int busnum, int size, uint64_t address) __attribute__ ((always_inline));
static inline uint64_t bdk_csr_read(bdk_node_t node, bdk_csr_type_t type, int busnum, int size, uint64_t address)
{
extern uint64_t __bdk_csr_read_slow(bdk_node_t node, bdk_csr_type_t type, int busnum, int size, uint64_t address);
switch (type)
{
case BDK_CSR_TYPE_DAB:
@ -174,10 +180,11 @@ static inline uint64_t bdk_csr_read(bdk_node_t node, bdk_csr_type_t type, int bu
* @param address The address of the CSR
* @param value Value to write to the CSR
*/
/* FIXME(dhendrix): Moved __bdk_csr_write_slow out of the function body... */
extern void __bdk_csr_write_slow(bdk_node_t node, bdk_csr_type_t type, int busnum, int size, uint64_t address, uint64_t value);
static inline void bdk_csr_write(bdk_node_t node, bdk_csr_type_t type, int busnum, int size, uint64_t address, uint64_t value) __attribute__ ((always_inline));
static inline void bdk_csr_write(bdk_node_t node, bdk_csr_type_t type, int busnum, int size, uint64_t address, uint64_t value)
{
extern void __bdk_csr_write_slow(bdk_node_t node, bdk_csr_type_t type, int busnum, int size, uint64_t address, uint64_t value);
switch (type)
{
case BDK_CSR_TYPE_DAB:
@ -264,6 +271,8 @@ static inline void bdk_csr_write(bdk_node_t node, bdk_csr_type_t type, int busnu
* 2) Check if ("type".s."field" "op" "value")
* 3) If #2 isn't true loop to #1 unless too much time has passed.
*/
/* FIXME(dhendrix): removed bdk_thread_yield() */
#if 0
#define BDK_CSR_WAIT_FOR_FIELD(node, csr, field, op, value, timeout_usec) \
({int result; \
do { \
@ -285,6 +294,27 @@ static inline void bdk_csr_write(bdk_node_t node, bdk_csr_type_t type, int busnu
} \
} while (0); \
result;})
#endif
#define BDK_CSR_WAIT_FOR_FIELD(node, csr, field, op, value, timeout_usec) \
({int result; \
do { \
uint64_t done = bdk_clock_get_count(BDK_CLOCK_TIME) + (uint64_t)timeout_usec * \
bdk_clock_get_rate(bdk_numa_local(), BDK_CLOCK_TIME) / 1000000; \
typedef_##csr c; \
uint64_t _tmp_address = csr; \
while (1) \
{ \
c.u = bdk_csr_read(node, bustype_##csr, busnum_##csr, sizeof(typedef_##csr), _tmp_address); \
if ((c.s.field) op (value)) { \
result = 0; \
break; \
} else if (bdk_clock_get_count(BDK_CLOCK_TIME) > done) { \
result = -1; \
break; \
} \
} \
} while (0); \
result;})
/**
* This macro spins on a field waiting for it to reach a value. It
@ -299,6 +329,8 @@ static inline void bdk_csr_write(bdk_node_t node, bdk_csr_type_t type, int busnu
* change bit locations, the compiler will not catch those changes
* with this macro. Changes silently do the wrong thing at runtime.
*/
/* FIXME(dhendrix): removed bdk_thread_yield() */
#if 0
#define BDK_CSR_WAIT_FOR_CHIP_FIELD(node, csr, chip, field, op, value, timeout_usec) \
({int result; \
do { \
@ -320,5 +352,27 @@ static inline void bdk_csr_write(bdk_node_t node, bdk_csr_type_t type, int busnu
} \
} while (0); \
result;})
#endif
#define BDK_CSR_WAIT_FOR_CHIP_FIELD(node, csr, chip, field, op, value, timeout_usec) \
({int result; \
do { \
uint64_t done = bdk_clock_get_count(BDK_CLOCK_TIME) + (uint64_t)timeout_usec * \
bdk_clock_get_rate(bdk_numa_local(), BDK_CLOCK_TIME) / 1000000; \
typedef_##csr c; \
uint64_t _tmp_address = csr; \
while (1) \
{ \
c.u = bdk_csr_read(node, bustype_##csr, busnum_##csr, sizeof(typedef_##csr), _tmp_address); \
if ((c.chip.field) op (value)) { \
result = 0; \
break; \
} else if (bdk_clock_get_count(BDK_CLOCK_TIME) > done) { \
result = -1; \
break; \
} \
} \
} while (0); \
result;})
/** @} */
#endif

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -41,6 +41,12 @@
* PERFORMANCE OF THE SOFTWARE LIES WITH YOU.
***********************license end**************************************/
/* FIXME(dhendrix) added to make compiler happy. However this introduces a
* circular dependency and the typdef'd bdk_lmcx_modereg_params2_t makes
* forward declaration impossible. */
//#include <libdram/libdram-config.h>
#include <bdk-minimal.h>
#include <libbdk-arch/bdk-model.h>
/**
* @file

View File

@ -41,6 +41,7 @@
* PERFORMANCE OF THE SOFTWARE LIES WITH YOU.
***********************license end**************************************/
#include <bdk-minimal.h> /* FIXME: added by dhendrix */
/**
* @file

File diff suppressed because it is too large Load Diff

View File

@ -41,6 +41,7 @@
* PERFORMANCE OF THE SOFTWARE LIES WITH YOU.
***********************license end**************************************/
#include <bdk.h> /* FIXME(dhendrix): added to satisfy compiler... */
/**
* @file

File diff suppressed because it is too large Load Diff

View File

@ -41,6 +41,8 @@
* PERFORMANCE OF THE SOFTWARE LIES WITH YOU.
***********************license end**************************************/
#include <bdk-minimal.h>
#include <libbdk-arch/bdk-csr.h>
/**
* @file

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,551 @@
#ifndef __BDK_CSRS_SMI_H__
#define __BDK_CSRS_SMI_H__
/* This file is auto-generated. Do not edit */
/***********************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 NETWORKS 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**************************************/
/**
* @file
*
* Configuration and status register (CSR) address and type definitions for
* Cavium SMI.
*
* This file is auto generated. Do not edit.
*
*/
/**
* Enumeration smi_bar_e
*
* SMI Base Address Register Enumeration
* Enumerates the base address registers.
*/
#define BDK_SMI_BAR_E_SMI_PF_BAR0_CN8 (0x87e005000000ll)
#define BDK_SMI_BAR_E_SMI_PF_BAR0_CN8_SIZE 0x800000ull
#define BDK_SMI_BAR_E_SMI_PF_BAR0_CN9 (0x87e005000000ll)
#define BDK_SMI_BAR_E_SMI_PF_BAR0_CN9_SIZE 0x100000ull
/**
* Register (RSL) smi_#_clk
*
* SMI Clock Control Register
* This register determines the SMI timing characteristics.
* If software wants to change SMI CLK timing parameters ([SAMPLE]/[SAMPLE_HI]), software
* must delay the SMI_()_CLK CSR write by at least 512 coprocessor-clock cycles after the
* previous SMI operation is finished.
*/
union bdk_smi_x_clk
{
uint64_t u;
struct bdk_smi_x_clk_s
{
#if __BYTE_ORDER == __BIG_ENDIAN /* Word 0 - Big Endian */
uint64_t reserved_25_63 : 39;
uint64_t mode : 1; /**< [ 24: 24](R/W) IEEE operating mode; 0 = Clause 22 compliant, 1 = Clause 45 compliant. */
uint64_t reserved_21_23 : 3;
uint64_t sample_hi : 5; /**< [ 20: 16](R/W) Sample (extended bits). Specifies in coprocessor clock cycles when to sample read data. */
uint64_t sample_mode : 1; /**< [ 15: 15](R/W) Read data sampling mode.
According to the 802.3 specification, on read operations, the STA transitions SMIn_MDC and
the PHY drives SMIn_MDIO with some delay relative to that edge. This is Edge1.
The STA then samples SMIn_MDIO on the next rising edge of SMIn_MDC. This is Edge2. The
read data can be sampled relative to either edge.
0 = Sample time is relative to Edge2.
1 = Sample time is relative to Edge1. */
uint64_t reserved_14 : 1;
uint64_t clk_idle : 1; /**< [ 13: 13](R/W) SMIn_MDC toggle. When set, this bit causes SMIn_MDC not to toggle on idle cycles. */
uint64_t preamble : 1; /**< [ 12: 12](R/W) Preamble. When this bit is set, the 32-bit preamble is sent first on SMI transactions.
This field must be set to 1 when [MODE] = 1 in order for the receiving PHY to correctly
frame the transaction. */
uint64_t sample : 4; /**< [ 11: 8](R/W) Sample read data. Specifies the number of coprocessor clock cycles after the rising edge
of SMIn_MDC to wait before sampling read data.
_ ([SAMPLE_HI],[SAMPLE]) \> 1
_ ([SAMPLE_HI],[SAMPLE]) + 3 \<= 2 * [PHASE] */
uint64_t phase : 8; /**< [ 7: 0](R/W) MDC clock phase. Specifies the number of coprocessor clock cycles that make up an SMIn_MDC
phase.
_ [PHASE] \> 2 */
#else /* Word 0 - Little Endian */
uint64_t phase : 8; /**< [ 7: 0](R/W) MDC clock phase. Specifies the number of coprocessor clock cycles that make up an SMIn_MDC
phase.
_ [PHASE] \> 2 */
uint64_t sample : 4; /**< [ 11: 8](R/W) Sample read data. Specifies the number of coprocessor clock cycles after the rising edge
of SMIn_MDC to wait before sampling read data.
_ ([SAMPLE_HI],[SAMPLE]) \> 1
_ ([SAMPLE_HI],[SAMPLE]) + 3 \<= 2 * [PHASE] */
uint64_t preamble : 1; /**< [ 12: 12](R/W) Preamble. When this bit is set, the 32-bit preamble is sent first on SMI transactions.
This field must be set to 1 when [MODE] = 1 in order for the receiving PHY to correctly
frame the transaction. */
uint64_t clk_idle : 1; /**< [ 13: 13](R/W) SMIn_MDC toggle. When set, this bit causes SMIn_MDC not to toggle on idle cycles. */
uint64_t reserved_14 : 1;
uint64_t sample_mode : 1; /**< [ 15: 15](R/W) Read data sampling mode.
According to the 802.3 specification, on read operations, the STA transitions SMIn_MDC and
the PHY drives SMIn_MDIO with some delay relative to that edge. This is Edge1.
The STA then samples SMIn_MDIO on the next rising edge of SMIn_MDC. This is Edge2. The
read data can be sampled relative to either edge.
0 = Sample time is relative to Edge2.
1 = Sample time is relative to Edge1. */
uint64_t sample_hi : 5; /**< [ 20: 16](R/W) Sample (extended bits). Specifies in coprocessor clock cycles when to sample read data. */
uint64_t reserved_21_23 : 3;
uint64_t mode : 1; /**< [ 24: 24](R/W) IEEE operating mode; 0 = Clause 22 compliant, 1 = Clause 45 compliant. */
uint64_t reserved_25_63 : 39;
#endif /* Word 0 - End */
} s;
/* struct bdk_smi_x_clk_s cn8; */
struct bdk_smi_x_clk_cn9
{
#if __BYTE_ORDER == __BIG_ENDIAN /* Word 0 - Big Endian */
uint64_t reserved_25_63 : 39;
uint64_t mode : 1; /**< [ 24: 24](R/W) IEEE operating mode; 0 = Clause 22 compliant, 1 = Clause 45 compliant. */
uint64_t reserved_21_23 : 3;
uint64_t sample_hi : 5; /**< [ 20: 16](R/W) Sample (extended bits). Specifies in coprocessor clock cycles when to sample read data. */
uint64_t sample_mode : 1; /**< [ 15: 15](R/W) Read data sampling mode.
According to the 802.3 specification, on read operations, the STA transitions SMIn_MDC and
the PHY drives SMIn_MDIO with some delay relative to that edge. This is Edge1.
The STA then samples SMIn_MDIO on the next rising edge of SMIn_MDC. This is Edge2. The
read data can be sampled relative to either edge.
0 = Sample time is relative to Edge2.
1 = Sample time is relative to Edge1. */
uint64_t reserved_14 : 1;
uint64_t clk_idle : 1; /**< [ 13: 13](R/W) SMIn_MDC toggle. When set, this bit causes SMIn_MDC not to toggle on idle cycles. */
uint64_t preamble : 1; /**< [ 12: 12](R/W) Preamble. When this bit is set, the 32-bit preamble is sent first on SMI transactions.
This field must be set to 1 when [MODE] = 1 in order for the receiving PHY to correctly
frame the transaction. */
uint64_t sample : 4; /**< [ 11: 8](R/W) Sample read data. Specifies the number of coprocessor clock cycles after the rising edge
of SMIn_MDC to wait before sampling read data.
_ ([SAMPLE_HI],[SAMPLE]) \> 1
_ ([SAMPLE_HI],[SAMPLE]) + 3 \<= 2 * [PHASE] */
uint64_t phase : 8; /**< [ 7: 0](R/W) MDC clock phase. Specifies the number of coprocessor clock cycles that make up an SMIn_MDC
phase.
_ [PHASE] \> 2
Internal:
FIXME number of 100MHz clocks or coproc clocks based on CSR that defaults to 100MHz. */
#else /* Word 0 - Little Endian */
uint64_t phase : 8; /**< [ 7: 0](R/W) MDC clock phase. Specifies the number of coprocessor clock cycles that make up an SMIn_MDC
phase.
_ [PHASE] \> 2
Internal:
FIXME number of 100MHz clocks or coproc clocks based on CSR that defaults to 100MHz. */
uint64_t sample : 4; /**< [ 11: 8](R/W) Sample read data. Specifies the number of coprocessor clock cycles after the rising edge
of SMIn_MDC to wait before sampling read data.
_ ([SAMPLE_HI],[SAMPLE]) \> 1
_ ([SAMPLE_HI],[SAMPLE]) + 3 \<= 2 * [PHASE] */
uint64_t preamble : 1; /**< [ 12: 12](R/W) Preamble. When this bit is set, the 32-bit preamble is sent first on SMI transactions.
This field must be set to 1 when [MODE] = 1 in order for the receiving PHY to correctly
frame the transaction. */
uint64_t clk_idle : 1; /**< [ 13: 13](R/W) SMIn_MDC toggle. When set, this bit causes SMIn_MDC not to toggle on idle cycles. */
uint64_t reserved_14 : 1;
uint64_t sample_mode : 1; /**< [ 15: 15](R/W) Read data sampling mode.
According to the 802.3 specification, on read operations, the STA transitions SMIn_MDC and
the PHY drives SMIn_MDIO with some delay relative to that edge. This is Edge1.
The STA then samples SMIn_MDIO on the next rising edge of SMIn_MDC. This is Edge2. The
read data can be sampled relative to either edge.
0 = Sample time is relative to Edge2.
1 = Sample time is relative to Edge1. */
uint64_t sample_hi : 5; /**< [ 20: 16](R/W) Sample (extended bits). Specifies in coprocessor clock cycles when to sample read data. */
uint64_t reserved_21_23 : 3;
uint64_t mode : 1; /**< [ 24: 24](R/W) IEEE operating mode; 0 = Clause 22 compliant, 1 = Clause 45 compliant. */
uint64_t reserved_25_63 : 39;
#endif /* Word 0 - End */
} cn9;
};
typedef union bdk_smi_x_clk bdk_smi_x_clk_t;
static inline uint64_t BDK_SMI_X_CLK(unsigned long a) __attribute__ ((pure, always_inline));
static inline uint64_t BDK_SMI_X_CLK(unsigned long a)
{
if (a<=1)
return 0x87e005003818ll + 0x80ll * ((a) & 0x1);
__bdk_csr_fatal("SMI_X_CLK", 1, a, 0, 0, 0);
}
#define typedef_BDK_SMI_X_CLK(a) bdk_smi_x_clk_t
#define bustype_BDK_SMI_X_CLK(a) BDK_CSR_TYPE_RSL
#define basename_BDK_SMI_X_CLK(a) "SMI_X_CLK"
#define device_bar_BDK_SMI_X_CLK(a) 0x0 /* PF_BAR0 */
#define busnum_BDK_SMI_X_CLK(a) (a)
#define arguments_BDK_SMI_X_CLK(a) (a),-1,-1,-1
/**
* Register (RSL) smi_#_clken
*
* SMI Clock Enable Register
* This register is to force conditional clock enable.
*/
union bdk_smi_x_clken
{
uint64_t u;
struct bdk_smi_x_clken_s
{
#if __BYTE_ORDER == __BIG_ENDIAN /* Word 0 - Big Endian */
uint64_t reserved_1_63 : 63;
uint64_t clken : 1; /**< [ 0: 0](R/W) Force the conditional clocking within SMI to be always on. For diagnostic use only. */
#else /* Word 0 - Little Endian */
uint64_t clken : 1; /**< [ 0: 0](R/W) Force the conditional clocking within SMI to be always on. For diagnostic use only. */
uint64_t reserved_1_63 : 63;
#endif /* Word 0 - End */
} s;
/* struct bdk_smi_x_clken_s cn; */
};
typedef union bdk_smi_x_clken bdk_smi_x_clken_t;
static inline uint64_t BDK_SMI_X_CLKEN(unsigned long a) __attribute__ ((pure, always_inline));
static inline uint64_t BDK_SMI_X_CLKEN(unsigned long a)
{
if (CAVIUM_IS_MODEL(CAVIUM_CN9XXX) && (a<=1))
return 0x87e005003830ll + 0x80ll * ((a) & 0x1);
__bdk_csr_fatal("SMI_X_CLKEN", 1, a, 0, 0, 0);
}
#define typedef_BDK_SMI_X_CLKEN(a) bdk_smi_x_clken_t
#define bustype_BDK_SMI_X_CLKEN(a) BDK_CSR_TYPE_RSL
#define basename_BDK_SMI_X_CLKEN(a) "SMI_X_CLKEN"
#define device_bar_BDK_SMI_X_CLKEN(a) 0x0 /* PF_BAR0 */
#define busnum_BDK_SMI_X_CLKEN(a) (a)
#define arguments_BDK_SMI_X_CLKEN(a) (a),-1,-1,-1
/**
* Register (RSL) smi_#_cmd
*
* SMI Command Control Register
* This register forces a read or write command to the PHY. Write operations to this register
* create SMI transactions. Software will poll (depending on the transaction type).
*/
union bdk_smi_x_cmd
{
uint64_t u;
struct bdk_smi_x_cmd_s
{
#if __BYTE_ORDER == __BIG_ENDIAN /* Word 0 - Big Endian */
uint64_t reserved_18_63 : 46;
uint64_t phy_op : 2; /**< [ 17: 16](R/W) PHY opcode, depending on SMI_()_CLK[MODE] setting.
* If SMI_()_CLK[MODE] = 0 (\<=1Gbs / Clause 22):
0 = Write operation, encoded in the frame as 01.
1 = Read operation, encoded in the frame as 10.
* If SMI_()_CLK[MODE] = 1 (\>1Gbs / Clause 45):
0x0 = Address.
0x1 = Write.
0x2 = Post-read-increment-address.
0x3 = Read. */
uint64_t reserved_13_15 : 3;
uint64_t phy_adr : 5; /**< [ 12: 8](R/W) PHY address. */
uint64_t reserved_5_7 : 3;
uint64_t reg_adr : 5; /**< [ 4: 0](R/W) PHY register offset. */
#else /* Word 0 - Little Endian */
uint64_t reg_adr : 5; /**< [ 4: 0](R/W) PHY register offset. */
uint64_t reserved_5_7 : 3;
uint64_t phy_adr : 5; /**< [ 12: 8](R/W) PHY address. */
uint64_t reserved_13_15 : 3;
uint64_t phy_op : 2; /**< [ 17: 16](R/W) PHY opcode, depending on SMI_()_CLK[MODE] setting.
* If SMI_()_CLK[MODE] = 0 (\<=1Gbs / Clause 22):
0 = Write operation, encoded in the frame as 01.
1 = Read operation, encoded in the frame as 10.
* If SMI_()_CLK[MODE] = 1 (\>1Gbs / Clause 45):
0x0 = Address.
0x1 = Write.
0x2 = Post-read-increment-address.
0x3 = Read. */
uint64_t reserved_18_63 : 46;
#endif /* Word 0 - End */
} s;
/* struct bdk_smi_x_cmd_s cn; */
};
typedef union bdk_smi_x_cmd bdk_smi_x_cmd_t;
static inline uint64_t BDK_SMI_X_CMD(unsigned long a) __attribute__ ((pure, always_inline));
static inline uint64_t BDK_SMI_X_CMD(unsigned long a)
{
if (a<=1)
return 0x87e005003800ll + 0x80ll * ((a) & 0x1);
__bdk_csr_fatal("SMI_X_CMD", 1, a, 0, 0, 0);
}
#define typedef_BDK_SMI_X_CMD(a) bdk_smi_x_cmd_t
#define bustype_BDK_SMI_X_CMD(a) BDK_CSR_TYPE_RSL
#define basename_BDK_SMI_X_CMD(a) "SMI_X_CMD"
#define device_bar_BDK_SMI_X_CMD(a) 0x0 /* PF_BAR0 */
#define busnum_BDK_SMI_X_CMD(a) (a)
#define arguments_BDK_SMI_X_CMD(a) (a),-1,-1,-1
/**
* Register (RSL) smi_#_en
*
* SMI Enable Register
* Enables the SMI interface.
*/
union bdk_smi_x_en
{
uint64_t u;
struct bdk_smi_x_en_s
{
#if __BYTE_ORDER == __BIG_ENDIAN /* Word 0 - Big Endian */
uint64_t reserved_1_63 : 63;
uint64_t en : 1; /**< [ 0: 0](R/W) SMI/MDIO interface enable:
1 = Enable interface.
0 = Disable interface: no transactions, no SMIn_MDC transitions. */
#else /* Word 0 - Little Endian */
uint64_t en : 1; /**< [ 0: 0](R/W) SMI/MDIO interface enable:
1 = Enable interface.
0 = Disable interface: no transactions, no SMIn_MDC transitions. */
uint64_t reserved_1_63 : 63;
#endif /* Word 0 - End */
} s;
/* struct bdk_smi_x_en_s cn; */
};
typedef union bdk_smi_x_en bdk_smi_x_en_t;
static inline uint64_t BDK_SMI_X_EN(unsigned long a) __attribute__ ((pure, always_inline));
static inline uint64_t BDK_SMI_X_EN(unsigned long a)
{
if (a<=1)
return 0x87e005003820ll + 0x80ll * ((a) & 0x1);
__bdk_csr_fatal("SMI_X_EN", 1, a, 0, 0, 0);
}
#define typedef_BDK_SMI_X_EN(a) bdk_smi_x_en_t
#define bustype_BDK_SMI_X_EN(a) BDK_CSR_TYPE_RSL
#define basename_BDK_SMI_X_EN(a) "SMI_X_EN"
#define device_bar_BDK_SMI_X_EN(a) 0x0 /* PF_BAR0 */
#define busnum_BDK_SMI_X_EN(a) (a)
#define arguments_BDK_SMI_X_EN(a) (a),-1,-1,-1
/**
* Register (RSL) smi_#_rd_dat
*
* SMI Read Data Register
* This register contains the data in a read operation.
*/
union bdk_smi_x_rd_dat
{
uint64_t u;
struct bdk_smi_x_rd_dat_s
{
#if __BYTE_ORDER == __BIG_ENDIAN /* Word 0 - Big Endian */
uint64_t reserved_18_63 : 46;
uint64_t pending : 1; /**< [ 17: 17](RO/H) Read transaction pending. Indicates that an SMI read transaction is in flight. */
uint64_t val : 1; /**< [ 16: 16](RO/H) Read data valid. Asserts when the read transaction completes. A read to this register clears [VAL]. */
uint64_t dat : 16; /**< [ 15: 0](RO/H) Read data. */
#else /* Word 0 - Little Endian */
uint64_t dat : 16; /**< [ 15: 0](RO/H) Read data. */
uint64_t val : 1; /**< [ 16: 16](RO/H) Read data valid. Asserts when the read transaction completes. A read to this register clears [VAL]. */
uint64_t pending : 1; /**< [ 17: 17](RO/H) Read transaction pending. Indicates that an SMI read transaction is in flight. */
uint64_t reserved_18_63 : 46;
#endif /* Word 0 - End */
} s;
/* struct bdk_smi_x_rd_dat_s cn; */
};
typedef union bdk_smi_x_rd_dat bdk_smi_x_rd_dat_t;
static inline uint64_t BDK_SMI_X_RD_DAT(unsigned long a) __attribute__ ((pure, always_inline));
static inline uint64_t BDK_SMI_X_RD_DAT(unsigned long a)
{
if (a<=1)
return 0x87e005003810ll + 0x80ll * ((a) & 0x1);
__bdk_csr_fatal("SMI_X_RD_DAT", 1, a, 0, 0, 0);
}
#define typedef_BDK_SMI_X_RD_DAT(a) bdk_smi_x_rd_dat_t
#define bustype_BDK_SMI_X_RD_DAT(a) BDK_CSR_TYPE_RSL
#define basename_BDK_SMI_X_RD_DAT(a) "SMI_X_RD_DAT"
#define device_bar_BDK_SMI_X_RD_DAT(a) 0x0 /* PF_BAR0 */
#define busnum_BDK_SMI_X_RD_DAT(a) (a)
#define arguments_BDK_SMI_X_RD_DAT(a) (a),-1,-1,-1
/**
* Register (RSL) smi_#_wr_dat
*
* SMI Write Data Register
* This register provides the data for a write operation.
*/
union bdk_smi_x_wr_dat
{
uint64_t u;
struct bdk_smi_x_wr_dat_s
{
#if __BYTE_ORDER == __BIG_ENDIAN /* Word 0 - Big Endian */
uint64_t reserved_18_63 : 46;
uint64_t pending : 1; /**< [ 17: 17](RO/H) Write transaction pending. Indicates that an SMI write transaction is in flight. */
uint64_t val : 1; /**< [ 16: 16](RO/H) Write data valid. Asserts when the write transaction completes. A read to this
register clears [VAL]. */
uint64_t dat : 16; /**< [ 15: 0](R/W/H) Write data. */
#else /* Word 0 - Little Endian */
uint64_t dat : 16; /**< [ 15: 0](R/W/H) Write data. */
uint64_t val : 1; /**< [ 16: 16](RO/H) Write data valid. Asserts when the write transaction completes. A read to this
register clears [VAL]. */
uint64_t pending : 1; /**< [ 17: 17](RO/H) Write transaction pending. Indicates that an SMI write transaction is in flight. */
uint64_t reserved_18_63 : 46;
#endif /* Word 0 - End */
} s;
/* struct bdk_smi_x_wr_dat_s cn; */
};
typedef union bdk_smi_x_wr_dat bdk_smi_x_wr_dat_t;
static inline uint64_t BDK_SMI_X_WR_DAT(unsigned long a) __attribute__ ((pure, always_inline));
static inline uint64_t BDK_SMI_X_WR_DAT(unsigned long a)
{
if (a<=1)
return 0x87e005003808ll + 0x80ll * ((a) & 0x1);
__bdk_csr_fatal("SMI_X_WR_DAT", 1, a, 0, 0, 0);
}
#define typedef_BDK_SMI_X_WR_DAT(a) bdk_smi_x_wr_dat_t
#define bustype_BDK_SMI_X_WR_DAT(a) BDK_CSR_TYPE_RSL
#define basename_BDK_SMI_X_WR_DAT(a) "SMI_X_WR_DAT"
#define device_bar_BDK_SMI_X_WR_DAT(a) 0x0 /* PF_BAR0 */
#define busnum_BDK_SMI_X_WR_DAT(a) (a)
#define arguments_BDK_SMI_X_WR_DAT(a) (a),-1,-1,-1
/**
* Register (RSL) smi_drv_ctl
*
* SMI Drive Strength Control Register
* Enables the SMI interface.
*/
union bdk_smi_drv_ctl
{
uint64_t u;
struct bdk_smi_drv_ctl_s
{
#if __BYTE_ORDER == __BIG_ENDIAN /* Word 0 - Big Endian */
uint64_t reserved_11_63 : 53;
uint64_t pctl : 3; /**< [ 10: 8](R/W) PCTL drive strength control bits. Suggested values:
0x4 = 60 ohm.
0x6 = 40 ohm.
0x7 = 30 ohm. */
uint64_t reserved_3_7 : 5;
uint64_t nctl : 3; /**< [ 2: 0](R/W) NCTL drive strength control bits. Suggested values:
0x4 = 60 ohm.
0x6 = 40 ohm.
0x7 = 30 ohm. */
#else /* Word 0 - Little Endian */
uint64_t nctl : 3; /**< [ 2: 0](R/W) NCTL drive strength control bits. Suggested values:
0x4 = 60 ohm.
0x6 = 40 ohm.
0x7 = 30 ohm. */
uint64_t reserved_3_7 : 5;
uint64_t pctl : 3; /**< [ 10: 8](R/W) PCTL drive strength control bits. Suggested values:
0x4 = 60 ohm.
0x6 = 40 ohm.
0x7 = 30 ohm. */
uint64_t reserved_11_63 : 53;
#endif /* Word 0 - End */
} s;
/* struct bdk_smi_drv_ctl_s cn; */
};
typedef union bdk_smi_drv_ctl bdk_smi_drv_ctl_t;
#define BDK_SMI_DRV_CTL BDK_SMI_DRV_CTL_FUNC()
static inline uint64_t BDK_SMI_DRV_CTL_FUNC(void) __attribute__ ((pure, always_inline));
static inline uint64_t BDK_SMI_DRV_CTL_FUNC(void)
{
return 0x87e005003828ll;
}
#define typedef_BDK_SMI_DRV_CTL bdk_smi_drv_ctl_t
#define bustype_BDK_SMI_DRV_CTL BDK_CSR_TYPE_RSL
#define basename_BDK_SMI_DRV_CTL "SMI_DRV_CTL"
#define device_bar_BDK_SMI_DRV_CTL 0x0 /* PF_BAR0 */
#define busnum_BDK_SMI_DRV_CTL 0
#define arguments_BDK_SMI_DRV_CTL -1,-1,-1,-1
/**
* Register (RSL) smi_drv_rsvd
*
* INTERNAL: SMI Drive Reserve Register
*
* Enables the SMI1 interface.
*/
union bdk_smi_drv_rsvd
{
uint64_t u;
struct bdk_smi_drv_rsvd_s
{
#if __BYTE_ORDER == __BIG_ENDIAN /* Word 0 - Big Endian */
uint64_t reserved_11_63 : 53;
uint64_t pctl : 3; /**< [ 10: 8](R/W) Reserved. */
uint64_t reserved_3_7 : 5;
uint64_t nctl : 3; /**< [ 2: 0](R/W) Reserved. */
#else /* Word 0 - Little Endian */
uint64_t nctl : 3; /**< [ 2: 0](R/W) Reserved. */
uint64_t reserved_3_7 : 5;
uint64_t pctl : 3; /**< [ 10: 8](R/W) Reserved. */
uint64_t reserved_11_63 : 53;
#endif /* Word 0 - End */
} s;
/* struct bdk_smi_drv_rsvd_s cn; */
};
typedef union bdk_smi_drv_rsvd bdk_smi_drv_rsvd_t;
#define BDK_SMI_DRV_RSVD BDK_SMI_DRV_RSVD_FUNC()
static inline uint64_t BDK_SMI_DRV_RSVD_FUNC(void) __attribute__ ((pure, always_inline));
static inline uint64_t BDK_SMI_DRV_RSVD_FUNC(void)
{
if (CAVIUM_IS_MODEL(CAVIUM_CN81XX))
return 0x87e0050038a8ll;
if (CAVIUM_IS_MODEL(CAVIUM_CN83XX))
return 0x87e0050038a8ll;
if (CAVIUM_IS_MODEL(CAVIUM_CN9XXX))
return 0x87e0050038a8ll;
__bdk_csr_fatal("SMI_DRV_RSVD", 0, 0, 0, 0, 0);
}
#define typedef_BDK_SMI_DRV_RSVD bdk_smi_drv_rsvd_t
#define bustype_BDK_SMI_DRV_RSVD BDK_CSR_TYPE_RSL
#define basename_BDK_SMI_DRV_RSVD "SMI_DRV_RSVD"
#define device_bar_BDK_SMI_DRV_RSVD 0x0 /* PF_BAR0 */
#define busnum_BDK_SMI_DRV_RSVD 0
#define arguments_BDK_SMI_DRV_RSVD -1,-1,-1,-1
#endif /* __BDK_CSRS_SMI_H__ */

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,3 +1,6 @@
#ifndef __CB_BDK_FUSE_H__
#define __CB_BDK_FUSE_H__
/***********************license start***********************************
* Copyright (c) 2003-2017 Cavium Inc. (support@cavium.com). All rights
* reserved.
@ -115,3 +118,4 @@ extern int bdk_fuse_field_soft_blow(bdk_node_t node, int fuse);
*/
extern int bdk_fuse_field_hard_blow(bdk_node_t node, int start_fuse, uint64_t fuses0, uint64_t fuses1);
#endif

View File

@ -1,3 +1,5 @@
#ifndef __CB_BDK_LMT_H__
#define __CB_BDK_LMT_H__
/***********************license start***********************************
* Copyright (c) 2003-2017 Cavium Inc. (support@cavium.com). All rights
* reserved.
@ -98,3 +100,4 @@ static inline int bdk_lmt_submit(uint64_t io_address)
}
/** @} */
#endif

View File

@ -1,3 +1,6 @@
#ifndef __CB_BDK_MODEL_H__
#define __CB_BDK_MODEL_H__
/***********************license start***********************************
* Copyright (c) 2003-2017 Cavium Inc. (support@cavium.com). All rights
* reserved.
@ -88,8 +91,8 @@
#define CAVIUM_CN8XXX (CAVIUM_CN88XX_PASS1_0 | __OM_IGNORE_MODEL)
#define CAVIUM_CN9XXX (CAVIUM_CN93XX_PASS1_0 | __OM_IGNORE_MODEL)
static inline uint64_t cavium_get_model() __attribute__ ((pure, always_inline));
static inline uint64_t cavium_get_model()
static inline uint64_t cavium_get_model(void) __attribute__ ((pure, always_inline));
static inline uint64_t cavium_get_model(void)
{
#ifdef BDK_BUILD_HOST
extern uint32_t thunder_remote_get_model(void) __attribute__ ((pure));
@ -158,13 +161,5 @@ static inline int CAVIUM_IS_MODEL(uint32_t arg_model)
*/
extern int cavium_is_altpkg(uint32_t arg_model);
/**
* Return the SKU string for a chip
*
* @param node Node to get SKU for
*
* @return Chip's SKU
*/
extern const char* bdk_model_get_sku(int node);
/** @} */
#endif

View File

@ -1,3 +1,6 @@
#ifndef __CB_BDK_NUMA_H__
#define __CB_BDK_NUMA_H__
/***********************license start***********************************
* Copyright (c) 2003-2017 Cavium Inc. (support@cavium.com). All rights
* reserved.
@ -37,6 +40,10 @@
* ARISING OUT OF USE OR PERFORMANCE OF THE SOFTWARE LIES WITH YOU.
***********************license end**************************************/
/* FIXME(dhendricks): added */
#include <libbdk-arch/bdk-asm.h>
#include <libbdk-arch/bdk-model.h>
/**
* @file
*
@ -113,7 +120,7 @@ extern int bdk_numa_exists(bdk_node_t node);
*
* @return
*/
extern int bdk_numa_is_only_one();
extern int bdk_numa_is_only_one(void);
/**
* Given a physical address without a node, return the proper physical address
@ -136,4 +143,4 @@ static inline uint64_t bdk_numa_get_address(bdk_node_t node, uint64_t pa)
return pa;
}
#endif

View File

@ -1,3 +1,5 @@
#ifndef __CB_BDK_REQUIRE_H__
#define __CB_BDK_REQIORE_H__
/***********************license start***********************************
* Copyright (c) 2003-2017 Cavium Inc. (support@cavium.com). All rights
* reserved.
@ -102,6 +104,8 @@
* reference to bdk_requires_depends() which then contains strong
* references to all needed components.
*/
extern void __bdk_require_depends(void);
// FIXME(dhendrix): leave it out if possible */
//extern void __bdk_require_depends(void);
/** @} */
#endif

View File

@ -1,130 +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**************************************/
/**
* @file
*
* Utility functions for endian swapping
*
* <hr>$Revision: 32636 $<hr>
*
* @addtogroup hal
* @{
*/
/**
* Byte swap a 16 bit number
*
* @param x 16 bit number
* @return Byte swapped result
*/
static inline uint16_t bdk_swap16(uint16_t x)
{
return ((uint16_t)((((uint16_t)(x) & (uint16_t)0x00ffU) << 8) |
(((uint16_t)(x) & (uint16_t)0xff00U) >> 8) ));
}
/**
* Byte swap a 32 bit number
*
* @param x 32 bit number
* @return Byte swapped result
*/
static inline uint32_t bdk_swap32(uint32_t x)
{
#if (__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 3))
return __builtin_bswap32(x);
#else
x = ((x<<8)&0xFF00FF00) | ((x>>8)&0x00FF00FF);
x = (x>>16) | (x<<16);
return x;
#endif
}
/**
* Byte swap a 64 bit number
*
* @param x 64 bit number
* @return Byte swapped result
*/
static inline uint64_t bdk_swap64(uint64_t x)
{
#if (__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 3))
return __builtin_bswap64(x);
#else
x = ((x<< 8)&0xFF00FF00FF00FF00ULL) | ((x>> 8)&0x00FF00FF00FF00FFULL);
x = ((x<<16)&0xFFFF0000FFFF0000ULL) | ((x>>16)&0x0000FFFF0000FFFFULL);
return (x>>32) | (x<<32);
#endif
}
#if __BYTE_ORDER == __BIG_ENDIAN
#define bdk_cpu_to_le16(x) bdk_swap16(x)
#define bdk_cpu_to_le32(x) bdk_swap32(x)
#define bdk_cpu_to_le64(x) bdk_swap64(x)
#define bdk_cpu_to_be16(x) (x)
#define bdk_cpu_to_be32(x) (x)
#define bdk_cpu_to_be64(x) (x)
#else
#define bdk_cpu_to_le16(x) (x)
#define bdk_cpu_to_le32(x) (x)
#define bdk_cpu_to_le64(x) (x)
#define bdk_cpu_to_be16(x) bdk_swap16(x)
#define bdk_cpu_to_be32(x) bdk_swap32(x)
#define bdk_cpu_to_be64(x) bdk_swap64(x)
#endif
#define bdk_le16_to_cpu(x) bdk_cpu_to_le16(x)
#define bdk_le32_to_cpu(x) bdk_cpu_to_le32(x)
#define bdk_le64_to_cpu(x) bdk_cpu_to_le64(x)
#define bdk_be16_to_cpu(x) bdk_cpu_to_be16(x)
#define bdk_be32_to_cpu(x) bdk_cpu_to_be32(x)
#define bdk_be64_to_cpu(x) bdk_cpu_to_be64(x)
/** @} */

View File

@ -1,3 +1,6 @@
#ifndef __CB_BDK_WARN_H__
#define __CB_BDK_WARN_H__
/***********************license start***********************************
* Copyright (c) 2003-2017 Cavium Inc. (support@cavium.com). All rights
* reserved.
@ -37,6 +40,8 @@
* ARISING OUT OF USE OR PERFORMANCE OF THE SOFTWARE LIES WITH YOU.
***********************license end**************************************/
#include <console/console.h>
/**
* @file
*
@ -48,11 +53,14 @@
* @{
*/
extern void __bdk_die(void) __attribute__ ((noreturn));
extern void bdk_fatal(const char *format, ...) __attribute__ ((noreturn, format(printf, 1, 2)));
extern void bdk_error(const char *format, ...) __attribute__ ((format(printf, 1, 2)));
extern void bdk_warn(const char *format, ...) __attribute__ ((format(printf, 1, 2)));
#define bdk_warn_if(expression, format, ...) if (bdk_unlikely(expression)) bdk_warn(format, ##__VA_ARGS__)
#define bdk_warn(format, ...) printk(BIOS_WARNING, format, ##__VA_ARGS__)
#define bdk_error(format, ...) printk(BIOS_ERR, format, ##__VA_ARGS__)
#define bdk_fatal(format, ...) \
do { \
printk(BIOS_CRIT, format, ##__VA_ARGS__); \
while (1) \
; \
} while (0)
/* The following defines control detailed tracing of various parts of the
BDK. Each one can be enabled(1) or disabled(0) independently. These
@ -87,9 +95,6 @@ typedef enum
__BDK_TRACE_ENABLE_LAST, /* Must always be last value */
} bdk_trace_enable_t;
/* See bdk-config.c to change the trace level for before config files are loaded */
extern uint64_t bdk_trace_enables;
/**
* Macro for low level tracing of BDK functions. When enabled,
* these translate to printf() calls. The "area" is a string
@ -97,8 +102,22 @@ extern uint64_t bdk_trace_enables;
* enable macro to use. The macro expects a ';' after it.
*/
#define BDK_TRACE(area, format, ...) do { \
if (bdk_trace_enables & (1ull << BDK_TRACE_ENABLE_##area)) \
printf(#area ": " format, ##__VA_ARGS__); \
if ((BDK_TRACE_ENABLE_INIT == BDK_TRACE_ENABLE_##area && \
IS_ENABLED(CONFIG_CAVIUM_BDK_VERBOSE_INIT)) || \
(BDK_TRACE_ENABLE_DRAM == BDK_TRACE_ENABLE_##area && \
IS_ENABLED(CONFIG_CAVIUM_BDK_VERBOSE_DRAM)) || \
(BDK_TRACE_ENABLE_DRAM_TEST == BDK_TRACE_ENABLE_##area && \
IS_ENABLED(CONFIG_CAVIUM_BDK_VERBOSE_DRAM_TEST)) || \
(BDK_TRACE_ENABLE_QLM == BDK_TRACE_ENABLE_##area && \
IS_ENABLED(CONFIG_CAVIUM_BDK_VERBOSE_QLM)) || \
(BDK_TRACE_ENABLE_PCIE_CONFIG == BDK_TRACE_ENABLE_##area && \
IS_ENABLED(CONFIG_CAVIUM_BDK_VERBOSE_PCIE_CONFIG)) || \
(BDK_TRACE_ENABLE_PCIE == BDK_TRACE_ENABLE_##area && \
IS_ENABLED(CONFIG_CAVIUM_BDK_VERBOSE_PCIE)) || \
(BDK_TRACE_ENABLE_PHY == BDK_TRACE_ENABLE_##area && \
IS_ENABLED(CONFIG_CAVIUM_BDK_VERBOSE_PHY))) \
printk(BIOS_DEBUG, #area ": " format, ##__VA_ARGS__); \
} while (0)
/** @} */
#endif

View File

@ -1,43 +0,0 @@
#ifndef __LIBBDK_BIST_H
#define __LIBBDK_BIST_H
/***********************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**************************************/
void bdk_bist_check();
#endif

View File

@ -1,41 +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**************************************/
void efuse_read_all_o3(unsigned char *efuse_ptr, int cached_read);
void dump_fuses(void);
int num_fuses(void);

View File

@ -1,54 +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**************************************/
/**
* @file
*
* Boot services for CCPI
*
* @addtogroup boot
* @{
*/
/**
* Initialize the CCPI links and bringup the other nodes
*/
extern void bdk_boot_ccpi(void);
/** @} */

Some files were not shown because too many files have changed in this diff Show More