/*----------------------------------------------------------------------------- * Function: hdcp_suspend_resume_auto_ri *----------------------------------------------------------------------------- */ static int hdcp_suspend_resume_auto_ri(enum ri_suspend_resume state) { static u8 OldRiStat, OldRiCommand; u8 TimeOut = 10; /* Suspend Auto Ri in order to allow FW access MDDC bus. * Poll 0x72:0x26[0] for MDDC bus availability or timeout */ DBG("hdcp_suspend_resume_auto_ri() state=%s", state == AUTO_RI_SUSPEND ? "SUSPEND" : "RESUME"); if (state == AUTO_RI_SUSPEND) { /* Save original Auto Ri state */ OldRiCommand = RD_FIELD_32(hdcp.hdmi_wp_base_addr + HDMI_IP_CORE_SYSTEM, HDMI_IP_CORE_SYSTEM__RI_CMD, 0, 0); /* Disable Auto Ri */ hdcp_lib_auto_ri_check(false); /* Wait for HW to release MDDC bus */ /* TODO: while loop / timeout to be enhanced */ while (--TimeOut) { if (!RD_FIELD_32(hdcp.hdmi_wp_base_addr + HDMI_IP_CORE_SYSTEM, HDMI_IP_CORE_SYSTEM__RI_STAT, 0, 0)) break; } /* MDDC bus not relinquished */ if (!TimeOut) { printk(KERN_ERR "HDCP: Suspending Auto Ri failed !\n"); return -HDCP_DDC_ERROR; } OldRiStat = RD_FIELD_32(hdcp.hdmi_wp_base_addr + HDMI_IP_CORE_SYSTEM, HDMI_IP_CORE_SYSTEM__RI_STAT, 0, 0); } else { /* If Auto Ri was enabled before it was suspended */ if ((OldRiStat) && (OldRiCommand)) /* Re-enable Auto Ri */ hdcp_lib_auto_ri_check(false); } return HDCP_OK; }
/*----------------------------------------------------------------------------- * Function: hdcp_irq_cb *----------------------------------------------------------------------------- */ static void hdcp_irq_cb(int status) { DBG("hdcp_irq_cb() status=%x", status); if (!hdcp.hdcp_keys_loaded) { DBG("%s: hdcp_keys not loaded = %d", __func__, hdcp.hdcp_keys_loaded); return; } /* Disable auto Ri/BCAPS immediately */ if (((status & HDMI_RI_ERR) || (status & HDMI_BCAP) || (status & HDMI_HPD_LOW)) && (hdcp.hdcp_state != HDCP_ENABLE_PENDING)) { hdcp_lib_auto_ri_check(false); hdcp_lib_auto_bcaps_rdy_check(false); } /* Work queue execution not required if HDCP is disabled */ /* TODO: ignore interrupts if they are masked (cannnot access UMASK * here so should use global variable */ if ((hdcp.hdcp_state != HDCP_DISABLED) && (hdcp.hdcp_state != HDCP_ENABLE_PENDING)) { if (status & HDMI_HPD_LOW) { hdcp_lib_set_encryption(HDCP_ENC_OFF); hdcp_ddc_abort(); } if (status & HDMI_RI_ERR) { hdcp_lib_set_av_mute(AV_MUTE_SET); hdcp_lib_set_encryption(HDCP_ENC_OFF); hdcp_submit_work(HDCP_RI_FAIL_EVENT, 0); } /* RI error takes precedence over BCAP */ else if (status & HDMI_BCAP) hdcp_submit_work(HDCP_KSV_LIST_RDY_EVENT, 0); } if (status & HDMI_HPD_LOW) { hdcp.pending_disable = 1; /* Used to exit on-going HDCP * work */ hdcp.hpd_low = 0; /* Used to cancel HDCP works */ hdcp_lib_disable(); /* In case of HDCP_STOP_FRAME_EVENT, HDCP stop * frame callback is blocked and waiting for * HDCP driver to finish accessing the HW * before returning * Reason is to avoid HDMI driver to shutdown * DSS/HDMI power before HDCP work is finished */ hdcp.hdmi_state = HDMI_STOPPED; hdcp.hdcp_state = HDCP_ENABLE_PENDING; hdcp.auth_state = HDCP_STATE_DISABLED; } }
/*----------------------------------------------------------------------------- * Function: hdcp_wq_authentication_failure *----------------------------------------------------------------------------- */ static void hdcp_wq_authentication_failure(void) { if (hdcp.hdmi_state == HDMI_STOPPED) { hdcp.auth_state = HDCP_STATE_AUTH_FAILURE; return; } hdcp_lib_auto_ri_check(false); hdcp_lib_auto_bcaps_rdy_check(false); hdcp_lib_set_av_mute(AV_MUTE_SET); hdcp_lib_set_encryption(HDCP_ENC_OFF); hdcp_cancel_work(&hdcp.pending_wq_event); hdcp_lib_disable(); hdcp.pending_disable = 0; if (hdcp.retry_cnt && (hdcp.hdmi_state != HDMI_STOPPED)) { if (hdcp.retry_cnt < HDCP_INFINITE_REAUTH) { hdcp.retry_cnt--; printk(KERN_INFO "HDCP: authentication failed - " "retrying, attempts=%d\n", hdcp.retry_cnt); } else printk(KERN_INFO "HDCP: authentication failed - " "retrying\n"); hdcp.hdcp_state = HDCP_AUTHENTICATION_START; hdcp.auth_state = HDCP_STATE_AUTH_FAIL_RESTARTING; hdcp.pending_wq_event = hdcp_submit_work(HDCP_AUTH_REATT_EVENT, HDCP_REAUTH_DELAY); } else { printk(KERN_INFO "HDCP: authentication failed - " "HDCP disabled\n"); hdcp.hdcp_state = HDCP_ENABLE_PENDING; hdcp.auth_state = HDCP_STATE_AUTH_FAILURE; } }
/*----------------------------------------------------------------------------- * Function: hdcp_lib_step2 *----------------------------------------------------------------------------- */ int hdcp_lib_step2(void) { /* HDCP authentication steps: * 1) Disable auto Ri check * 2) DDC: read BStatus (nb of devices, MAX_DEV */ u8 bstatus[2]; int status = HDCP_OK; DBG("hdcp_lib_step2() %u", jiffies_to_msecs(jiffies)); #ifdef _9032_AUTO_RI_ /* Disable Auto Ri */ hdcp_lib_auto_ri_check(false); #endif /* DDC: Read Bstatus (1st byte) from Rx */ if (hdcp_ddc_read(DDC_BSTATUS_LEN, DDC_BSTATUS_ADDR, bstatus)) return -HDCP_DDC_ERROR; /* Get KSV list size */ DBG("KSV list size: %d", bstatus[0] & DDC_BSTATUS0_DEV_COUNT); sha_input.byte_counter = (bstatus[0] & DDC_BSTATUS0_DEV_COUNT) * 5; /* Check BStatus topology errors */ if (bstatus[0] & DDC_BSTATUS0_MAX_DEVS) { DBG("MAX_DEV_EXCEEDED set"); return -HDCP_AUTH_FAILURE; } if (bstatus[1] & DDC_BSTATUS1_MAX_CASC) { DBG("MAX_CASCADE_EXCEEDED set"); return -HDCP_AUTH_FAILURE; } DBG("Retrieving KSV list..."); /* Clear all SHA input data */ /* TODO: should be done earlier at HDCP init */ memset(sha_input.data, 0, MAX_SHA_DATA_SIZE); if (hdcp.pending_disable) return -HDCP_CANCELLED_AUTH; /* DDC: read KSV list */ if (sha_input.byte_counter) { if (hdcp_ddc_read(sha_input.byte_counter, DDC_KSV_FIFO_ADDR, (u8 *)&sha_input.data)) return -HDCP_DDC_ERROR; } /* Read and add Bstatus */ if (hdcp_lib_sha_bstatus(&sha_input)) return -HDCP_DDC_ERROR; if (hdcp.pending_disable) return -HDCP_CANCELLED_AUTH; /* Read V' */ if (hdcp_ddc_read(DDC_V_LEN, DDC_V_ADDR, sha_input.vprime)) return -HDCP_DDC_ERROR; if (hdcp.pending_disable) return -HDCP_CANCELLED_AUTH; /* clear sha_input values in cache*/ dma_sync_single_for_device(NULL, __pa((u32)(&sha_input)), sizeof(struct hdcp_sha_in), DMA_TO_DEVICE); status = omap4_secure_dispatcher(PPA_SERVICE_HDCP_CHECK_V, FLAG_START_CRITICAL, 1, __pa((u32)&sha_input), 0, 0, 0); /* Wait for user space */ if (status) { printk(KERN_ERR "HDCP: omap4_secure_dispatcher CHECH_V error " "%d\n", status); return -HDCP_AUTH_FAILURE; } if (status == HDCP_OK) { /* Re-enable Ri check */ #ifdef _9032_AUTO_RI_ hdcp_lib_auto_ri_check(true); #endif } return status; }
/*----------------------------------------------------------------------------- * Function: hdcp_lib_step1_r0_check *----------------------------------------------------------------------------- */ int hdcp_lib_step1_r0_check(void) { int status = HDCP_OK; /* HDCP authentication steps: * 1) DDC: Read M0' * 2) Compare M0 and M0' * if Rx is a receiver: switch to authentication step 3 * 3) Enable encryption / auto Ri check / disable AV mute * if Rx is a repeater: switch to authentication step 2 * 3) Get M0 from HDMI IP and store it for further processing (V) * 4) Enable encryption / auto Ri check / auto BCAPS RDY polling * Disable AV mute */ DBG("hdcp_lib_step1_r0_check() %u", jiffies_to_msecs(jiffies)); status = hdcp_lib_r0_check(); if (status < 0) return status; /* Authentication 1st step done */ /* Now prepare 2nd step authentication in case of RX repeater and * enable encryption / Ri check */ if (hdcp.pending_disable) return -HDCP_CANCELLED_AUTH; if (hdcp_lib_check_repeater_bit_in_tx()) { status = omap4_secure_dispatcher(PPA_SERVICE_HDCP_READ_M0, FLAG_START_CRITICAL, 0, 0, 0, 0, 0); /* Wait for user space */ if (status) { printk(KERN_ERR "HDCP: omap4_secure_dispatcher M0 error " "%d\n", status); return -HDCP_AUTH_FAILURE; } DBG("hdcp_lib_set_encryption() %u", jiffies_to_msecs(jiffies)); /* Enable encryption */ hdcp_lib_set_encryption(HDCP_ENC_ON); #ifdef _9032_AUTO_RI_ /* Enable Auto Ri */ hdcp_lib_auto_ri_check(true); #endif #ifdef _9032_BCAP_ /* Enable automatic BCAPS polling */ hdcp_lib_auto_bcaps_rdy_check(true); #endif /* Now, IP waiting for BCAPS ready bit */ } else { /* Receiver: enable encryption and auto Ri check */ hdcp_lib_set_encryption(HDCP_ENC_ON); #ifdef _9032_AUTO_RI_ /* Enable Auto Ri */ hdcp_lib_auto_ri_check(true); #endif } /* Clear AV mute */ hdcp_lib_set_av_mute(AV_MUTE_CLEAR); return HDCP_OK; }