/*************************************************************************** * Copyright (c) 2002-2008, Broadcom Corporation * All Rights Reserved * Confidential Property of Broadcom Corporation * * THIS SOFTWARE MAY ONLY BE USED SUBJECT TO AN EXECUTED SOFTWARE LICENSE * AGREEMENT BETWEEN THE USER AND BROADCOM. YOU HAVE NO RIGHT TO USE OR * EXPLOIT THIS MATERIAL EXCEPT SUBJECT TO THE TERMS OF SUCH AN AGREEMENT. * * $brcm_Workfile: bhdmlib_hdcp.c $ * $brcm_Revision: Hydra_Software_Devel/35 $ * $brcm_Date: 8/14/08 6:02p $ * * Module Description: * This module contains function calls used to test the HDCP Authentication * of an DVI or HDMI receiver. These calls make use of the transport (BXPT) * and HDMI (BHDM) porting interface modules * * Revision History: * * $brcm_Log: /magnum/syslib/hdmlib/bhdmlib_hdcp.c $ * * Hydra_Software_Devel/35 8/14/08 6:02p vle * PR 45705: Check for existence of BTMR_Handle before starting HDCP * authentication * * Hydra_Software_Devel/34 4/23/08 4:39p rgreen * PR42107: Remove prior HDCP Repeater Simulation code used to test * epeaters unctionality hen epeaters were not widely available * * Hydra_Software_Devel/33 4/23/08 4:31p rgreen * PR42107: Send Encrypted HDCP frames once repeater authentication has * completed successfully * * Hydra_Software_Devel/32 4/2/08 2:31p vle * PR 40101: Time HDCP Keyloader function to accurately calculate * appropriate wait time before reading R0' * * Hydra_Software_Devel/31 2/28/08 11:08a rgreen * PR40101 : On Aegis based chips, adjust VxWorks to full 100ms for DCP * Compliance test * * Hydra_Software_Devel/30 1/30/08 6:58p vle * PR 39077: Clear authentication if there is an error authenticate * attached repeater. * * Hydra_Software_Devel/29 10/10/07 11:02a rgreen * PR35874 ,PR31560: * Read/Write Repeater KSV FIFO only if devices are attached * Increase delay before reading R0' to ensure meeting 100ms HDCP * requirement. * * Hydra_Software_Devel/28 9/17/07 4:09p rgreen * PR34967: Stop Authentication process when MAX_CASCADE_EXCEEDED is set * in repeaters BStatus register * * Hydra_Software_Devel/27 7/11/07 6:15p rgreen * PR31560,PR3296: Restore use of BKNI_Sleep vs BKNI_Delay to minimize * effect of delay. Refactor of HDCP Authenitication process to be * implemented moving delay control to the app * * Hydra_Software_Devel/26 5/23/07 11:31p rgreen * PR31560:Remove excess delay in reading HDCP R0 value from receiver * * Hydra_Software_Devel/25 1/25/07 6:58p vle * PR 25502: Add 100ms delay to allow Rx R0 to be ready at receiver. * * Hydra_Software_Devel/24 8/11/06 1:15p rgreen * PR22187: Fix HDCP Key Loader to use standalone HSM PI * * Hydra_Software_Devel/23 5/2/06 3:11p rgreen * PR20139: Re-Enable compilation for HSM for HDCP * * Hydra_Software_Devel/22 3/10/06 1:13p rgreen * PR19265: Add BCM97400 HDMI Support; No HDCP yet * * Hydra_Software_Devel/21 2/24/06 7:58p rgreen * PR19265: Remove un-needed header file * * Hydra_Software_Devel/20 2/8/06 5:00p rgreen * PR8896: Fix compilation warnings. * * Hydra_Software_Devel/19 10/21/05 5:44p rgreen * PR17750: Fix Ksv FIFO Ready message * * Hydra_Software_Devel/18 10/20/05 5:31p erickson * PR17108: added temp 7401 hacks * * Hydra_Software_Devel/17 6/27/05 6:22p rgreen * PR15217: Add Auth Support for HDCP Repeaters with Device Count 0; * Use bhdm_config.h configuration option. * Add option for Repeater Simulation Test * * Hydra_Software_Devel/16 4/29/05 5:43p rgreen * PR14848: Return failure when Repeater downstream devices do not * authenticate * * Hydra_Software_Devel/15 4/21/05 7:58p rgreen * PR9474: HDCP Support * Increase timeout for waiting for KSV FIFO Ready to 5 seconds * * Hydra_Software_Devel/14 3/8/05 4:21p rgreen * PR9474: HDCP 1.1 Support * Restore inadvertantly removed BHDM_HDCP_GetBCaps function * * Hydra_Software_Devel/13 3/3/05 5:22p rgreen * PR9474: HDCP 1.1 Support * Remove unused debug functions * Remove call to depracated function BHDM_HDCP_SetVersion * * Hydra_Software_Devel/12 12/9/04 2:40p rgreen * PR8896: Correctly report status of BHDM_HDCP_AuthenticateRepeater; Use * function argument uint8_t RepeaterAuthenticated instead of local bool * bRepeaterAuthenticated when checking the status of the Repeater * Authentication. * * Clean up debug messages * * Hydra_Software_Devel/11 10/21/04 6:26p rgreen * PR8896: Remove HDCP Key functions used for debug purposes. * * Hydra_Software_Devel/10 10/18/04 11:59a rgreen * PR9474: Add HDCP 1.1 Support * Add check to determine if Rx supports HDCP 1.1 * Remove debug message * * Hydra_Software_Devel/9 9/24/04 6:24p rgreen * PR9474: Add timeout for reading the HDCP Repeater KSV FIFO * * Hydra_Software_Devel/8 8/18/04 4:40p rgreen * PR 12116: Add HDCP Key Loading Support * Use new BHDM_EncryptedHdcpStructure for HDCP Key loading * * Hydra_Software_Devel/7 5/13/04 4:32p rgreen * PR 10273: HDMI / HDCP Revocation/renewability support requirement * * Hydra_Software_Devel/6 4/5/04 1:17p rgreen * PR8896: HDMI API Development/Test * PR10273: HDCP Revocation/renewability support * Add support to AuthenticateReceiver function for checking Revoked KSVs * * Hydra_Software_Devel/5 3/26/04 7:16p rgreen * PR8896: HDMI API Development/Test * Fix compilation error for BXPT_Ca_SetKeySerializer * * Hydra_Software_Devel/4 2/13/04 7:58p rgreen * PR8896: HDMI API Development/Test * Add code to support Repeater Authentication; * Use BHDM_CONFIG_REPEATER_SIMULATION_TEST to generate Tx verifications values contained in * the HDCP 1.1 Spec * Modify BHDM_HDCP_AuthenticateRepeater call * * Hydra_Software_Devel/3 1/27/04 1:03p rgreen * PR8896: HDMI API Development/Test * Move AuthenticateRepeater function to BHDMlib; needs access to XPT * handle for authentication with HDCP Repeater * * Hydra_Software_Devel/2 1/26/04 11:22a rgreen * PR8896: HDMI API Development/Test * Remove unused variable in AuthenticateReceiver function (compile * warning) * Correct labels in enter/leave macros for Debug function * * Hydra_Software_Devel/1 1/20/04 7:37p rgreen * PR8896: HDMI API Development/Test * Create HDMI HDCP Syslib to utilize XPT Key Serializer * * ***************************************************************************/ #include "bstd.h" #include "bxpt.h" #include "btmr.h" #include "bhdm_config.h" #include "bhdmlib_hdcp.h" #include "bhdmlib_hdcp_keyloader.h" BDBG_MODULE(BHDMLIB_HDCP) ; #define BHDM_CHECK_RC( rc, func ) \ do \ { \ if( (rc = BERR_TRACE(func)) != BERR_SUCCESS ) \ { \ goto done; \ } \ } while(0) typedef struct BHDMlib_HDCP_P_Handle { BHDM_Handle hHDMI ; BHDMLIB_KeyHandle hHANDLE ; BTMR_Handle hTMR; } BHDMlib_HDCP_P_Handle ; /****************************************************************************** BERR_Code BHDMlib_HDCP_Open Summary:Open a HDCP handle for HDCP Authentication between the Transmitter and the Receiver. *******************************************************************************/ BERR_Code BHDMlib_HDCP_Open( BHDMlib_HDCP_Handle *phHDCP, /* [out] pointer to new HDCP lib handle */ BHDM_Handle hHDMI, /* [in] newly opened HDMI handle */ BHDMLIB_KeyHandle hHANDLE ) /* [in] newly opened handle for Keys*/ { BERR_Code rc = BERR_SUCCESS; BHDMlib_HDCP_Handle hHDCP = NULL ; BDBG_ENTER(BHDMlib_HDCP_Open) ; BDBG_ASSERT(hHDMI) ; BDBG_ASSERT(hHANDLE) ; hHDCP = (BHDMlib_HDCP_Handle) BKNI_Malloc(sizeof(BHDMlib_HDCP_P_Handle)) ; if (!hHDCP) { rc = BERR_TRACE(BERR_OUT_OF_SYSTEM_MEMORY); goto done; } hHDCP->hHDMI = hHDMI ; hHDCP_BHDMLIB_KeyHandle = hHANDLE ; hHDCP->hTMR = NULL; /* keep created pointer */ *phHDCP = hHDCP ; done: BDBG_LEAVE(BHDMlib_HDCP_Open); return rc ; } /****************************************************************************** BERR_Code BHDMlib_HDCP_Close Summary:Close the HDCP handled opened for HDCP Authentication between the Transmitter and the Receiver. *******************************************************************************/ BERR_Code BHDMlib_HDCP_Close( BHDMlib_HDCP_Handle hHDCP /* [in] HDCP lib handle */ ) { BERR_Code rc = BERR_SUCCESS; BDBG_ENTER(BHDMlib_HDCP_Close); /* free memory associated with the HDCP handle */ BKNI_Free( (void *) hHDCP) ; BDBG_LEAVE(BHDMlib_HDCP_Close); return rc ; } /****************************************************************************** BERR_Code BHDMlib_HDCP_AuthenticateReceiver Summary:Authenticate the HDCP link between the Transmitter and the Receiver. *******************************************************************************/ BERR_Code BHDMlib_HDCP_AuthenticateReceiver( BHDMlib_HDCP_Handle hHDCP, /* [in] HDCP lib handle */ BHDM_HDCP_AnSelect AnSelection, /* [in] HDCP An type value to use */ const uint8_t *pTxAksv, /* [in] pointer HDCP Key Set Aksv Value */ const BHDM_EncryptedHdcpKeyStruct *pTxKeyStructure, /* [in] pointer to HDCP Keys */ const uint8_t *pRevokedKsvList, /* [in] pointer to Revoked KSV List */ const uint16_t uiNumRevokedKsvs /* [in] number of KSVs in Revoked Ksv List */ ) { BERR_Code rc = BERR_SUCCESS; uint8_t RxAuthenticated = 0 ; #ifdef RESET_OLDER_SI_DVI_RX uint8_t RxHasBeenResetOnce = 0 ; #endif uint8_t BCaps ; uint8_t RxIsHdcpRepeater = 0 ; BTMR_TimerHandle hTimer; BTMR_Settings stTmrSettings; uint32_t uiTimer1 = 0; uint32_t uiTimer2 = 0; BDBG_ENTER(BHDMlib_HDCP_AuthenticateReceiver) ; BDBG_ASSERT( hHDCP ); BDBG_ASSERT( hHDCP->hTMR ); /************************************************/ /* Create timer to monitor wait time before reading R0' */ /************************************************/ rc = BTMR_GetDefaultTimerSettings(&stTmrSettings); if (rc != BERR_SUCCESS) { goto done; } /* Set appropriate Timer Settings */ stTmrSettings.type = BTMR_Type_eSharedFreeRun; stTmrSettings.exclusive = false ; /* Create timer */ rc = BTMR_CreateTimer(hHDCP->hTMR, &hTimer, &stTmrSettings) ; if(rc != BERR_SUCCESS) { rc = BERR_TRACE(BERR_LEAKED_RESOURCE); goto done ; } /* use the Rx BCaps register to check which HDCP Version to use */ BHDM_CHECK_RC(rc, BHDM_HDCP_GetRxCaps(hHDCP->hHDMI, &BCaps)) ; while (!RxAuthenticated) { /* Read the Bksv from the Rx */ if ((rc = BHDM_HDCP_ReadRxBksv(hHDCP->hHDMI, pRevokedKsvList, uiNumRevokedKsvs)) != BERR_SUCCESS) goto ResetRx ; /* Generate/Write the Authentication An value */ BHDM_CHECK_RC(rc, BHDM_HDCP_GenerateAn(hHDCP->hHDMI, AnSelection)) ; /* Write the Tx Aksv to the Receiver */ if ((rc = BHDM_HDCP_WriteTxAksvToRx(hHDCP->hHDMI, pTxAksv)) != BERR_SUCCESS) goto ResetRx ; /* Record timer before loading HDCP keys */ if ((rc = BTMR_ReadTimer(hTimer, &uiTimer1)) != BERR_SUCCESS) { BDBG_ERR(("Error reading shared timer")); goto done; } /* Rx R0 is ready 100ms after writing Aksv */ /* while waiting for R0..., load the transmitter HDCP Keys */ if ((rc = BHDM_HDCP_EnableSerialKeyLoad(hHDCP->hHDMI)) != BERR_SUCCESS) goto ResetRx ; if ((rc = BHDMLIB_HDCP_LoadEncryptedHdcpKeys(hHDCP_BHDMLIB_KeyHandle, pTxKeyStructure)) != BERR_SUCCESS) goto ResetRx ; /* Read timer after finish loading HDCP keys and calculate elapsed time for loading HDCP keys*/ if ((rc = BTMR_ReadTimer(hTimer, &uiTimer2)) != BERR_SUCCESS) { BDBG_ERR(("Error reading shared timer")); goto done; } uiTimer1 = (uiTimer2 - uiTimer1)/1000; /* Make sure to wait a total of 100ms or more before reading R0' after writing Aksv */ /* Wait time = 115 ms - the time it took to load the HDCP keys */ BKNI_Sleep(115 - uiTimer1); /* Authenticate the Link */ if ((rc = BHDM_HDCP_AuthenticateLink(hHDCP->hHDMI)) == BERR_SUCCESS) { RxAuthenticated = 1 ; /* check if Rx is a Repeater */ RxIsHdcpRepeater = BCaps & BHDM_HDCP_RxCaps_eHdcpRepeater ; if (RxIsHdcpRepeater) { /* Send encrypted frames to the repeater after it has been authenticated. i.e. before starting HDCP Repeater Authentication (Part 2) */ BHDM_HDCP_XmitEncrypted(hHDCP->hHDMI) ; rc = BHDMlib_HDCP_AuthenticateRepeater(hHDCP->hHDMI, &RxAuthenticated, pRevokedKsvList, uiNumRevokedKsvs) ; } if (RxAuthenticated) goto done ; } ResetRx: BDBG_MSG(("Unable to Authenticate Receiver")) ; #ifndef RESET_OLDER_SI_DVI_RX break ; /* DO NOT TRY RESETTING Rx Receiver */ #else /* Debug/Test code to support earlier Silicon Image DVI Rx */ /* ** RESET RX ** ** try resetting the Rx... this will occur only if there was a problem ** with enabling the HDCP link. Try resetting the Rx only once. */ if (RxHasBeenResetOnce) break ; BDBG_WRN(("Attempting Reset of Receiver...\n")); /* ** This reset step is REQUIRED for resetting OLDER Silicon Image (SI) ** Receivers. If the Si Rx is not properly reset the HDCP ** Authentication will fail. the SI Receivers need the TMDS buffer and ** clock turned off for 100ms and subsequently turned back on to reset. ** ** NOTE: the TMDS buffer on/off will cause all displays to blank ** for a fraction of a second. The reset will most likely be needed on ** displays containing OLDER SI Receivers. */ BHDM_ResetHdmiRx(hHDCP->hHDMI) ; RxHasBeenResetOnce = 1 ; #endif } /* while !RxAuthenticated) */ done: BDBG_LEAVE(BHDMlib_HDCP_AuthenticateReceiver) ; /* Destroy Timer */ BTMR_DestroyTimer(hTimer); return rc ; } /* end BHDMlib_HDCP_AuthenticateReceiver */ /****************************************************************************** BERR_Code BHDMlib_HDCP_AuthenticateRepeater Summary:Authenticate the HDCP link between the Transmitter and an HDCP Repeater. *******************************************************************************/ BERR_Code BHDMlib_HDCP_AuthenticateRepeater( BHDM_Handle hHDMI, /* [in] HDCP lib handle */ uint8_t *RepeaterAuthenticated, const uint8_t *pRevokedKsvList, /* [in] pointer to Revoked KSV List */ const uint16_t uiNumRevokedKsvs /* [in] number of KSVs in Revoked Ksv List */ ) { BERR_Code rc = BERR_SUCCESS; bool KsvFifoReady ; uint8_t timeoutMs ; uint8_t KsvListMemoryAllocated = 0 ; uint8_t BCaps, *KsvList = NULL, DeviceCount, RepeaterLevels ; uint16_t BStatus, iNumKsvBytes ; BDBG_ENTER(BHDMlib_HDCP_AuthenticateRepeater) ; BDBG_ASSERT( hHDMI ); *RepeaterAuthenticated = 0 ; timeoutMs = 50 ; do { BHDM_CHECK_RC(rc, BHDM_HDCP_GetRxCaps(hHDMI, &BCaps)) ; if ((KsvFifoReady = BCaps & BHDM_HDCP_RxCaps_eKsvFifoReady)) break ; BDBG_WRN(("Wait for KSV FIFO Rdy; timeout in %d ms", timeoutMs * 100)) ; BKNI_Sleep(100) ; } while (timeoutMs--) ; if (!KsvFifoReady) { BDBG_ERR(("HDCP Auth Failure; Repeater KSV FIFO not ready")) ; rc = BHDM_HDCP_REPEATER_FIFO_NOT_READY ; goto done ; } /* check Repeater Values */ BHDM_CHECK_RC(rc, BHDM_HDCP_GetRxStatus(hHDMI, &BStatus)) ; BHDM_CHECK_RC(rc, BHDM_HDCP_GetRepeaterDepth(hHDMI, &RepeaterLevels)) ; BHDM_CHECK_RC(rc, BHDM_HDCP_GetRepeaterDeviceCount(hHDMI, &DeviceCount)) ; BDBG_MSG(("RXStatus: %X, Depth: %d, Devices: %d", BStatus, RepeaterLevels, DeviceCount)) ; /* check if the number of repeater levels has been exceeded */ if (BStatus & BHDM_HDCP_RxStatus_eMaxRepeatersExceeded) { BDBG_ERR(("%d Levels of Repeaters exceed the MAX allowed of %d", RepeaterLevels, BHDM_HDCP_REPEATER_MAX_DEPTH )) ; rc = BHDM_HDCP_REPEATER_DEPTH_EXCEEDED ; goto done ; } /* check if the number of receiver devices has been exceeded */ if (BStatus & BHDM_HDCP_RxStatus_eMaxDevicesExceeded) { BDBG_ERR(("Number of Devices: %d exceeds the MAX allowed of %d", DeviceCount, BHDM_HDCP_REPEATER_MAX_DEVICE_COUNT )) ; rc = BHDM_HDCP_RX_DEVICES_EXCEEDED ; goto done ; } /* initialize the Repeater Authentication */ BHDM_HDCP_InitializeRepeaterAuthentication(hHDMI) ; if (DeviceCount) { /* allocate a buffer to hold the Ksv List */ iNumKsvBytes = (uint16_t) (DeviceCount * BHDM_HDCP_KSV_LENGTH) ; KsvList = (uint8_t *) BKNI_Malloc(sizeof(uint8_t) * iNumKsvBytes) ; KsvListMemoryAllocated = 1 ; /* read the Ksv List */ /* pass the revoked list for checking against downstream Rx devices */ BHDM_CHECK_RC(rc, BHDM_HDCP_ReadRxRepeaterKsvFIFO(hHDMI, KsvList, DeviceCount, pRevokedKsvList, uiNumRevokedKsvs)) ; /* write the Ksvs from the Rx (Repeater) to the Transmitter core for verification */ BHDM_CHECK_RC(rc, BHDM_HDCP_WriteTxKsvFIFO(hHDMI, KsvList, DeviceCount)) ; } else /* handle zero devices attached to repeater */ { #if BHDM_CONFIG_DISABLE_HDCP_AUTH_REPEATER_DEVCOUNT0 /* do not allow authentication with repeaters that have device count of 0 */ BDBG_WRN(("Auth Disabled for Repeaters with Device Count of 0")) ; return BHDM_HDCP_REPEATER_DEVCOUNT_0 ; #else /* force V calculation for repeater with zero attached devices */ BHDM_HDCP_ForceVCalculation(hHDMI) ; #endif } /* check SHA-1 Hash Verification (V).... */ BHDM_CHECK_RC(rc, BHDM_HDCP_RepeaterAuthenticateLink(hHDMI, RepeaterAuthenticated)) ; if (!*RepeaterAuthenticated) { BDBG_ERR(("Repeater failed to authenticate")) ; rc = BHDM_HDCP_REPEATER_AUTH_ERROR ; goto done ; } done: /* release allocated memory for Ksv list */ if (KsvListMemoryAllocated) BKNI_Free(KsvList) ; if (rc != BERR_SUCCESS) BHDM_HDCP_ClearAuthentication(hHDMI); BDBG_LEAVE(BHDMlib_HDCP_AuthenticateRepeater) ; return rc ; } /* end BHDMlib_HDCP_AuthenticateRepeater */ BERR_Code BHDMlib_HDCP_SetTimerHandle( BHDMlib_HDCP_Handle hHDCP, /* [out] pointer to new HDCP lib handle */ BTMR_Handle hTMR) /* [in] TMR handle */ { BERR_Code rc = BERR_SUCCESS; BDBG_ENTER(BHDMlib_HDCP_SetTimerHandle) ; BDBG_ASSERT(hTMR) ; /* Save TMR handle into HDMlib handle */ hHDCP->hTMR = hTMR ; BDBG_LEAVE(BHDMlib_HDCP_SetTimerHandle); return rc ; }