This commit is contained in:
Andy Ritger
2022-11-10 08:39:33 -08:00
parent 7c345b838b
commit 758b4ee818
1323 changed files with 262135 additions and 60754 deletions

View File

@@ -0,0 +1,195 @@
/*
* SPDX-FileCopyrightText: Copyright (c) 2020-2021 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
* SPDX-License-Identifier: MIT
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#include "common_nvswitch.h"
#include "ls10/ls10.h"
#include "ls10/clock_ls10.h"
#include "nvswitch/ls10/dev_trim.h"
#include "nvswitch/ls10/dev_soe_ip.h"
#include "nvswitch/ls10/dev_npgperf_ip.h"
#include "nvswitch/ls10/dev_nvlw_ip.h"
#include "nvswitch/ls10/dev_nport_ip.h"
#include "nvswitch/ls10/dev_minion_ip.h"
#include "nvswitch/ls10/dev_timer_ip.h"
#include "nvswitch/ls10/dev_minion_ip.h"
#include "nvswitch/ls10/dev_pri_hub_prt_ip.h"
#include "nvswitch/ls10/dev_pri_masterstation_ip.h"
//
// Initialize the software state of the switch PLL
//
NvlStatus
nvswitch_init_pll_config_ls10
(
nvswitch_device *device
)
{
NVSWITCH_PLL_LIMITS pll_limits;
NVSWITCH_PLL_INFO pll;
NvlStatus retval = NVL_SUCCESS;
//
// These parameters could come from schmoo'ing API, settings file or a ROM.
// If no configuration ROM settings are present, use the PLL documentation
//
// PLL40G_SMALL_ESD.doc
//
pll_limits.ref_min_mhz = 100;
pll_limits.ref_max_mhz = 100;
pll_limits.vco_min_mhz = 1750;
pll_limits.vco_max_mhz = 3800;
pll_limits.update_min_mhz = 13; // 13.5MHz
pll_limits.update_max_mhz = 38; // 38.4MHz
pll_limits.m_min = NV_CLOCK_NVSW_SYS_SWITCHPLL_COEFF_MDIV_MIN;
pll_limits.m_max = NV_CLOCK_NVSW_SYS_SWITCHPLL_COEFF_MDIV_MAX;
pll_limits.n_min = NV_CLOCK_NVSW_SYS_SWITCHPLL_COEFF_NDIV_MIN;
pll_limits.n_max = NV_CLOCK_NVSW_SYS_SWITCHPLL_COEFF_NDIV_MAX;
pll_limits.pl_min = NV_CLOCK_NVSW_SYS_SWITCHPLL_COEFF_PLDIV_MIN;
pll_limits.pl_max = NV_CLOCK_NVSW_SYS_SWITCHPLL_COEFF_PLDIV_MAX;
pll_limits.valid = NV_TRUE;
//
// set well known coefficients to achieve frequency
//
pll.src_freq_khz = 100000; // 100MHz
pll.M = 3;
pll.N = 80;
pll.PL = 2;
pll.dist_mode = 0; // Ignored. Only 1x supported
pll.refclk_div = NV_CLOCK_NVSW_SYS_RX_BYPASS_REFCLK_DIV_INIT;
retval = nvswitch_validate_pll_config(device, &pll, pll_limits);
if (retval != NVL_SUCCESS)
{
NVSWITCH_PRINT(device, WARN,
"Selecting default PLL setting.\n");
// Select default, safe clock
pll.src_freq_khz = 100000; // 100MHz
pll.M = 3;
pll.N = 80;
pll.PL = 2;
pll.dist_mode = 0; // Ignored. Only 1x supported
pll.refclk_div = NV_CLOCK_NVSW_SYS_RX_BYPASS_REFCLK_DIV_INIT;
retval = nvswitch_validate_pll_config(device, &pll, pll_limits);
if (retval != NVL_SUCCESS)
{
NVSWITCH_PRINT(device, ERROR,
"Default PLL setting failed.\n");
return retval;
}
}
device->switch_pll = pll;
return NVL_SUCCESS;
}
//
// Check that the PLLs are initialized. VBIOS is expected to configure PLLs
//
NvlStatus
nvswitch_init_pll_ls10
(
nvswitch_device *device
)
{
NvU32 pllRegVal;
//
// Clocks should only be initialized on silicon or a clocks netlist on emulation
//
if (IS_RTLSIM(device) || IS_EMULATION(device) || IS_FMODEL(device))
{
NVSWITCH_PRINT(device, WARN,
"%s: Skipping setup of NVSwitch clocks\n",
__FUNCTION__);
return NVL_SUCCESS;
}
pllRegVal = NVSWITCH_ENG_RD32(device, CLKS_SYS, , 0, _CLOCK_NVSW_SYS, _SWITCHPLL_CFG);
if (!FLD_TEST_DRF(_CLOCK_NVSW_SYS, _SWITCHPLL_CFG, _PLL_LOCK, _TRUE, pllRegVal))
{
NVSWITCH_PRINT(device, ERROR,
"%s: _PLL_LOCK failed\n",
__FUNCTION__);
return -NVL_INITIALIZATION_TOTAL_FAILURE;
}
pllRegVal = NVSWITCH_ENG_RD32(device, CLKS_SYS, , 0, _CLOCK_NVSW_SYS, _SWITCHPLL_CTRL);
if (!FLD_TEST_DRF_NUM(_CLOCK_NVSW_SYS, _SWITCHPLL_CTRL, _PLL_FREQLOCK, 1, pllRegVal))
{
NVSWITCH_PRINT(device, ERROR,
"%s: _PLL_FREQLOCK failed\n",
__FUNCTION__);
return -NVL_INITIALIZATION_TOTAL_FAILURE;
}
pllRegVal = NVSWITCH_ENG_RD32(device, CLKS_SYS, , 0, _CLOCK_NVSW_SYS, _SWITCHCLK_SWITCH_DIVIDER);
if (!FLD_TEST_DRF_NUM(_CLOCK_NVSW_SYS, _SWITCHCLK_SWITCH_DIVIDER, _SWITCH_DIVIDER_DONE, 1, pllRegVal))
{
NVSWITCH_PRINT(device, ERROR,
"%s: _SWITCH_DIVIDER_DONE failed\n",
__FUNCTION__);
return -NVL_INITIALIZATION_TOTAL_FAILURE;
}
pllRegVal = NVSWITCH_ENG_RD32(device, CLKS_SYS, , 0, _CLOCK_NVSW_SYS, _SYSTEM_CLK_SWITCH_DIVIDER);
if (!FLD_TEST_DRF_NUM(_CLOCK_NVSW_SYS, _SYSTEM_CLK_SWITCH_DIVIDER, _SWITCH_DIVIDER_DONE, 1, pllRegVal))
{
NVSWITCH_PRINT(device, ERROR,
"%s: _SWITCH_DIVIDER_DONE for SYSTEMCLK failed\n",
__FUNCTION__);
return -NVL_INITIALIZATION_TOTAL_FAILURE;
}
return NVL_SUCCESS;
}
//
// Initialize clock gating.
//
void
nvswitch_init_clock_gating_ls10
(
nvswitch_device *device
)
{
//
// CG and PROD settings were already handled by:
// - nvswitch_nvs_top_prod_ls10
// - nvswitch_npg_prod_ls10
// - nvswitch_apply_prod_nvlw_ls10
// - nvswitch_apply_prod_nxbar_ls10
//
// which were all called by nvswitch_initialize_ip_wrappers_ls10
return;
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,376 @@
/*
* SPDX-FileCopyrightText: Copyright (c) 2020-2022 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
* SPDX-License-Identifier: MIT
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#include "common_nvswitch.h"
#include "ls10/ls10.h"
#include "flcn/flcn_nvswitch.h"
#include "nvswitch/ls10/dev_falcon_v4.h"
#include "nvswitch/ls10/dev_riscv_pri.h"
//
// Functions shared with LR10
//
void flcnSetupHal_LR10(PFLCN pFlcn);
static NvU32
_flcnRiscvRegRead_LS10
(
nvswitch_device *device,
PFLCN pFlcn,
NvU32 offset
)
{
// Probably should perform some checks on the offset, the device, and the engine descriptor
return nvswitch_reg_read_32(device, NV_FALCON2_SOE_BASE + offset);
}
static void
_flcnRiscvRegWrite_LS10
(
nvswitch_device *device,
PFLCN pFlcn,
NvU32 offset,
NvU32 data
)
{
// Probably should perform some checks on the offset, the device, and the engine descriptor
nvswitch_reg_write_32(device, NV_FALCON2_SOE_BASE + offset, data);
}
/*!
* @brief Retrieve the size of the falcon data memory.
*
* @param[in] pGpu OBJGPU pointer
* @param[in] pFlcn Falcon object pointer
* @param[in] bFalconReachable If set, returns size that can be reached by Falcon
*
* @return IMEM size in bytes
*/
static NvU32
_flcnDmemSize_LS10
(
nvswitch_device *device,
PFLCN pFlcn
)
{
NvU32 data = flcnRegRead_HAL(device, pFlcn, NV_PFALCON_FALCON_HWCFG3);
return (DRF_VAL(_PFALCON, _FALCON_HWCFG3, _DMEM_TOTAL_SIZE, data) <<
FALCON_DMEM_BLKSIZE2);
}
/*
* @brief Get the destination after masking
* off all but the OFFSET and BLOCK in IMEM
*
* @param[in] dst Destination in IMEM
*
* @returns dst with only OFFSET and BLOCK bits set
*/
static NvU32
_flcnSetImemAddr_LS10
(
nvswitch_device *device,
PFLCN pFlcn,
NvU32 dst
)
{
NVSWITCH_ASSERT(0);
return 0;
}
/*!
*
* @brief Copy contents of pSrc to IMEM
*
* @param[in] pGpu OBJGPU pointer
* @param[in] pFlcn Falcon object pointer
* @param[in] dst Destination in IMEM
* @param[in] pSrc IMEM contents
* @param[in] sizeInBytes Total IMEM size in bytes
* @param[in] bSecure NV_TRUE if IMEM is signed
* @param[in] tag IMEM tag
* @param[in] port PMB port to copy IMEM
*
* @returns void
*/
static void
_flcnImemCopyTo_LS10
(
nvswitch_device *device,
PFLCN pFlcn,
NvU32 dst,
NvU8 *pSrc,
NvU32 sizeBytes,
NvBool bSecure,
NvU32 tag,
NvU8 port
)
{
}
/*!
*
* @brief Mask the DMEM destination to have only the BLK and OFFSET bits set
*
* @param[in] dst Destination in DMEM
*
* @returns masked destination value in DMEM
*/
static NvU32
_flcnSetDmemAddr_LS10
(
nvswitch_device *device,
PFLCN pFlcn,
NvU32 dst
)
{
return (dst & (DRF_SHIFTMASK(NV_PFALCON_FALCON_DMEMC_OFFS) |
DRF_SHIFTMASK(NV_PFALCON_FALCON_DMEMC_BLK)));
}
/*!
* Depending on the direction of the copy, copies 'sizeBytes' to/from 'pBuf'
* from/to DMEM offset 'dmemAddr' using DMEM access port 'port'.
*
* @param[in] pGpu GPU object pointer
* @param[in] pFlcn Falcon object pointer
* @param[in] dmemAddr The DMEM offset for the copy
* @param[in] pBuf The pointer to the buffer containing the data to copy
* @param[in] sizeBytes The number of bytes to copy
* @param[in] port The DMEM port index to use when accessing DMEM
* @param[in] bCopyFrom Boolean representing the copy direction (to/from DMEM)
*
* @return NV_OK if the data was successfully copied
* NV_ERR_INVALID_ARGUMENT if the input argument(s) is/are invalid
*/
static NV_STATUS
_flcnDmemTransfer_LS10
(
nvswitch_device *device,
PFLCN pFlcn,
NvU32 dmemAddr,
NvU8 *pBuf,
NvU32 sizeBytes,
NvU8 port,
NvBool bCopyFrom
)
{
NvU32 numWords;
NvU32 numBytes;
NvU32 *pData = (NvU32 *)pBuf;
NvU32 reg32;
NvU32 i;
// simply return if the copy-size is zero
if (sizeBytes == 0)
{
NVSWITCH_PRINT(device, ERROR, "Zero-byte copy requested\n");
NVSWITCH_ASSERT(0);
return -NVL_BAD_ARGS;
}
// the DMEM address must be 4-byte aligned
if (!NV_IS_ALIGNED(dmemAddr, FLCN_DMEM_ACCESS_ALIGNMENT))
{
NVSWITCH_PRINT(device, ERROR, "Source not 4-byte aligned. dmemAddr=0x%08x\n", dmemAddr);
NVSWITCH_ASSERT(0);
return -NVL_BAD_ARGS;
}
// calculate the number of words and bytes
numWords = sizeBytes >> 2;
numBytes = sizeBytes & NVSWITCH_MASK_BITS(2);
// mask off all but the OFFSET and BLOCK in DMEM offset
reg32 = flcnSetDmemAddr_HAL(device, pFlcn, dmemAddr);
if (bCopyFrom)
{
// mark auto-increment on read
reg32 = FLD_SET_DRF_NUM(_PFALCON, _FALCON_DMEMC, _AINCR, 0x1, reg32);
}
else
{
// mark auto-increment on write
reg32 = FLD_SET_DRF_NUM(_PFALCON, _FALCON_DMEMC, _AINCW, 0x1, reg32);
}
flcnRegWrite_HAL(device, pFlcn, NV_PFALCON_FALCON_DMEMC(port), reg32);
// directly copy as many words as possible
for (i = 0; i < numWords; i++)
{
if (bCopyFrom)
{
pData[i] = flcnRegRead_HAL(device, pFlcn, NV_PFALCON_FALCON_DMEMD(port));
}
else
{
flcnRegWrite_HAL(device, pFlcn, NV_PFALCON_FALCON_DMEMD(port), pData[i]);
}
}
// Check if there are left over bytes to copy
if (numBytes > 0)
{
NvU32 bytesCopied = numWords << 2;
//
// Read the contents first. If we're copying to the DMEM, we've set
// autoincrement on write, so reading does not modify the pointer. We
// can, thus, do a read/modify/write without needing to worry about the
// pointer having moved forward. There is no special explanation needed
// if we're copying from the DMEM since this is the last access to HW
// in that case.
//
reg32 = flcnRegRead_HAL(device, pFlcn, NV_PFALCON_FALCON_DMEMD(port));
if (bCopyFrom)
{
// Copy byte-by-byte into the buffer as required
for (i = 0; i < numBytes; i++)
{
pBuf[bytesCopied + i] = ((NvU8 *)&reg32)[i];
}
}
else
{
// Modify what we read byte-by-byte before writing to dmem
for (i = 0; i < numBytes; i++)
{
((NvU8 *)&reg32)[i] = pBuf[bytesCopied + i];
}
flcnRegWrite_HAL(device, pFlcn, NV_PFALCON_FALCON_DMEMD(port), reg32);
}
}
return NVL_SUCCESS;
}
static void
_flcnDbgInfoCaptureRiscvPcTrace_LS10
(
nvswitch_device *device,
PFLCN pFlcn
)
{
NvU32 ctl, ridx, widx, count, bufferSize;
NvBool full;
flcnRiscvRegWrite_HAL(device, pFlcn, NV_PRISCV_RISCV_TRACECTL,
DRF_DEF(_PRISCV_RISCV, _TRACECTL, _MODE, _FULL) |
DRF_DEF(_PRISCV_RISCV, _TRACECTL, _UMODE_ENABLE, _TRUE) |
DRF_DEF(_PRISCV_RISCV, _TRACECTL, _MMODE_ENABLE, _TRUE) |
DRF_DEF(_PRISCV_RISCV, _TRACECTL, _INTR_ENABLE, _FALSE) |
DRF_DEF(_PRISCV_RISCV, _TRACECTL, _HIGH_THSHD, _INIT));
ctl = flcnRiscvRegRead_HAL(device, pFlcn, NV_PRISCV_RISCV_TRACECTL);
full = FLD_TEST_DRF_NUM(_PRISCV_RISCV, _TRACECTL,_FULL, 1, ctl);
if (full)
{
NVSWITCH_PRINT(device, INFO, "%s: Trace buffer full. Entries may have been lost.\n", __FUNCTION__);
}
// Reset and disable buffer, we don't need it during dump
flcnRiscvRegWrite_HAL(device, pFlcn, NV_PRISCV_RISCV_TRACECTL, 0);
widx = flcnRiscvRegRead_HAL(device, pFlcn, NV_PRISCV_RISCV_TRACE_WTIDX);
widx = DRF_VAL(_PRISCV_RISCV, _TRACE_WTIDX, _WTIDX, widx);
ridx = flcnRiscvRegRead_HAL(device, pFlcn, NV_PRISCV_RISCV_TRACE_RDIDX);
bufferSize = DRF_VAL(_PRISCV_RISCV, _TRACE_RDIDX, _MAXIDX, ridx);
ridx = DRF_VAL(_PRISCV_RISCV, _TRACE_RDIDX, _RDIDX, ridx);
count = widx > ridx ? widx - ridx : bufferSize + widx - ridx;
//
// Trace buffer is full when write idx == read idx and full is set,
// otherwise it is empty.
//
if (widx == ridx && !full)
count = 0;
if (count)
{
NvU32 entry;
NVSWITCH_PRINT(device, INFO, "%s: Tracebuffer has %d entries. Starting with latest.\n", __FUNCTION__, count);
ridx = widx;
for (entry = 0; entry < count; ++entry)
{
NvU64 pc;
ridx = ridx > 0 ? ridx - 1 : bufferSize - 1;
flcnRiscvRegWrite_HAL(device, pFlcn, NV_PRISCV_RISCV_TRACE_RDIDX, DRF_NUM(_PRISCV_RISCV, _TRACE_RDIDX, _RDIDX, ridx));
pc = flcnRiscvRegRead_HAL(device, pFlcn, NV_PRISCV_RISCV_TRACEPC_HI);
pc = (pc << 32) | flcnRiscvRegRead_HAL(device, pFlcn, NV_PRISCV_RISCV_TRACEPC_LO);
NVSWITCH_PRINT(device, INFO, "%s: TRACE[%d] = 0x%16llx\n", __FUNCTION__, entry, pc);
}
}
else
{
NVSWITCH_PRINT(device, INFO, "%s: Trace buffer is empty.\n", __FUNCTION__);
}
// reset trace buffer
flcnRiscvRegWrite_HAL(device, pFlcn, NV_PRISCV_RISCV_TRACE_RDIDX, 0);
flcnRiscvRegWrite_HAL(device, pFlcn, NV_PRISCV_RISCV_TRACE_WTIDX, 0);
// Clear full and empty bits
ctl = FLD_SET_DRF_NUM(_PRISCV_RISCV, _TRACECTL, _FULL, 0, ctl);
ctl = FLD_SET_DRF_NUM(_PRISCV_RISCV, _TRACECTL, _EMPTY, 0, ctl);
flcnRiscvRegWrite_HAL(device, pFlcn, NV_PRISCV_RISCV_TRACECTL, ctl);
}
/**
* @brief set hal function pointers for functions defined in
* LS10 (i.e. this file)
*
* this function has to be at the end of the file so that all the
* other functions are already defined.
*
* @param[in] pFlcn The flcn for which to set hals
*/
void
flcnSetupHal_LS10
(
PFLCN pFlcn
)
{
flcn_hal *pHal = pFlcn->pHal;
flcnSetupHal_LR10(pFlcn);
pHal->riscvRegRead = _flcnRiscvRegRead_LS10;
pHal->riscvRegWrite = _flcnRiscvRegWrite_LS10;
pHal->dmemTransfer = _flcnDmemTransfer_LS10;
pHal->setDmemAddr = _flcnSetDmemAddr_LS10;
pHal->imemCopyTo = _flcnImemCopyTo_LS10;
pHal->setImemAddr = _flcnSetImemAddr_LS10;
pHal->dmemSize = _flcnDmemSize_LS10;
pHal->dbgInfoCaptureRiscvPcTrace = _flcnDbgInfoCaptureRiscvPcTrace_LS10;
}

View File

@@ -0,0 +1,257 @@
/*
* SPDX-FileCopyrightText: Copyright (c) 2020-2022 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
* SPDX-License-Identifier: MIT
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#include "common_nvswitch.h"
#include "ls10/ls10.h"
#include "ls10/inforom_ls10.h"
#include "inforom/ifrstruct.h"
#include "soe/soeififr.h"
#include "rmsoecmdif.h"
#include "flcn/flcn_nvswitch.h"
#include "rmflcncmdif_nvswitch.h"
NvlStatus
nvswitch_inforom_nvl_log_error_event_ls10
(
nvswitch_device *device,
void *pNvlGeneric,
void *pNvlErrorEvent,
NvBool *bDirty
)
{
return -NVL_ERR_NOT_IMPLEMENTED;
}
NvlStatus nvswitch_inforom_nvl_update_link_correctable_error_info_ls10
(
nvswitch_device *device,
void *pNvlGeneric,
void *pData,
NvU8 linkId,
NvU8 nvliptInstance,
NvU8 localLinkIdx,
void *pNvlErrorCounts,
NvBool *bDirty
)
{
return -NVL_ERR_NOT_IMPLEMENTED;
}
NvlStatus
nvswitch_oms_inforom_flush_ls10
(
nvswitch_device *device
)
{
return -NVL_ERR_NOT_IMPLEMENTED;
}
void
nvswitch_initialize_oms_state_ls10
(
nvswitch_device *device,
INFOROM_OMS_STATE *pOmsState
)
{
return;
}
NvBool
nvswitch_oms_get_device_disable_ls10
(
INFOROM_OMS_STATE *pOmsState
)
{
return NV_FALSE;
}
void
nvswitch_oms_set_device_disable_ls10
(
INFOROM_OMS_STATE *pOmsState,
NvBool bForceDeviceDisable
)
{
return;
}
void
nvswitch_inforom_ecc_get_total_errors_ls10
(
nvswitch_device *device,
INFOROM_ECC_OBJECT *pEccGeneric,
NvU64 *pCorrectedTotal,
NvU64 *pUncorrectedTotal
)
{
return;
}
NvlStatus
nvswitch_bbx_add_sxid_ls10
(
nvswitch_device *device,
NvU32 exceptionType,
NvU32 data0,
NvU32 data1,
NvU32 data2
)
{
NvlStatus status;
FLCN *pFlcn;
RM_FLCN_CMD_SOE bbxCmd;
NvU32 cmdSeqDesc;
NVSWITCH_TIMEOUT timeout;
if (!nvswitch_is_inforom_supported_ls10(device))
{
NVSWITCH_PRINT(device, INFO, "InfoROM is not supported, skipping\n");
return NVL_SUCCESS;
}
// Avoid logging SOE related SXIDs to prevent recursive errors
if (exceptionType > NVSWITCH_ERR_HW_SOE && exceptionType < NVSWITCH_ERR_HW_SOE_LAST)
{
NVSWITCH_PRINT(device, INFO, "Not logging SXID: %d to InfoROM\n", exceptionType);
return NVL_SUCCESS;
}
pFlcn = device->pSoe->pFlcn;
nvswitch_timeout_create(NVSWITCH_INTERVAL_5MSEC_IN_NS, &timeout);
nvswitch_os_memset(&bbxCmd, 0, sizeof(bbxCmd));
bbxCmd.hdr.unitId = RM_SOE_UNIT_IFR;
bbxCmd.hdr.size = sizeof(bbxCmd);
bbxCmd.cmd.ifr.cmdType = RM_SOE_IFR_BBX_SXID_ADD;
bbxCmd.cmd.ifr.bbxSxidAdd.exceptionType = exceptionType;
bbxCmd.cmd.ifr.bbxSxidAdd.data[0] = data0;
bbxCmd.cmd.ifr.bbxSxidAdd.data[1] = data1;
bbxCmd.cmd.ifr.bbxSxidAdd.data[2] = data2;
status = flcnQueueCmdPostBlocking(device, pFlcn,
(PRM_FLCN_CMD)&bbxCmd,
NULL, // pMsg
NULL, // pPayload
SOE_RM_CMDQ_LOG_ID,
&cmdSeqDesc,
&timeout);
if (status != NV_OK)
{
NVSWITCH_PRINT(device, ERROR, "%s: BBX cmd %d failed. rc:%d\n",
__FUNCTION__, bbxCmd.cmd.ifr.cmdType, status);
}
return status;
}
NvlStatus
nvswitch_bbx_unload_ls10
(
nvswitch_device *device
)
{
NvlStatus status;
FLCN *pFlcn;
RM_FLCN_CMD_SOE bbxCmd;
NvU32 cmdSeqDesc;
NVSWITCH_TIMEOUT timeout;
pFlcn = device->pSoe->pFlcn;
nvswitch_timeout_create(NVSWITCH_INTERVAL_750MSEC_IN_NS, &timeout);
nvswitch_os_memset(&bbxCmd, 0, sizeof(bbxCmd));
bbxCmd.hdr.unitId = RM_SOE_UNIT_IFR;
bbxCmd.hdr.size = sizeof(bbxCmd);
bbxCmd.cmd.ifr.cmdType = RM_SOE_IFR_BBX_SHUTDOWN;
status = flcnQueueCmdPostBlocking(device, pFlcn,
(PRM_FLCN_CMD)&bbxCmd,
NULL, // pMsg
NULL, // pPayload
SOE_RM_CMDQ_LOG_ID,
&cmdSeqDesc,
&timeout);
if (status != NV_OK)
{
NVSWITCH_PRINT(device, ERROR, "%s: BBX cmd %d failed. rc:%d\n",
__FUNCTION__, bbxCmd.cmd.ifr.cmdType, status);
}
return status;
}
NvlStatus
nvswitch_bbx_load_ls10
(
nvswitch_device *device,
NvU64 time_ns,
NvU8 osType,
NvU32 osVersion
)
{
NvlStatus status;
FLCN *pFlcn;
RM_FLCN_CMD_SOE bbxCmd;
NvU32 cmdSeqDesc = 0;
NVSWITCH_TIMEOUT timeout;
pFlcn = device->pSoe->pFlcn;
nvswitch_timeout_create(NVSWITCH_INTERVAL_750MSEC_IN_NS, &timeout);
nvswitch_os_memset(&bbxCmd, 0, sizeof(bbxCmd));
bbxCmd.hdr.unitId = RM_SOE_UNIT_IFR;
bbxCmd.hdr.size = sizeof(bbxCmd);
bbxCmd.cmd.ifr.cmdType = RM_SOE_IFR_BBX_INITIALIZE;
bbxCmd.cmd.ifr.bbxInit.osType = osType;
bbxCmd.cmd.ifr.bbxInit.osVersion = osVersion;
RM_FLCN_U64_PACK(&bbxCmd.cmd.ifr.bbxInit.time, &time_ns);
NVSWITCH_PRINT(device, INFO, "RM_SOE_IFR_BBX_INITIALIZE called, time_ns=%llu \n", time_ns);
status = flcnQueueCmdPostBlocking(device, pFlcn,
(PRM_FLCN_CMD)&bbxCmd,
NULL, // pMsg
NULL, // pPayload
SOE_RM_CMDQ_LOG_ID,
&cmdSeqDesc,
&timeout);
if (status != NV_OK)
{
NVSWITCH_PRINT(device, ERROR, "%s: BBX cmd %d failed. rc:%d\n",
__FUNCTION__, bbxCmd.cmd.ifr.cmdType, status);
}
return status;
}
NvlStatus
nvswitch_bbx_get_sxid_ls10
(
nvswitch_device *device,
NVSWITCH_GET_SXIDS_PARAMS *params
)
{
return -NVL_ERR_NOT_SUPPORTED;
}

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,975 @@
/*
* SPDX-FileCopyrightText: Copyright (c) 2020-2022 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
* SPDX-License-Identifier: MIT
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#include "nvlink_export.h"
#include "common_nvswitch.h"
#include "ls10/ls10.h"
#include "ls10/minion_ls10.h"
#include "ls10/minion_nvlink_defines_public_ls10.h"
#include "regkey_nvswitch.h"
#include "nvswitch/ls10/dev_minion_ip.h"
#include "nvswitch/ls10/dev_minion_ip_addendum.h"
#include "nvswitch/ls10/dev_ingress_ip.h"
#include "nvswitch/ls10/dev_egress_ip.h"
#include "nvswitch/ls10/dev_riscv_pri.h"
#include "nvswitch/ls10/dev_nvlphyctl_ip.h"
#include "flcn/flcn_nvswitch.h"
/*
* @Brief : Check if MINION is already running.
*
* The function assumes that if one of MINIONs is running, all of them are
* running. This approach needs to be fixed.
*
* TODO: Refactor minion code to check for each minion's status individually.
*
* @param[in] device Bootstrap MINIONs on this device
*/
static NvBool
_nvswitch_check_running_minions
(
nvswitch_device *device
)
{
NvU32 data, i;
NvBool bMinionRunning = NV_FALSE;
for (i = 0; i < NUM_MINION_ENGINE_LS10; i++)
{
if (!NVSWITCH_ENG_VALID_LS10(device, MINION, i))
{
NVSWITCH_PRINT(device, SETUP,
"%s: MINION instance %d is not valid.\n",
__FUNCTION__, i);
continue;
}
data = NVSWITCH_MINION_RD32_LS10(device, i, _CMINION, _FALCON_IRQSTAT);
if (FLD_TEST_DRF(_CMINION, _FALCON_IRQSTAT, _HALT, _FALSE, data))
{
data = NVSWITCH_MINION_RD32_LS10(device, i, _MINION, _MINION_STATUS);
if (FLD_TEST_DRF(_MINION, _MINION_STATUS, _STATUS, _BOOT, data))
{
//
// Set initialized flag if MINION is running.
// We don't want to bootstrap a falcon that is already running.
//
nvswitch_set_minion_initialized(device, i, NV_TRUE);
NVSWITCH_PRINT(device, SETUP,
"%s: MINION instance %d is already bootstrapped.\n",
__FUNCTION__, i);
bMinionRunning = NV_TRUE;
}
}
}
return bMinionRunning;
}
NvlStatus
nvswitch_minion_get_dl_status_ls10
(
nvswitch_device *device,
NvU32 linkId,
NvU32 statusIdx,
NvU32 statusArgs,
NvU32 *statusData
)
{
NVSWITCH_TIMEOUT timeout;
NvBool keepPolling;
NvU32 regData, localLinkNumber;
localLinkNumber = linkId % NVSWITCH_LINKS_PER_MINION_LS10;
if (NVSWITCH_IS_LINK_ENG_VALID_LS10(device, MINION, linkId) &&
!nvswitch_is_minion_initialized(device, NVSWITCH_GET_LINK_ENG_INST(device, linkId, MINION)))
{
NVSWITCH_PRINT(device, ERROR,
"%s: MINION %d is not initialized for link %08x.\n",
__FUNCTION__, NVSWITCH_GET_LINK_ENG_INST(device, linkId, MINION),
linkId);
return -NVL_ERR_INVALID_STATE;
}
// Query the DL status interface to get the data
NVSWITCH_MINION_LINK_WR32_LS10(device, linkId, _MINION, _NVLINK_DL_STAT(localLinkNumber),
DRF_NUM(_MINION, _NVLINK_DL_STAT, _ARGS, statusArgs) |
DRF_NUM(_MINION, _NVLINK_DL_STAT, _STATUSIDX, statusIdx));
if (IS_FMODEL(device) || IS_EMULATION(device) || IS_RTLSIM(device))
{
nvswitch_timeout_create(20 * NVSWITCH_INTERVAL_1SEC_IN_NS, &timeout);
}
else
{
nvswitch_timeout_create(NVSWITCH_INTERVAL_5MSEC_IN_NS, &timeout);
}
// Poll for READY bit to be set
do
{
keepPolling = (nvswitch_timeout_check(&timeout)) ? NV_FALSE : NV_TRUE;
regData = NVSWITCH_MINION_LINK_RD32_LS10(device, linkId, _MINION, _NVLINK_DL_STAT(localLinkNumber));
if (FLD_TEST_DRF_NUM(_MINION, _NVLINK_DL_STAT, _READY, 1, regData))
{
*statusData = NVSWITCH_MINION_LINK_RD32_LS10(device, linkId, _MINION, _NVLINK_DL_STATDATA(localLinkNumber));
return NVL_SUCCESS;
}
if (IS_FMODEL(device) || IS_RTLSIM(device))
{
nvswitch_os_sleep(1);
}
}
while (keepPolling);
NVSWITCH_PRINT(device, ERROR,
"%s: Timeout waiting for DL_STAT request to complete"
" NV_MINION_NVLINK_DL_STAT(%d) = 0x%08x\n",
__FUNCTION__, linkId, regData);
return -NVL_ERR_INVALID_STATE;
}
/*
* @Brief : Send MINION DL CMD for a particular link
*
* @param[in] device Send command to MINION on this device
* @param[in] linkNumber DLCMD will be sent on this link number
*
* @return Returns true if the DLCMD passed
*/
NvlStatus
nvswitch_minion_send_command_ls10
(
nvswitch_device *device,
NvU32 linkNumber,
NvU32 command,
NvU32 scratch0
)
{
NvU32 data = 0, localLinkNumber, statData = 0;
NvU32 ingressEccRegVal = 0, egressEccRegVal = 0;
NVSWITCH_TIMEOUT timeout;
NvBool keepPolling;
localLinkNumber = linkNumber % NVSWITCH_LINKS_PER_MINION_LS10;
if (NVSWITCH_IS_LINK_ENG_VALID_LS10(device, MINION, linkNumber) &&
!nvswitch_is_minion_initialized(device, NVSWITCH_GET_LINK_ENG_INST(device, linkNumber, MINION)))
{
NVSWITCH_PRINT(device, ERROR,
"%s: MINION %d is not initialized for link %08x.\n",
__FUNCTION__, NVSWITCH_GET_LINK_ENG_INST(device, linkNumber, MINION),
linkNumber);
return NVL_SUCCESS;
}
data = NVSWITCH_MINION_LINK_RD32_LS10(device, linkNumber, _MINION, _NVLINK_DL_CMD(localLinkNumber));
if (FLD_TEST_DRF_NUM(_MINION, _NVLINK_DL_CMD, _FAULT, 1, data))
{
NVSWITCH_PRINT(device, ERROR,
"%s: MINION %d is in fault state. NV_MINION_NVLINK_DL_CMD(%d) = %08x\n",
__FUNCTION__, NVSWITCH_GET_LINK_ENG_INST(device, linkNumber, MINION),
linkNumber, data);
return -NVL_ERR_GENERIC;
}
// Write to minion scratch if needed by command
switch (command)
{
case NV_MINION_NVLINK_DL_CMD_COMMAND_CONFIGEOM:
data = 0;
data = FLD_SET_DRF_NUM(_MINION, _MISC_0, _SCRATCH_SWRW_0, scratch0, data);
NVSWITCH_MINION_WR32_LS10(device,
NVSWITCH_GET_LINK_ENG_INST(device, linkNumber, MINION), _MINION, _MISC_0, data);
break;
case NV_MINION_NVLINK_DL_CMD_COMMAND_INITPHASE1:
//
// WAR bug 2708497
// Before INITPHASE1, we must clear these values, then set back to
// _PROD after the call
// NV_INGRESS_ERR_ECC_CTRL_NCISOC_PARITY_ENABLE
// NV_EGRESS_ERR_ECC_CTRL_NCISOC_PARITY_ENABLE
//
ingressEccRegVal = NVSWITCH_NPORT_RD32_LS10(device, linkNumber, _INGRESS, _ERR_ECC_CTRL);
NVSWITCH_NPORT_WR32_LS10(device, linkNumber, _INGRESS, _ERR_ECC_CTRL,
FLD_SET_DRF(_INGRESS, _ERR_ECC_CTRL, _NCISOC_PARITY_ENABLE, _DISABLE, ingressEccRegVal));
egressEccRegVal = NVSWITCH_NPORT_RD32_LS10(device, linkNumber, _EGRESS, _ERR_ECC_CTRL);
NVSWITCH_NPORT_WR32_LS10(device, linkNumber, _EGRESS, _ERR_ECC_CTRL,
FLD_SET_DRF(_EGRESS, _ERR_ECC_CTRL, _NCISOC_PARITY_ENABLE, _DISABLE, egressEccRegVal));
break;
default:
break;
}
data = FLD_SET_DRF_NUM(_MINION, _NVLINK_DL_CMD, _COMMAND, command, data);
data = FLD_SET_DRF_NUM(_MINION, _NVLINK_DL_CMD, _FAULT, 1, data);
NVSWITCH_MINION_LINK_WR32_LS10(device, linkNumber, _MINION, _NVLINK_DL_CMD(localLinkNumber), data);
if (IS_FMODEL(device) || IS_EMULATION(device) || IS_RTLSIM(device))
{
nvswitch_timeout_create(10 * NVSWITCH_INTERVAL_1SEC_IN_NS, &timeout);
}
else
{
nvswitch_timeout_create(NVSWITCH_INTERVAL_5MSEC_IN_NS, &timeout);
}
//
// We will exit this if the command is successful OR
// if timeout waiting for the READY bit to be set OR
// if it generates a MINION FAULT
//
do
{
keepPolling = (nvswitch_timeout_check(&timeout)) ? NV_FALSE : NV_TRUE;
data = NVSWITCH_MINION_LINK_RD32_LS10(device, linkNumber, _MINION, _NVLINK_DL_CMD(localLinkNumber));
if (FLD_TEST_DRF_NUM(_MINION, _NVLINK_DL_CMD, _READY, 1, data))
{
// The command has completed, success?
if (FLD_TEST_DRF_NUM(_MINION, _NVLINK_DL_CMD, _FAULT, 1, data))
{
NVSWITCH_PRINT(device, ERROR,
"%s: NVLink MINION command faulted!"
" NV_MINION_NVLINK_DL_CMD(%d) = 0x%08x\n",
__FUNCTION__, linkNumber, data);
// Pull fault code and subcode
if (nvswitch_minion_get_dl_status(device, linkNumber,
NV_NVLSTAT_MN00, 0, &statData) == NVL_SUCCESS)
{
NVSWITCH_PRINT(device, ERROR,
"%s: Minion DLCMD Fault code = 0x%x, Sub-code = 0x%x\n",
__FUNCTION__,
DRF_VAL(_NVLSTAT, _MN00, _LINK_INTR_CODE, statData),
DRF_VAL(_NVLSTAT, _MN00, _LINK_INTR_SUBCODE, statData));
}
else
{
NVSWITCH_PRINT(device, ERROR,
"%s: Failed to get code and subcode from DLSTAT, link %d\n",
__FUNCTION__, linkNumber);
}
// Clear the fault and return
NVSWITCH_PRINT(device, ERROR,
"%s: Clearing NVLink MINION fault for link %d\n",
__FUNCTION__, linkNumber);
data = FLD_SET_DRF_NUM(_MINION, _NVLINK_DL_CMD, _FAULT, 1, 0x0);
NVSWITCH_MINION_LINK_WR32_LS10(device, linkNumber, _MINION, _NVLINK_DL_CMD(localLinkNumber), data);
return -NVL_ERR_INVALID_STATE;
}
else
{
NVSWITCH_PRINT(device, SETUP,
"%s: NVLink MINION command %x was sent successfully for link %d\n",
__FUNCTION__, command, linkNumber);
break;
}
}
nvswitch_os_sleep(1);
}
while (keepPolling);
if (!FLD_TEST_DRF_NUM(_MINION, _NVLINK_DL_CMD, _READY, 1, data))
{
NVSWITCH_PRINT(device, ERROR,
"%s: Timeout waiting for NVLink MINION command to complete!"
" NV_MINION_NVLINK_DL_CMD(%d) = 0x%08x\n",
__FUNCTION__, linkNumber, data);
return -NVL_ERR_INVALID_STATE;
}
if (command == NV_MINION_NVLINK_DL_CMD_COMMAND_INITPHASE1)
{
NVSWITCH_NPORT_WR32_LS10(device, linkNumber, _INGRESS, _ERR_ECC_CTRL, ingressEccRegVal);
NVSWITCH_NPORT_WR32_LS10(device, linkNumber, _EGRESS, _ERR_ECC_CTRL, egressEccRegVal);
}
return NVL_SUCCESS;
}
/*
* @Brief : Bootstrap all MINIONs on the specified device
*
* @param[in] device Bootstrap MINIONs on this device
*/
NvlStatus
nvswitch_init_minion_ls10
(
nvswitch_device *device
)
{
NvlStatus status = NVL_SUCCESS;
if (_nvswitch_check_running_minions(device))
{
return NVL_SUCCESS;
}
status = -NVL_INITIALIZATION_TOTAL_FAILURE;
return status;
}
NvlStatus
nvswitch_set_minion_initialized_ls10
(
nvswitch_device *device,
NvU32 idx_minion,
NvBool initialized
)
{
ls10_device *chip_device = NVSWITCH_GET_CHIP_DEVICE_LS10(device);
if (!NVSWITCH_ENG_VALID_LS10(device, MINION, idx_minion))
{
return -NVL_BAD_ARGS;
}
chip_device->engMINION[idx_minion].initialized = initialized;
return NVL_SUCCESS;
}
NvBool
nvswitch_is_minion_initialized_ls10
(
nvswitch_device *device,
NvU32 idx_minion
)
{
ls10_device *chip_device = NVSWITCH_GET_CHIP_DEVICE_LS10(device);
if (!NVSWITCH_ENG_VALID_LS10(device, MINION, idx_minion))
{
return NV_FALSE;
}
return (chip_device->engMINION[idx_minion].initialized != 0);
}
NvlStatus
nvswitch_minion_set_sim_mode_ls10
(
nvswitch_device *device,
nvlink_link *link
)
{
NvlStatus status = NVL_SUCCESS;
NvU32 dlcmd;
NvU32 linkNumber = link->linkNumber;
NvU32 localLinkNumber = linkNumber % NVSWITCH_LINKS_PER_MINION_LS10;
switch (device->regkeys.set_simmode)
{
case NV_SWITCH_REGKEY_MINION_SET_SIMMODE_FAST:
dlcmd = NV_MINION_NVLINK_DL_CMD_COMMAND_DBG_SETSIMMODE_FAST;
break;
case NV_SWITCH_REGKEY_MINION_SET_SIMMODE_MEDIUM:
dlcmd = NV_MINION_NVLINK_DL_CMD_COMMAND_DBG_SETSIMMODE_MEDIUM;
break;
case NV_SWITCH_REGKEY_MINION_SET_SIMMODE_SLOW:
dlcmd = NV_MINION_NVLINK_DL_CMD_COMMAND_DBG_SETSIMMODE_SLOW;
break;
default:
return NVL_SUCCESS;
}
status = nvswitch_minion_send_command(device, linkNumber, dlcmd, 0);
if (status != NVL_SUCCESS)
{
NVSWITCH_PRINT(device, ERROR,
"%s: DLCMD 0x%x failed on link: %d\n",
__FUNCTION__, dlcmd, linkNumber);
return status;
}
// Setting RXCAL_EN_ALARM timer value
NVSWITCH_MINION_LINK_WR32_LS10(device, linkNumber, _MINION,
_NVLINK_DL_CMD_DATA(localLinkNumber),
NV_MINION_DL_CMD_DATA_RXCAL_EN_ALARM);
status = nvswitch_minion_send_command(device, linkNumber,
NV_MINION_NVLINK_DL_CMD_COMMAND_DBG_SETSIMMODE_RXCAL_EN_ALARM, 0);
if (status != NVL_SUCCESS)
{
NVSWITCH_PRINT(device, ERROR,
"%s: DLCMD DBG_SETSIMMODE_RXCAL_EN_ALARM failed on link: %d\n",
__FUNCTION__, linkNumber);
return status;
}
// Setting INIT_CAL_DONE timer value
NVSWITCH_MINION_LINK_WR32_LS10(device, linkNumber, _MINION,
_NVLINK_DL_CMD_DATA(localLinkNumber),
NV_MINION_DL_CMD_DATA_INIT_CAL_DONE);
status = nvswitch_minion_send_command(device, linkNumber,
NV_MINION_NVLINK_DL_CMD_COMMAND_DBG_SETSIMMODE_INIT_CAL_DONE, 0);
if (status != NVL_SUCCESS)
{
NVSWITCH_PRINT(device, ERROR,
"%s: DLCMD DBG_SETSIMMODE_INIT_CAL_DONE failed on link: %d\n",
__FUNCTION__, linkNumber);
return status;
}
return status;
}
NvlStatus
nvswitch_minion_set_smf_settings_ls10
(
nvswitch_device *device,
nvlink_link *link
)
{
NvlStatus status = NVL_SUCCESS;
NvU32 dlcmd;
NvU32 linkNumber = link->linkNumber;
switch (device->regkeys.set_smf_settings)
{
case NV_SWITCH_REGKEY_MINION_SET_SMF_SETTINGS_SLOW:
dlcmd = NV_MINION_NVLINK_DL_CMD_COMMAND_DBG_SETSIMMODE_SMF_VALUES_SLOW;
break;
case NV_SWITCH_REGKEY_MINION_SET_SMF_SETTINGS_MEDIUM:
dlcmd = NV_MINION_NVLINK_DL_CMD_COMMAND_DBG_SETSIMMODE_SMF_VALUES_MEDIUM;
break;
case NV_SWITCH_REGKEY_MINION_SET_SMF_SETTINGS_FAST:
dlcmd = NV_MINION_NVLINK_DL_CMD_COMMAND_DBG_SETSIMMODE_SMF_VALUES_FAST;
break;
case NV_SWITCH_REGKEY_MINION_SET_SMF_SETTINGS_MEDIUM_SERIAL:
dlcmd = NV_MINION_NVLINK_DL_CMD_COMMAND_DBG_SETSIMMODE_SMF_VALUES_MEDIUM_SERIAL;
break;
default:
return NVL_SUCCESS;
}
status = nvswitch_minion_send_command(device, linkNumber, dlcmd, 0);
if (status != NVL_SUCCESS)
{
NVSWITCH_PRINT(device, ERROR,
"%s: DLCMD 0x%x failed on link: %d\n",
__FUNCTION__, dlcmd, linkNumber);
return status;
}
return status;
}
NvlStatus
nvswitch_minion_select_uphy_tables_ls10
(
nvswitch_device *device,
nvlink_link *link
)
{
NvlStatus status = NVL_SUCCESS;
NvU32 dlcmd;
NvU32 linkNumber = link->linkNumber;
switch (device->regkeys.select_uphy_tables)
{
case NV_SWITCH_REGKEY_MINION_SELECT_UPHY_TABLES_SHORT:
dlcmd = NV_MINION_NVLINK_DL_CMD_COMMAND_DBG_SETSIMMODE_UPHY_TABLES_SHORT;
break;
case NV_SWITCH_REGKEY_MINION_SELECT_UPHY_TABLES_FAST:
dlcmd = NV_MINION_NVLINK_DL_CMD_COMMAND_DBG_SETSIMMODE_UPHY_TABLES_FAST;
break;
default:
return NVL_SUCCESS;
}
status = nvswitch_minion_send_command(device, linkNumber, dlcmd, 0);
if (status != NVL_SUCCESS)
{
NVSWITCH_PRINT(device, ERROR,
"%s: DLCMD 0x%x failed on link: %d\n",
__FUNCTION__, dlcmd, linkNumber);
return status;
}
return status;
}
NvlStatus
nvswitch_minion_get_rxdet_status_ls10
(
nvswitch_device *device,
NvU32 linkId
)
{
NvU32 statData;
NvlStatus status;
NVSWITCH_TIMEOUT timeout;
NvBool keepPolling;
if (IS_FMODEL(device) || IS_EMULATION(device) || IS_RTLSIM(device))
{
nvswitch_timeout_create(30*NVSWITCH_INTERVAL_1SEC_IN_NS, &timeout);
}
else
{
nvswitch_timeout_create(20 * NVSWITCH_INTERVAL_1MSEC_IN_NS, &timeout);
}
// Poll for READY bit to be set
do
{
keepPolling = (nvswitch_timeout_check(&timeout)) ? NV_FALSE : NV_TRUE;
// Check RXDET status on MINION DL STAT interface
status = nvswitch_minion_get_dl_status(device, linkId, NV_NVLSTAT_LNK2, 0, &statData);
if (status != NVL_SUCCESS)
{
return status;
}
if (FLD_TEST_DRF(_NVLSTAT, _LNK2, _RXDET_LINK_STATUS, _FOUND, statData))
{
NVSWITCH_PRINT(device, INFO,
"%s: RXDET LINK_STATUS = FOUND on link: %d\n",
__FUNCTION__, linkId);
// Retrieve which lanes were found (should be all)
device->link[linkId].lane_rxdet_status_mask =
DRF_VAL(_NVLSTAT, _LNK2, _RXDET_LANE_STATUS, statData);
//
// MINION doesn't have knowledge of lane reversal and therefore
// reports logical lanes. We must reverse the bitmask here if applicable
// since RM reports physical lanes.
//
if (nvswitch_link_lane_reversed_lr10(device, linkId))
{
NVSWITCH_REVERSE_BITMASK_32(NVSWITCH_NUM_LANES_LS10,
device->link[linkId].lane_rxdet_status_mask);
}
return NVL_SUCCESS;
}
if (FLD_TEST_DRF(_NVLSTAT, _LNK2, _RXDET_LINK_STATUS, _TIMEOUT, statData))
{
NVSWITCH_PRINT(device, ERROR,
"%s: RXDET LINK_STATUS = TIMEOUT on link: %d\n",
__FUNCTION__, linkId);
// Retrieve which lanes were found
device->link[linkId].lane_rxdet_status_mask =
DRF_VAL(_NVLSTAT, _LNK2, _RXDET_LANE_STATUS, statData);
//
// MINION doesn't have knowledge of lane reversal and therefore
// reports logical lanes. We must reverse the bitmask here if applicable
// since RM reports physical lanes.
//
if (nvswitch_link_lane_reversed_lr10(device, linkId))
{
NVSWITCH_REVERSE_BITMASK_32(NVSWITCH_NUM_LANES_LS10,
device->link[linkId].lane_rxdet_status_mask);
}
return -NVL_ERR_INVALID_STATE;
}
nvswitch_os_sleep(1);
}
while (keepPolling);
NVSWITCH_PRINT(device, ERROR,
"%s: Timeout waiting for RXDET STATUS on link: %d\n",
__FUNCTION__, linkId);
return -NVL_ERR_INVALID_STATE;
}
/*
* @Brief : Check if the RISCV CPU has started
*
* @param[in] device The Nvswitch device
* @param[in] idx_minion MINION instance to use
*/
NvBool
nvswitch_minion_is_riscv_active_ls10
(
nvswitch_device *device,
NvU32 idx_minion
)
{
NvU32 val;
val = NVSWITCH_MINION_RD32_LS10(device, idx_minion, _CMINION_RISCV, _CPUCTL);
return FLD_TEST_DRF(_CMINION, _RISCV_CPUCTL, _ACTIVE_STAT, _ACTIVE, val);
}
NvlStatus
nvswitch_minion_clear_dl_error_counters_ls10
(
nvswitch_device *device,
NvU32 linkId
)
{
NvlStatus status;
status = nvswitch_minion_send_command(device, linkId,
NV_MINION_NVLINK_DL_CMD_COMMAND_DLSTAT_CLR_DLERRCNT, 0);
if (status != NVL_SUCCESS)
{
NVSWITCH_PRINT(device, ERROR, "%s : Failed to clear error count to MINION for link # %d\n",
__FUNCTION__, linkId);
}
return status;
}
NvlStatus
nvswitch_minion_send_inband_data_ls10
(
nvswitch_device *device,
NvU32 linkId,
nvswitch_inband_send_data *inBandData
)
{
NvlStatus status = NVL_SUCCESS;
#if defined(INCLUDE_NVLINK_LIB)
NvlStatus tempStatus = NVL_SUCCESS;
NvU32 localLinkNumber = linkId % NVSWITCH_LINKS_PER_MINION_LS10;
NvU8 *sendBuffer = inBandData->sendBuffer;
NvU32 bufferSize = inBandData->bufferSize;
NvU32 data = 0;
NvU32 regval = 0;
NvU32 statData = 0;
NVSWITCH_TIMEOUT timeout;
NvBool bKeepPolling = NV_TRUE;
if (bufferSize == 0 || bufferSize > NVLINK_INBAND_MAX_XFER_SIZE)
{
NVSWITCH_PRINT(device, ERROR, "Bad Inband data size %d. Skipping Inband Send\n", bufferSize);
return -NVL_ERR_INVALID_STATE;
}
// Buffer Size must be reduced by 1 as per the minion protocol
regval = DRF_NUM(_MINION, _INBAND_SEND_DATA, _BUFFER_SIZE, (bufferSize - 1));
regval |= DRF_NUM(_MINION, _INBAND_SEND_DATA, _FLAGS,inBandData->hdr.data);
NVSWITCH_MINION_WR32_LS10(device,
NVSWITCH_GET_LINK_ENG_INST(device, linkId, MINION),
_MINION, _NVLINK_DL_CMD_DATA(localLinkNumber),
regval);
status = nvswitch_minion_send_command(device, linkId,
NV_MINION_NVLINK_DL_CMD_COMMAND_WRITE_TX_BUFFER_START, 0);
if (status != NVL_SUCCESS)
{
NVSWITCH_PRINT(device, ERROR, "Link %d Inband Buffer transfer for TX_BUFFER_START failed\n", linkId);
return status;
}
while (bufferSize != 0)
{
nvswitch_os_memcpy(&data, sendBuffer, NV_MIN(sizeof(data), bufferSize));
NVSWITCH_MINION_WR32_LS10(device,
NVSWITCH_GET_LINK_ENG_INST(device, linkId, MINION),
_MINION, _NVLINK_DL_CMD_DATA(localLinkNumber),
data);
status = nvswitch_minion_send_command(device, linkId,
NV_MINION_NVLINK_DL_CMD_COMMAND_WRITE_TX_BUFFER_MIDDLE, 0);
if (status != NVL_SUCCESS)
{
NVSWITCH_PRINT(device, ERROR, "Link %d Inband Buffer transfer failed\n", linkId);
goto clear_buffer;
}
bufferSize -= NV_MIN(sizeof(data), bufferSize);
sendBuffer += NV_MIN(sizeof(data), bufferSize);
}
status = nvswitch_minion_send_command(device, linkId,
NV_MINION_NVLINK_DL_CMD_COMMAND_WRITE_TX_BUFFER_END, 0);
if (status != NVL_SUCCESS)
{
NVSWITCH_PRINT(device, ERROR, "Link %d Inband Buffer transfer for TX_BUFFER_END\n", linkId);
goto clear_buffer;
}
// Wait for buffer complete or buffer fail
nvswitch_timeout_create(2 * NVSWITCH_INTERVAL_4SEC_IN_NS, &timeout);
do
{
bKeepPolling = !nvswitch_timeout_check(&timeout);
// DLSTAT need to explicitly checked
status = nvswitch_minion_get_dl_status(device, linkId, NV_NVLSTAT_UC01, 0, &statData);
if (status != NVL_SUCCESS)
{
NVSWITCH_PRINT(device, INFO,"%s : Failed to poll DLSTAT register for (%s):(%d)\n",
__FUNCTION__, device->name, linkId);
status = -NVL_ERR_INVALID_STATE;
goto clear_buffer;
}
if (FLD_TEST_DRF(_NVLSTAT, _UC01, _INBAND_BUFFER_COMPLETE, _TRUE, statData))
{
return NVL_SUCCESS;
}
if (FLD_TEST_DRF(_NVLSTAT, _UC01, _INBAND_BUFFER_FAIL, _TRUE, statData))
{
NVSWITCH_PRINT(device, ERROR, "Link %d Inband Buffer transfer BUFFER_FAILED\n", linkId);
status = -NVL_ERR_INVALID_STATE;
goto clear_buffer;
}
//
// Consider a case where both FM and RM trying to write on the same NVLink at the same time.
// Both are waiting on each other to read the buffer, but they have also blocked the ISR,
// as while waiting they hold the device lock. Thus, it is necessary to unblock one of them.
// And to do that we have service BUFFER_AVAILABLE while waiting.
//
nvswitch_service_minion_all_links_ls10(device);
nvswitch_os_sleep(10);
} while (bKeepPolling);
NVSWITCH_PRINT(device, ERROR, "Link %d Inband Neither got BUFFER_FAIL nor BUFFER_COMPLETE\n", linkId);
clear_buffer:
tempStatus = nvswitch_minion_send_command(device, linkId,
NV_MINION_NVLINK_DL_CMD_COMMAND_CLEAR_TX_BUFFER,
0);
if (tempStatus != NVL_SUCCESS)
{
NVSWITCH_PRINT(device, ERROR, "Link %d Inband Buffer transfer for TX_BUFFER_CLEAR\n", linkId);
return status;
}
// Check if we received BUFFER_COMPLETE is seen while doing a BUFFER_CLEAR
tempStatus = nvswitch_minion_get_dl_status(device, linkId, NV_NVLSTAT_UC01, 0, &statData);
if (tempStatus != NVL_SUCCESS)
{
NVSWITCH_PRINT(device, INFO,"%s : Failed to poll DLSTAT register for (%s):(%d)\n",
__FUNCTION__, device->name, linkId);
return status;
}
if (FLD_TEST_DRF(_NVLSTAT, _UC01, _INBAND_BUFFER_COMPLETE, _TRUE, statData))
{
status = NVL_SUCCESS;
}
else
{
status = bKeepPolling ? status: -NVL_ERR_STATE_IN_USE;
}
#endif
return status;
}
void
nvswitch_minion_receive_inband_data_ls10
(
nvswitch_device *device,
NvU32 linkId
)
{
NvlStatus status = NVL_SUCCESS;
#if defined(INCLUDE_NVLINK_LIB)
NvlStatus tempStatus = NVL_SUCCESS;
NvU32 numEntries = 0;
NvU32 i;
NvU32 localLinkNumber = linkId % NVSWITCH_LINKS_PER_MINION_LS10;
NvU8 *receiveBuffer;
NvU32 regVal, dataSize, remainingBuffer, bytesToXfer;
nvlink_inband_drv_hdr_t hdr;
status = nvswitch_minion_send_command(device, linkId,
NV_MINION_NVLINK_DL_CMD_COMMAND_READ_RX_BUFFER_START,
0);
if (status != NV_OK)
goto cleanup;
regVal = NVSWITCH_MINION_RD32_LS10(device,
NVSWITCH_GET_LINK_ENG_INST(device, linkId, MINION),
_MINION, _NVLINK_DL_CMD_DATA(localLinkNumber));
// Add 1 to the data as per minion protocol
dataSize = DRF_VAL(_MINION, _INBAND_SEND_DATA, _BUFFER_SIZE, regVal) + 1;
hdr.data = DRF_VAL(_MINION, _INBAND_SEND_DATA, _FLAGS, regVal);
numEntries = NV_ALIGN_UP(dataSize, NVLINK_INBAND_MAX_XFER_AT_ONCE)/
NVLINK_INBAND_MAX_XFER_AT_ONCE;
remainingBuffer = dataSize;
if ((hdr.data & (NVLINK_INBAND_DRV_HDR_TYPE_START |
NVLINK_INBAND_DRV_HDR_TYPE_MID |
NVLINK_INBAND_DRV_HDR_TYPE_END)) == 0)
{
NVSWITCH_PRINT(device, ERROR, "InBand: HDR is wrong\n");
goto cleanup;
}
if (hdr.data & NVLINK_INBAND_DRV_HDR_TYPE_START)
{
if (device->link[linkId].inbandData.message != NULL)
{
NVSWITCH_PRINT(device, ERROR, "InBand: Got TYPE_START for existing data\n");
NVSWITCH_ASSERT(0);
goto cleanup;
}
device->link[linkId].inbandData.message =
nvswitch_os_malloc(sizeof(nvswitch_inband_data_list));
if (device->link[linkId].inbandData.message == NULL)
{
status = -NVL_NO_MEM;
goto cleanup;
}
device->link[linkId].inbandData.message->dataSize = 0;
}
if (device->link[linkId].inbandData.message == NULL)
{
NVSWITCH_PRINT(device, ERROR, "InBand: Data being sent without _START\n");
goto cleanup;
}
receiveBuffer = device->link[linkId].inbandData.message->data;
receiveBuffer += device->link[linkId].inbandData.message->dataSize;
if (((dataSize + device->link[linkId].inbandData.message->dataSize) >
NVSWITCH_INBAND_DATA_SIZE) ||
(dataSize > NVLINK_INBAND_MAX_XFER_SIZE) ||
(dataSize == 0))
{
NVSWITCH_PRINT(device, ERROR, "InBand: Msg is of wrong Size :DataSize = %d Msg Size= %d\n",
dataSize, device->link[linkId].inbandData.message->dataSize);
NVSWITCH_ASSERT(0);
goto cleanup;
}
for (i = 0; i < numEntries; i++)
{
status = nvswitch_minion_send_command(device, linkId,
NV_MINION_NVLINK_DL_CMD_COMMAND_READ_RX_BUFFER_MIDDLE, 0);
if (status != NV_OK)
{
NVSWITCH_PRINT(device, ERROR, "Link %d Inband Buffer receive"
"for entry %d failed\n", linkId, i);
goto cleanup;
}
regVal = NVSWITCH_MINION_RD32_LS10(device,
NVSWITCH_GET_LINK_ENG_INST(device, linkId, MINION),
_MINION, _NVLINK_DL_CMD_DATA(localLinkNumber));
bytesToXfer = NV_MIN(remainingBuffer, NVLINK_INBAND_MAX_XFER_AT_ONCE);
nvswitch_os_memcpy(receiveBuffer, &regVal, bytesToXfer);
receiveBuffer += bytesToXfer;
remainingBuffer -= bytesToXfer;
}
status = nvswitch_minion_send_command(device, linkId,
NV_MINION_NVLINK_DL_CMD_COMMAND_READ_RX_BUFFER_END, 0);
if (status != NV_OK)
{
NVSWITCH_PRINT(device, ERROR, "Link %d Inband Buffer receive"
"for entry %d failed\n", linkId, numEntries);
goto cleanup;
}
device->link[linkId].inbandData.message->dataSize += dataSize;
if (hdr.data & NVLINK_INBAND_DRV_HDR_TYPE_END)
{
nvswitch_filter_messages(device, linkId);
}
return;
cleanup:
tempStatus = nvswitch_minion_send_command(device, linkId,
NV_MINION_NVLINK_DL_CMD_COMMAND_CLEAR_RX_BUFFER,
0);
if (tempStatus != NVL_SUCCESS)
{
NVSWITCH_PRINT(device, ERROR, "Link %d Inband Buffer transfer for RX_BUFFER_CLEAR\n", linkId);
return;
}
if (device->link[linkId].inbandData.message != NULL)
{
nvswitch_os_free(device->link[linkId].inbandData.message);
device->link[linkId].inbandData.message = NULL;
}
//TODO: Check if we need to send a failure msg to client?
#endif
}
NvlStatus
nvswitch_minion_get_ali_debug_registers_ls10
(
nvswitch_device *device,
nvlink_link *link,
NVSWITCH_MINION_ALI_DEBUG_REGISTERS *params
)
{
NvU32 localLinkNumber = link->linkNumber % NVSWITCH_LINKS_PER_MINION_LS10;
if (!nvswitch_minion_get_dl_status(device, link->linkNumber,
NV_NVLSTAT_MN00, 0, &(params->dlstatMn00)) == NVL_SUCCESS)
{
NVSWITCH_PRINT(device, INFO,"%s : Failed to poll DLSTAT _MN00 register for (%s):(%d)\n",
__FUNCTION__, device->name, link->linkNumber);
}
if (!nvswitch_minion_get_dl_status(device, link->linkNumber, NV_NVLSTAT_UC01, 0, &(params->dlstatUc01)))
{
NVSWITCH_PRINT(device, INFO,"%s : Failed to poll DLSTAT UC01 register for (%s):(%d)\n",
__FUNCTION__, device->name, link->linkNumber);
}
params->dlstatLinkIntr = NVSWITCH_MINION_LINK_RD32_LS10(device, link->linkNumber,
_MINION, _NVLINK_LINK_INTR(localLinkNumber));
return NVL_SUCCESS;
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,349 @@
/*
* SPDX-FileCopyrightText: Copyright (c) 2020-2022 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
* SPDX-License-Identifier: MIT
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#include "common_nvswitch.h"
#include "regkey_nvswitch.h"
#include "ls10/ls10.h"
#include "ls10/pmgr_ls10.h"
#include "error_nvswitch.h"
#include "pmgr_nvswitch.h"
#include "rom_nvswitch.h"
#include "export_nvswitch.h"
#include "soe/soe_nvswitch.h"
#include "soe/soeifcore.h"
#include "nvswitch/ls10/dev_pmgr.h"
static NvBool
_nvswitch_i2c_ports_priv_locked_ls10
(
nvswitch_device *device
)
{
NvU32 regVal;
regVal = NVSWITCH_REG_RD32(device, _PMGR, _I2C_PRIV_LEVEL_MASK(NVSWITCH_I2C_PORT_I2CA));
if (FLD_TEST_DRF(_PMGR, _I2C_PRIV_LEVEL_MASK, _WRITE_PROTECTION_LEVEL0, _DISABLE, regVal))
{
return NV_TRUE;
}
regVal = NVSWITCH_REG_RD32(device, _PMGR, _I2C_PRIV_LEVEL_MASK(NVSWITCH_I2C_PORT_I2CB));
if (FLD_TEST_DRF(_PMGR, _I2C_PRIV_LEVEL_MASK, _WRITE_PROTECTION_LEVEL0, _DISABLE, regVal))
{
return NV_TRUE;
}
regVal = NVSWITCH_REG_RD32(device, _PMGR, _I2C_PRIV_LEVEL_MASK(NVSWITCH_I2C_PORT_I2CC));
if (FLD_TEST_DRF(_PMGR, _I2C_PRIV_LEVEL_MASK, _WRITE_PROTECTION_LEVEL0, _DISABLE, regVal))
{
return NV_TRUE;
}
return NV_FALSE;
}
static NvlStatus
_nvswitch_i2c_init_soe_ls10
(
nvswitch_device *device
)
{
NvlStatus ret;
PNVSWITCH_OBJI2C pI2c;
pI2c = device->pI2c;
if (!nvswitch_is_soe_supported(device))
{
return -NVL_ERR_NOT_SUPPORTED;
}
// Setup DMA
ret = nvswitch_os_alloc_contig_memory(device->os_handle, &pI2c->pCpuAddr, SOE_I2C_DMA_BUF_SIZE,
(device->dma_addr_width == 32));
if (ret != NVL_SUCCESS)
{
NVSWITCH_PRINT(device, ERROR, "%s: nvswitch_os_alloc_contig_memory returned %d\n", __FUNCTION__, ret);
return ret;
}
nvswitch_os_memset(pI2c->pCpuAddr, 0, SOE_I2C_DMA_BUF_SIZE);
ret = nvswitch_os_map_dma_region(device->os_handle, pI2c->pCpuAddr, &pI2c->dmaHandle,
SOE_I2C_DMA_BUF_SIZE, NVSWITCH_DMA_DIR_BIDIRECTIONAL);
if (ret != NVL_SUCCESS)
{
NVSWITCH_PRINT(device, ERROR, "%s: nvswitch_os_map_dma_region returned %d\n", __FUNCTION__, ret);
nvswitch_os_free_contig_memory(device->os_handle, pI2c->pCpuAddr, SOE_I2C_DMA_BUF_SIZE);
pI2c->pCpuAddr = NULL;
return ret;
}
return NVL_SUCCESS;
}
/*! @brief Set up a port to use a PMGR implementation.
*
* @param[in] device NvSwitch device
* @param[in] port The port identifier for the bus.
*/
static void
_nvswitch_i2c_set_port_pmgr_ls10
(
nvswitch_device *device,
NvU32 port
)
{
PNVSWITCH_OBJI2C pI2c = device->pI2c;
NVSWITCH_ASSERT(port < NVSWITCH_MAX_I2C_PORTS);
pI2c->PortInfo[port] = FLD_SET_DRF(_I2C, _PORTINFO, _DEFINED, _PRESENT, pI2c->PortInfo[port]);
pI2c->Ports[port].defaultSpeedMode = NVSWITCH_I2C_SPEED_MODE_100KHZ;
pI2c->PortInfo[port] = FLD_SET_DRF(_I2C, _PORTINFO,
_ACCESS_ALLOWED, _TRUE,
pI2c->PortInfo[port]);
}
//
// Pre-initialize the software & hardware state of the switch I2C & GPIO interface
//
void
nvswitch_init_pmgr_ls10
(
nvswitch_device *device
)
{
PNVSWITCH_OBJI2C pI2c;
// Initialize I2C object
nvswitch_i2c_init(device);
pI2c = device->pI2c;
if (pI2c != NULL)
{
pI2c->kernelI2CSupported = NV_TRUE;
pI2c->soeI2CSupported = NV_TRUE;
if (_nvswitch_i2c_ports_priv_locked_ls10(device))
{
NVSWITCH_PRINT(device, WARN, "%s: I2C ports priv locked!\n", __FUNCTION__);
pI2c->kernelI2CSupported = NV_FALSE;
}
if (_nvswitch_i2c_init_soe_ls10(device) != NVL_SUCCESS)
{
pI2c->soeI2CSupported = NV_FALSE;
}
// Setup the 3 I2C ports
_nvswitch_i2c_set_port_pmgr_ls10(device, NVSWITCH_I2C_PORT_I2CA);
_nvswitch_i2c_set_port_pmgr_ls10(device, NVSWITCH_I2C_PORT_I2CB);
_nvswitch_i2c_set_port_pmgr_ls10(device, NVSWITCH_I2C_PORT_I2CC);
}
}
static const NVSWITCH_GPIO_INFO nvswitch_gpio_pin_Default[] =
{
NVSWITCH_DESCRIBE_GPIO_PIN( 0, _INSTANCE_ID0, 0, IN), // Instance ID bit 0
NVSWITCH_DESCRIBE_GPIO_PIN( 1, _INSTANCE_ID1, 0, IN), // Instance ID bit 1
NVSWITCH_DESCRIBE_GPIO_PIN( 2, _INSTANCE_ID2, 0, IN), // Instance ID bit 2
};
static const NvU32 nvswitch_gpio_pin_Default_size = NV_ARRAY_ELEMENTS(nvswitch_gpio_pin_Default);
//
// Initialize the software state of the switch I2C & GPIO interface
// Temporarily forcing default GPIO values.
//
// TODO: This function should be updated with the board values from DCB.
void
nvswitch_init_pmgr_devices_ls10
(
nvswitch_device *device
)
{
ls10_device *chip_device = NVSWITCH_GET_CHIP_DEVICE_LS10(device);
PNVSWITCH_OBJI2C pI2c = device->pI2c;
if (IS_FMODEL(device) || IS_EMULATION(device) || IS_RTLSIM(device))
{
// GPIOs not modelled on non-silicon
chip_device->gpio_pin = NULL;
chip_device->gpio_pin_size = 0;
}
else
{
chip_device->gpio_pin = nvswitch_gpio_pin_Default;
chip_device->gpio_pin_size = nvswitch_gpio_pin_Default_size;
}
pI2c->device_list = NULL;
pI2c->device_list_size = 0;
}
NvlStatus
nvswitch_get_rom_info_ls10
(
nvswitch_device *device,
NVSWITCH_EEPROM_TYPE *eeprom
)
{
NVSWITCH_PRINT(device, WARN, "%s: Function not implemented\n", __FUNCTION__);
return NVL_SUCCESS;
}
/*!
* RM Control command to determine the physical id of the device.
*/
NvU32
nvswitch_read_physical_id_ls10
(
nvswitch_device *device
)
{
ls10_device *chip_device = NVSWITCH_GET_CHIP_DEVICE_LS10(device);
NvU32 physical_id = 0;
NvU32 data;
NvU32 idx_gpio;
NvU32 input_inv;
NvU32 function_offset;
for (idx_gpio = 0; idx_gpio < chip_device->gpio_pin_size; idx_gpio++)
{
if ((chip_device->gpio_pin[idx_gpio].function >= NVSWITCH_GPIO_ENTRY_FUNCTION_INSTANCE_ID0) &&
(chip_device->gpio_pin[idx_gpio].function <= NVSWITCH_GPIO_ENTRY_FUNCTION_INSTANCE_ID6))
{
if (chip_device->gpio_pin[idx_gpio].misc == NVSWITCH_GPIO_ENTRY_MISC_IO_INV_IN)
{
input_inv = NV_PMGR_GPIO_INPUT_CNTL_1_INV_YES;
}
else
{
input_inv = NV_PMGR_GPIO_INPUT_CNTL_1_INV_NO;
}
NVSWITCH_REG_WR32(device, _PMGR, _GPIO_INPUT_CNTL_1,
DRF_NUM(_PMGR, _GPIO_INPUT_CNTL_1, _PINNUM, chip_device->gpio_pin[idx_gpio].pin) |
DRF_NUM(_PMGR, _GPIO_INPUT_CNTL_1, _INV, input_inv) |
DRF_DEF(_PMGR, _GPIO_INPUT_CNTL_1, _BYPASS_FILTER, _NO));
data = NVSWITCH_REG_RD32(device, _PMGR, _GPIO_INPUT_CNTL_1);
function_offset = chip_device->gpio_pin[idx_gpio].function -
NVSWITCH_GPIO_ENTRY_FUNCTION_INSTANCE_ID0;
physical_id |=
(DRF_VAL(_PMGR, _GPIO_INPUT_CNTL_1, _READ, data) << function_offset);
}
}
NVSWITCH_PRINT(device, SETUP, "%s Device position Id = 0x%x\n", __FUNCTION__, physical_id);
return physical_id;
}
/*!
* RM Control command to perform indexed I2C.
*/
NvlStatus
nvswitch_ctrl_i2c_indexed_ls10
(
nvswitch_device *device,
NVSWITCH_CTRL_I2C_INDEXED_PARAMS *pParams
)
{
PNVSWITCH_OBJI2C pI2c;
pI2c = device->pI2c;
if (pI2c == NULL)
{
return -NVL_ERR_NOT_SUPPORTED;
}
if (pParams == NULL)
{
return -NVL_BAD_ARGS;
}
// SW I2C only supported by kernel driver
if (device->regkeys.force_kernel_i2c == NV_SWITCH_REGKEY_FORCE_KERNEL_I2C_ENABLE ||
FLD_TEST_DRF(SWITCH_CTRL, _I2C_FLAGS, _FLAVOR, _SW, pParams->flags))
{
if (!pI2c->kernelI2CSupported)
{
return -NVL_ERR_NOT_SUPPORTED;
}
return nvswitch_ctrl_i2c_indexed_lr10(device, pParams);
}
if (pI2c->soeI2CSupported)
{
return soeI2CAccess_HAL(device, pParams);
}
return -NVL_ERR_NOT_SUPPORTED;
}
/*!
* Return if I2C transactions can be supported.
*
* @param[in] device The NvSwitch Device.
*
*/
NvBool
nvswitch_is_i2c_supported_ls10
(
nvswitch_device *device
)
{
return ((device->pI2c != NULL) &&
(device->pI2c->soeI2CSupported || device->pI2c->kernelI2CSupported));
}
/*!
* Return if I2C device and port is allowed access
*
* @param[in] device The NvSwitch Device.
* @param[in] port The I2C Port.
* @param[in] addr The I2C device to access.
* @param[in] bIsRead Boolean if I2C transaction is a read.
*
*/
NvBool
nvswitch_i2c_is_device_access_allowed_ls10
(
nvswitch_device *device,
NvU32 port,
NvU8 addr,
NvBool bIsRead
)
{
// Check will be performed in SOE
return NV_TRUE;
}

View File

@@ -0,0 +1,222 @@
/*
* SPDX-FileCopyrightText: Copyright (c) 2020-2022 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
* SPDX-License-Identifier: MIT
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#include "common_nvswitch.h"
#include "flcn/flcn_nvswitch.h"
#include "rmflcncmdif_nvswitch.h"
#include "nvVer.h"
NvlStatus
nvswitch_smbpbi_alloc_ls10
(
nvswitch_device *device
)
{
return NVL_SUCCESS;
}
NvlStatus
nvswitch_smbpbi_post_init_hal_ls10
(
nvswitch_device *device
)
{
return NVL_SUCCESS;
}
void
nvswitch_smbpbi_destroy_hal_ls10
(
nvswitch_device *device
)
{
}
NvlStatus
nvswitch_smbpbi_get_dem_num_messages_ls10
(
nvswitch_device *device,
NvU8 *pMsgCount
)
{
return -NVL_ERR_NOT_SUPPORTED;
}
NvlStatus
nvswitch_inforom_dem_load_ls10
(
nvswitch_device *device
)
{
return -NVL_ERR_NOT_SUPPORTED;
}
NvlStatus
nvswitch_smbpbi_dem_load_ls10
(
nvswitch_device *device
)
{
return -NVL_ERR_NOT_SUPPORTED;
}
void
nvswitch_smbpbi_log_message_ls10
(
nvswitch_device *device,
NvU32 num,
NvU32 msglen,
NvU8 *osErrorString
)
{
struct smbpbi *pSmbpbi = device->pSmbpbi;
RM_FLCN_CMD_SOE cmd;
RM_SOE_SMBPBI_CMD_LOG_MESSAGE *pLogCmd = &cmd.cmd.smbpbiCmd.logMessage;
NvU8 offset;
NvU8 segSize;
NVSWITCH_TIMEOUT timeout;
NvU32 cmdSeqDesc;
FLCN *pFlcn;
NvlStatus status;
if ((pSmbpbi == NULL) || (device->pSoe == NULL) ||
(pSmbpbi->logMessageNesting++ != 0))
{
goto nvswitch_smbpbi_log_message_exit;
}
pFlcn = device->pSoe->pFlcn;
nvswitch_os_memset(&cmd, 0, sizeof(cmd));
cmd.hdr.unitId = RM_SOE_UNIT_SMBPBI;
cmd.hdr.size = RM_SOE_CMD_SIZE(SMBPBI, LOG_MESSAGE);
cmd.cmd.smbpbiCmd.cmdType = RM_SOE_SMBPBI_CMD_ID_LOG_MESSAGE;
msglen = NV_MIN(msglen, RM_SOE_SMBPBI_CMD_LOG_MESSAGE_MAX_STRING);
pLogCmd->sxidId = num;
pLogCmd->msgLen = msglen;
pLogCmd->timeStamp = nvswitch_os_get_platform_time() / NVSWITCH_NSEC_PER_SEC;
for (offset = 0; msglen > 0; offset += segSize)
{
segSize = NV_MIN(msglen, RM_SOE_SMBPBI_CMD_LOG_MESSAGE_STRING_SEGMENT_SZ);
nvswitch_os_memcpy(pLogCmd->errorString, osErrorString + offset, segSize);
pLogCmd->msgOffset = offset;
pLogCmd->segSize = segSize;
nvswitch_timeout_create(NVSWITCH_INTERVAL_1SEC_IN_NS, &timeout);
status = flcnQueueCmdPostBlocking(device, pFlcn,
(PRM_FLCN_CMD)&cmd,
NULL, // pMsg - not used for now
NULL, // pPayload - not used for now
SOE_RM_CMDQ_LOG_ID,
&cmdSeqDesc,
&timeout);
if (status != NV_OK)
{
NVSWITCH_PRINT(device, ERROR, "%s: SMBPBI Log Message command failed. rc:%d\n",
__FUNCTION__, status);
break;
}
msglen -= segSize;
}
pSmbpbi->logMessageNesting = 0;
nvswitch_smbpbi_log_message_exit:
return;
}
NvlStatus
nvswitch_smbpbi_send_init_data_ls10
(
nvswitch_device *device
)
{
struct smbpbi *pSmbpbi = device->pSmbpbi;
RM_FLCN_CMD_SOE cmd;
RM_SOE_SMBPBI_CMD_INIT_DATA *pInitDataCmd = &cmd.cmd.smbpbiCmd.initData;
NVSWITCH_TIMEOUT timeout;
NvU32 cmdSeqDesc;
FLCN *pFlcn = device->pSoe->pFlcn;
NvlStatus status = NVL_SUCCESS;
ct_assert(sizeof(NV_VERSION_STRING) <= sizeof(pInitDataCmd->driverVersionString));
if (pSmbpbi == NULL)
{
goto nvswitch_smbpbi_send_init_data_exit;
}
nvswitch_os_memset(&cmd, 0, sizeof(cmd));
cmd.hdr.unitId = RM_SOE_UNIT_SMBPBI;
cmd.hdr.size = RM_SOE_CMD_SIZE(SMBPBI, INIT_DATA);
cmd.cmd.smbpbiCmd.cmdType = RM_SOE_SMBPBI_CMD_ID_INIT_DATA;
nvswitch_os_strncpy((char *)pInitDataCmd->driverVersionString,
NV_VERSION_STRING,
sizeof(pInitDataCmd->driverVersionString));
pInitDataCmd->driverVersionString[sizeof(pInitDataCmd->driverVersionString) - 1] = 0;
nvswitch_timeout_create(NVSWITCH_INTERVAL_1SEC_IN_NS, &timeout);
status = flcnQueueCmdPostBlocking(device, pFlcn,
(PRM_FLCN_CMD)&cmd,
NULL, // pMsg - not used for now
NULL, // pPayload - not used for now
SOE_RM_CMDQ_LOG_ID,
&cmdSeqDesc,
&timeout);
if (status != NV_OK)
{
NVSWITCH_PRINT(device, ERROR, "%s: SMBPBI Init Data command failed. rc:%d\n",
__FUNCTION__, status);
}
else
{
NVSWITCH_PRINT(device, INFO, "%s: SMBPBI Init Data sent to SOE.\n",
__FUNCTION__);
}
nvswitch_smbpbi_send_init_data_exit:
return status;
}
void
nvswitch_smbpbi_send_unload_ls10
(
nvswitch_device *device
)
{
}
void
nvswitch_smbpbi_dem_flush_ls10
(
nvswitch_device *device
)
{
}

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,358 @@
/*
* SPDX-FileCopyrightText: Copyright (c) 2020-2022 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
* SPDX-License-Identifier: MIT
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#include "export_nvswitch.h"
#include "common_nvswitch.h"
#include "ls10/ls10.h"
#include "ls10/therm_ls10.h"
#include "error_nvswitch.h"
#include "soe/soeiftherm.h"
#include "nvswitch/ls10/dev_therm.h"
//
// Thermal functions
//
//
// Initialize thermal offsets for External Tdiode.
//
NvlStatus
nvswitch_init_thermal_ls10
(
nvswitch_device *device
)
{
ls10_device *chip_device = NVSWITCH_GET_CHIP_DEVICE_LS10(device);
// Mark everything invalid
chip_device->tdiode.method = NVSWITCH_THERM_METHOD_UNKNOWN;
return NVL_SUCCESS;
}
static void
_nvswitch_read_max_tsense_temperature_ls10
(
nvswitch_device *device,
NVSWITCH_CTRL_GET_TEMPERATURE_PARAMS *info,
NvU32 channel
)
{
NvU32 offset;
NvU32 temperature;
temperature = NVSWITCH_REG_RD32(device, _THERM, _TSENSE_MAXIMUM_TEMPERATURE);
temperature = DRF_VAL(_THERM_TSENSE, _MAXIMUM_TEMPERATURE, _MAXIMUM_TEMPERATURE, temperature);
temperature = NV_TSENSE_FXP_9_5_TO_24_8(temperature);
if (channel == NVSWITCH_THERM_CHANNEL_LR10_TSENSE_MAX)
{
offset = NVSWITCH_REG_RD32(device, _THERM, _TSENSE_U2_A_0_BJT_0_TEMPERATURE_MODIFICATIONS);
offset = DRF_VAL(_THERM_TSENSE, _U2_A_0_BJT_0_TEMPERATURE_MODIFICATIONS, _TEMPERATURE_OFFSET, offset);
// Temperature of the sensor reported equals calculation of the max temperature reported
// from the TSENSE HUB plus the temperature offset programmed by SW. This offset needs to
// be substracted to get the actual temperature of the sensor.
temperature -= NV_TSENSE_FXP_9_5_TO_24_8(offset);
}
info->temperature[channel] = temperature;
info->status[channel] = NVL_SUCCESS;
}
static void
_nvswitch_read_external_tdiode_temperature_ls10
(
nvswitch_device *device,
NVSWITCH_CTRL_GET_TEMPERATURE_PARAMS *info,
NvU32 channel
)
{
}
//
// nvswitch_therm_read_temperature
//
// Temperature and voltage are only available on SKUs which have thermal and
// voltage sensors.
//
NvlStatus
nvswitch_ctrl_therm_read_temperature_ls10
(
nvswitch_device *device,
NVSWITCH_CTRL_GET_TEMPERATURE_PARAMS *info
)
{
NvU32 channel;
NvU32 val;
NvU32 offset;
if (!info->channelMask)
{
NVSWITCH_PRINT(device, ERROR,
"%s: No channel given in the input.\n",
__FUNCTION__);
return -NVL_BAD_ARGS;
}
nvswitch_os_memset(info->temperature, 0x0, sizeof(info->temperature));
channel = NVSWITCH_THERM_CHANNEL_LS10_TSENSE_MAX;
if (info->channelMask & NVBIT(channel))
{
_nvswitch_read_max_tsense_temperature_ls10(device, info, channel);
info->channelMask &= ~NVBIT(channel);
}
channel = NVSWITCH_THERM_CHANNEL_LS10_TSENSE_OFFSET_MAX;
if (info->channelMask & NVBIT(channel))
{
_nvswitch_read_max_tsense_temperature_ls10(device, info, channel);
info->channelMask &= ~NVBIT(channel);
}
channel = NVSWITCH_THERM_CHANNEL_LS10_TDIODE;
if (info->channelMask & NVBIT(channel))
{
_nvswitch_read_external_tdiode_temperature_ls10(device, info, channel);
info->channelMask &= ~NVBIT(channel);
}
channel = NVSWITCH_THERM_CHANNEL_LS10_TDIODE_OFFSET;
if (info->channelMask & NVBIT(channel))
{
_nvswitch_read_external_tdiode_temperature_ls10(device, info, channel);
info->channelMask &= ~NVBIT(channel);
}
channel = NVSWITCH_THERM_CHANNEL_LS10_TSENSE_0;
if (info->channelMask & NVBIT(channel))
{
offset = NVSWITCH_REG_RD32(device, _THERM, _TSENSE_U2_A_0_BJT_0_TEMPERATURE_MODIFICATIONS);
offset = DRF_VAL(_THERM_TSENSE, _U2_A_0_BJT_0_TEMPERATURE_MODIFICATIONS, _TEMPERATURE_OFFSET, offset);
offset = NV_TSENSE_FXP_9_5_TO_24_8(offset);
val = NVSWITCH_REG_RD32(device, _THERM, _TSENSE_U2_A_0_BJT_0);
val = DRF_VAL(_THERM, _TSENSE_U2_A_0_BJT_0, _TEMPERATURE, val);
val = NV_TSENSE_FXP_9_5_TO_24_8(val);
val -= offset;
info->temperature[channel] = val;
info->channelMask &= ~NVBIT(channel);
}
channel = NVSWITCH_THERM_CHANNEL_LS10_TSENSE_1;
if (info->channelMask & NVBIT(channel))
{
offset = NVSWITCH_REG_RD32(device, _THERM, _TSENSE_U2_A_0_BJT_1_TEMPERATURE_MODIFICATIONS);
offset = DRF_VAL(_THERM_TSENSE, _U2_A_0_BJT_1_TEMPERATURE_MODIFICATIONS, _TEMPERATURE_OFFSET, offset);
offset = NV_TSENSE_FXP_9_5_TO_24_8(offset);
val = NVSWITCH_REG_RD32(device, _THERM, _TSENSE_U2_A_0_BJT_1);
val = DRF_VAL(_THERM, _TSENSE_U2_A_0_BJT_1, _TEMPERATURE, val);
val = NV_TSENSE_FXP_9_5_TO_24_8(val);
val -= offset;
info->temperature[channel] = val;
info->channelMask &= ~NVBIT(channel);
}
channel = NVSWITCH_THERM_CHANNEL_LS10_TSENSE_2;
if (info->channelMask & NVBIT(channel))
{
offset = NVSWITCH_REG_RD32(device, _THERM, _TSENSE_U2_A_0_BJT_2_TEMPERATURE_MODIFICATIONS);
offset = DRF_VAL(_THERM_TSENSE, _U2_A_0_BJT_2_TEMPERATURE_MODIFICATIONS, _TEMPERATURE_OFFSET, offset);
offset = NV_TSENSE_FXP_9_5_TO_24_8(offset);
val = NVSWITCH_REG_RD32(device, _THERM, _TSENSE_U2_A_0_BJT_2);
val = DRF_VAL(_THERM, _TSENSE_U2_A_0_BJT_2, _TEMPERATURE, val);
val = NV_TSENSE_FXP_9_5_TO_24_8(val);
val -= offset;
info->temperature[channel] = val;
info->channelMask &= ~NVBIT(channel);
}
channel = NVSWITCH_THERM_CHANNEL_LS10_TSENSE_3;
if (info->channelMask & NVBIT(channel))
{
offset = NVSWITCH_REG_RD32(device, _THERM, _TSENSE_U2_A_0_BJT_3_TEMPERATURE_MODIFICATIONS);
offset = DRF_VAL(_THERM_TSENSE, _U2_A_0_BJT_3_TEMPERATURE_MODIFICATIONS, _TEMPERATURE_OFFSET, offset);
offset = NV_TSENSE_FXP_9_5_TO_24_8(offset);
val = NVSWITCH_REG_RD32(device, _THERM, _TSENSE_U2_A_0_BJT_3);
val = DRF_VAL(_THERM, _TSENSE_U2_A_0_BJT_3, _TEMPERATURE, val);
val = NV_TSENSE_FXP_9_5_TO_24_8(val);
val -= offset;
info->temperature[channel] = val;
info->channelMask &= ~NVBIT(channel);
}
channel = NVSWITCH_THERM_CHANNEL_LS10_TSENSE_4;
if (info->channelMask & NVBIT(channel))
{
offset = NVSWITCH_REG_RD32(device, _THERM, _TSENSE_U2_A_0_BJT_4_TEMPERATURE_MODIFICATIONS);
offset = DRF_VAL(_THERM_TSENSE, _U2_A_0_BJT_4_TEMPERATURE_MODIFICATIONS, _TEMPERATURE_OFFSET, offset);
offset = NV_TSENSE_FXP_9_5_TO_24_8(offset);
val = NVSWITCH_REG_RD32(device, _THERM, _TSENSE_U2_A_0_BJT_4);
val = DRF_VAL(_THERM, _TSENSE_U2_A_0_BJT_4, _TEMPERATURE, val);
val = NV_TSENSE_FXP_9_5_TO_24_8(val);
val -= offset;
info->temperature[channel] = val;
info->channelMask &= ~NVBIT(channel);
}
channel = NVSWITCH_THERM_CHANNEL_LS10_TSENSE_5;
if (info->channelMask & NVBIT(channel))
{
offset = NVSWITCH_REG_RD32(device, _THERM, _TSENSE_U2_A_0_BJT_5_TEMPERATURE_MODIFICATIONS);
offset = DRF_VAL(_THERM_TSENSE, _U2_A_0_BJT_5_TEMPERATURE_MODIFICATIONS, _TEMPERATURE_OFFSET, offset);
offset = NV_TSENSE_FXP_9_5_TO_24_8(offset);
val = NVSWITCH_REG_RD32(device, _THERM, _TSENSE_U2_A_0_BJT_5);
val = DRF_VAL(_THERM, _TSENSE_U2_A_0_BJT_5, _TEMPERATURE, val);
val = NV_TSENSE_FXP_9_5_TO_24_8(val);
val -= offset;
info->temperature[channel] = val;
info->channelMask &= ~NVBIT(channel);
}
channel = NVSWITCH_THERM_CHANNEL_LS10_TSENSE_6;
if (info->channelMask & NVBIT(channel))
{
offset = NVSWITCH_REG_RD32(device, _THERM, _TSENSE_U2_A_0_BJT_6_TEMPERATURE_MODIFICATIONS);
offset = DRF_VAL(_THERM_TSENSE, _U2_A_0_BJT_6_TEMPERATURE_MODIFICATIONS, _TEMPERATURE_OFFSET, offset);
offset = NV_TSENSE_FXP_9_5_TO_24_8(offset);
val = NVSWITCH_REG_RD32(device, _THERM, _TSENSE_U2_A_0_BJT_6);
val = DRF_VAL(_THERM, _TSENSE_U2_A_0_BJT_6, _TEMPERATURE, val);
val = NV_TSENSE_FXP_9_5_TO_24_8(val);
val -= offset;
info->temperature[channel] = val;
info->channelMask &= ~NVBIT(channel);
}
channel = NVSWITCH_THERM_CHANNEL_LS10_TSENSE_7;
if (info->channelMask & NVBIT(channel))
{
offset = NVSWITCH_REG_RD32(device, _THERM, _TSENSE_U2_A_0_BJT_7_TEMPERATURE_MODIFICATIONS);
offset = DRF_VAL(_THERM_TSENSE, _U2_A_0_BJT_7_TEMPERATURE_MODIFICATIONS, _TEMPERATURE_OFFSET, offset);
offset = NV_TSENSE_FXP_9_5_TO_24_8(offset);
val = NVSWITCH_REG_RD32(device, _THERM, _TSENSE_U2_A_0_BJT_7);
val = DRF_VAL(_THERM, _TSENSE_U2_A_0_BJT_7, _TEMPERATURE, val);
val = NV_TSENSE_FXP_9_5_TO_24_8(val);
val -= offset;
info->temperature[channel] = val;
info->channelMask &= ~NVBIT(channel);
}
channel = NVSWITCH_THERM_CHANNEL_LS10_TSENSE_8;
if (info->channelMask & NVBIT(channel))
{
offset = NVSWITCH_REG_RD32(device, _THERM, _TSENSE_U2_A_0_BJT_8_TEMPERATURE_MODIFICATIONS);
offset = DRF_VAL(_THERM_TSENSE, _U2_A_0_BJT_8_TEMPERATURE_MODIFICATIONS, _TEMPERATURE_OFFSET, offset);
offset = NV_TSENSE_FXP_9_5_TO_24_8(offset);
val = NVSWITCH_REG_RD32(device, _THERM, _TSENSE_U2_A_0_BJT_8);
val = DRF_VAL(_THERM, _TSENSE_U2_A_0_BJT_8, _TEMPERATURE, val);
val = NV_TSENSE_FXP_9_5_TO_24_8(val);
val -= offset;
info->temperature[channel] = val;
info->channelMask &= ~NVBIT(channel);
}
if (info->channelMask)
{
NVSWITCH_PRINT(device, ERROR,
"%s: ChannelMask %x absent on LS10.\n",
__FUNCTION__, info->channelMask);
return -NVL_BAD_ARGS;
}
return NVL_SUCCESS;
}
NvlStatus
nvswitch_ctrl_therm_get_temperature_limit_ls10
(
nvswitch_device *device,
NVSWITCH_CTRL_GET_TEMPERATURE_LIMIT_PARAMS *info
)
{
NvU32 threshold;
NvU32 temperature;
threshold = nvswitch_reg_read_32(device, NV_THERM_TSENSE_THRESHOLD_TEMPERATURES);
switch (info->thermalEventId)
{
case NVSWITCH_CTRL_THERMAL_EVENT_ID_WARN:
{
// Get Slowdown temperature
temperature = DRF_VAL(_THERM_TSENSE, _THRESHOLD_TEMPERATURES,
_WARNING_TEMPERATURE, threshold);
break;
}
case NVSWITCH_CTRL_THERMAL_EVENT_ID_OVERT:
{
// Get Shutdown temperature
temperature = DRF_VAL(_THERM_TSENSE, _THRESHOLD_TEMPERATURES,
_OVERTEMP_TEMPERATURE, threshold);
break;
}
default:
{
NVSWITCH_PRINT(device, ERROR, "Invalid Thermal Event Id: 0x%x\n", info->thermalEventId);
return -NVL_BAD_ARGS;
}
}
info->temperatureLimit = NV_TSENSE_FXP_9_5_TO_24_8(temperature);
return NVL_SUCCESS;
}
// Background task to monitor thermal warn and adjust link mode
void
nvswitch_monitor_thermal_alert_ls10
(
nvswitch_device *device
)
{
return;
}