/** @file I2C Debug Port Protocol Implementation Copyright (c) 2022, Intel Corporation. All rights reserved.
SPDX-License-Identifier: BSD-2-Clause-Patent **/ #include #include #include #include #include #include #include #include /** Writes data to the I2C debug port @param[in] Buffer - The data to be written to the I2C debug port. @param[in] Count - The number of bytes to write to the I2C debug port. @retval EFI_SUCCESS - The data was successfully written. @retval EFI_INVALID_PARAMETER - One of the following conditions: * ByteCount is 0 * Buffer is NULL @retval EFI_TIMEOUT - The I2C controller did not respond within the required timeout period. @retval EFI_DEVICE_ERROR - An error occurred while accessing the I2C controller. **/ EFI_STATUS I2cDebugPortWrite ( IN UINT8 *Buffer, IN UINT32 Count ) { UINT8 WriteBuffer[I2C_DEBUG_PORT_MAX_DATA_SIZE + 1]; EFI_STATUS Status; UINT32 Index; UINT32 ImplementationDelayUs; UINT8 CurrentSize; UINT8 DdcBusPinPair; if (Count <= 0) { return EFI_INVALID_PARAMETER; } if (Buffer == NULL) { return EFI_INVALID_PARAMETER; } Status = GetGmbusBusPinPairForI2cDebugPort (&DdcBusPinPair); if (EFI_ERROR (Status)) { return Status; } ImplementationDelayUs = FixedPcdGet32 (PcdI2cHdmiDebugPortPacketStallUs); //BP: 3ms stall to catch up RaiseTplForI2cDebugPortAccess (); for (Index = 0; Index < Count; Index += I2C_DEBUG_PORT_MAX_DATA_SIZE) { MicroSecondDelay (ImplementationDelayUs); if ((Index + I2C_DEBUG_PORT_MAX_DATA_SIZE) >= Count) { CurrentSize = (UINT8) (Count - Index); } else { CurrentSize = I2C_DEBUG_PORT_MAX_DATA_SIZE; } WriteBuffer[0] = (I2C_DEBUG_PORT_WRITE_COMMAND << I2C_DEBUG_PORT_COMMAND_BIT_POSITION) | (CurrentSize & I2C_DEBUG_PORT_DATA_SIZE_BIT_MASK); CopyMem (&(WriteBuffer[1]), &(Buffer[Index]), CurrentSize); Status = GmbusWrite (DdcBusPinPair, I2C_DEBUG_PORT_WRITE_DEVICE_ADDRESS, TRUE, CurrentSize + 1, &(WriteBuffer[0])); if (EFI_ERROR (Status)) { break; } } RestoreTplAfterI2cDebugPortAccess (); return Status; } /** Reads data from the I2C debug port @param[out] Buffer - The memory buffer to return the read data. @param[in, out] Count - The number of bytes to read from the I2C debug port. On output, the number of bytes actually read. @retval EFI_SUCCESS - The data was successfully read. @retval EFI_INVALID_PARAMETER - One of the following conditions: * ByteCount is 0 * Buffer is NULL @retval EFI_TIMEOUT - The I2C controller did not respond within the required timeout period. @retval EFI_DEVICE_ERROR - An error occurred while accessing the I2C controller. **/ EFI_STATUS I2cDebugPortRead ( OUT UINT8 *Buffer, IN OUT UINT32 *Count ) { EFI_STATUS Status; UINT32 Index; UINT32 BytesRead; UINT32 ImplementationDelayUs; UINT32 CurrentSize; UINT8 DdcBusPinPair; UINT8 GmbusIndexData; BytesRead = 0; if ((*Count) <= 0) { return EFI_INVALID_PARAMETER; } if (Buffer == NULL) { return EFI_INVALID_PARAMETER; } Status = GetGmbusBusPinPairForI2cDebugPort (&DdcBusPinPair); if (EFI_ERROR (Status)) { return Status; } ImplementationDelayUs = FixedPcdGet32 (PcdI2cHdmiDebugPortPacketStallUs); //BP: 3ms stall to catch up RaiseTplForI2cDebugPortAccess (); for (Index = 0; Index < (*Count); Index += I2C_DEBUG_PORT_MAX_DATA_SIZE) { MicroSecondDelay (ImplementationDelayUs); if ((Index + I2C_DEBUG_PORT_MAX_DATA_SIZE) >= (*Count)) { CurrentSize = (*Count) - Index; } else { CurrentSize = I2C_DEBUG_PORT_MAX_DATA_SIZE; } GmbusIndexData = (I2C_DEBUG_PORT_READ_COMMAND << I2C_DEBUG_PORT_COMMAND_BIT_POSITION) | (CurrentSize & I2C_DEBUG_PORT_DATA_SIZE_BIT_MASK); Status = GmbusRead ( DdcBusPinPair, I2C_DEBUG_PORT_READ_DEVICE_ADDRESS, TRUE, TRUE, GmbusIndexData, &CurrentSize, &(Buffer[Index]) ); if (EFI_ERROR (Status)) { break; } BytesRead += CurrentSize; if (((Index + I2C_DEBUG_PORT_MAX_DATA_SIZE) < (*Count)) && (CurrentSize < I2C_DEBUG_PORT_MAX_DATA_SIZE)) { break; } } RestoreTplAfterI2cDebugPortAccess (); (*Count) = BytesRead; return Status; } /** Queries the I2C debug port to see if there are any data waiting to be read @param[out] NumberOfBytesInFifoBuffer - The number of bytes sitting in the I2C debug port's FIFO buffer waiting to be read @retval EFI_SUCCESS - The I2C debug port was successfully queried @retval EFI_INVALID_PARAMETER - One of the following conditions: * NumberOfBytesInFifoBuffer is NULL @retval EFI_TIMEOUT - The I2C controller did not respond within the required timeout period. @retval EFI_DEVICE_ERROR - An error occurred while accessing the I2C controller. **/ EFI_STATUS I2cDebugPortReadyToRead ( OUT UINT8 *NumberOfBytesInFifoBuffer ) { EFI_STATUS Status; UINT32 BytesRead; UINT8 DdcBusPinPair; UINT32 ImplementationDelayUs; UINT8 GmbusIndexData; BytesRead = 1; if (NumberOfBytesInFifoBuffer == NULL) { return EFI_INVALID_PARAMETER; } Status = GetGmbusBusPinPairForI2cDebugPort (&DdcBusPinPair); if (EFI_ERROR (Status)) { return Status; } ImplementationDelayUs = FixedPcdGet32 (PcdI2cHdmiDebugPortPacketStallUs); //BP: 3ms stall to catch up MicroSecondDelay (ImplementationDelayUs); GmbusIndexData = (I2C_DEBUG_PORT_READY_TO_READ_COMMAND << I2C_DEBUG_PORT_COMMAND_BIT_POSITION) | (1 & I2C_DEBUG_PORT_DATA_SIZE_BIT_MASK); //READY_TO_READ always returns 1 byte RaiseTplForI2cDebugPortAccess (); Status = GmbusRead (DdcBusPinPair, I2C_DEBUG_PORT_READ_DEVICE_ADDRESS, TRUE, TRUE, GmbusIndexData, &BytesRead, NumberOfBytesInFifoBuffer); if (EFI_ERROR (Status)) { return Status; } RestoreTplAfterI2cDebugPortAccess (); if (BytesRead != 1) { Status = EFI_DEVICE_ERROR; } return Status; }