/* * 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 (pParams->port == NVSWITCH_I2C_PORT_I2CA) { pParams->flags = FLD_SET_DRF(SWITCH_CTRL, _I2C_FLAGS, _SPEED_MODE, _100KHZ, pParams->flags); } 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; }