Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 3d4be6a2 authored by Linux Build Service Account's avatar Linux Build Service Account Committed by Gerrit - the friendly Code Review server
Browse files

Merge "msm: mdss: hdmi: hdcp: load keys separately before authentication"

parents b6a4104f 3d4d5668
Loading
Loading
Loading
Loading
+114 −135
Original line number Original line Diff line number Diff line
@@ -245,120 +245,148 @@ static int hdcp_scm_call(struct scm_hdcp_req *req, u32 *resp)
	return ret;
	return ret;
}
}


static int hdmi_hdcp_authentication_part1(struct hdmi_hdcp_ctrl *hdcp_ctrl)
static int hdmi_hdcp_load_keys(void *input)
{
{
	int rc;
	int rc = 0;
	bool use_sw_keys = false;
	u32 reg_val;
	u32 reg_val;
	u32 qfprom_aksv_lsb, qfprom_aksv_msb;
	u32 link0_aksv_0, link0_aksv_1;
	u32 link0_bksv_0, link0_bksv_1;
	u32 link0_an_0, link0_an_1;
	u32 timeout_count;
	bool is_match, use_sw_keys = false;
	bool stale_an = false;
	struct dss_io_data *io;
	struct dss_io_data *hdcp_io;
	u8 aksv[5], *bksv = NULL;
	u8 an[8];
	u8 bcaps;
	struct hdmi_tx_ddc_data ddc_data;
	u32 link0_status, an_ready, keys_state;
	u8 buf[0xFF];
	u32 ksv_lsb_addr, ksv_msb_addr;
	u32 ksv_lsb_addr, ksv_msb_addr;

	u32 aksv_lsb, aksv_msb;
	struct scm_hdcp_req scm_buf[SCM_HDCP_MAX_REG];
	u8 aksv[5];
	u32 phy_addr;
	struct dss_io_data *io;
	u32 ret  = 0;
	struct dss_io_data *qfprom_io;
	u32 resp = 0;
	struct hdmi_hdcp_ctrl *hdcp_ctrl = input;


	if (!hdcp_ctrl || !hdcp_ctrl->init_data.core_io ||
	if (!hdcp_ctrl || !hdcp_ctrl->init_data.core_io ||
		!hdcp_ctrl->init_data.qfprom_io) {
		!hdcp_ctrl->init_data.qfprom_io) {
		DEV_ERR("%s: invalid input\n", __func__);
		DEV_ERR("%s: invalid input\n", __func__);
		rc = -EINVAL;
		rc = -EINVAL;
		goto error;
		goto end;
	}
	}


	phy_addr = hdcp_ctrl->init_data.phy_addr;
	if ((HDCP_STATE_INACTIVE != hdcp_ctrl->hdcp_state) &&
	bksv = hdcp_ctrl->current_tp.bksv;
		(HDCP_STATE_AUTH_FAIL != hdcp_ctrl->hdcp_state)) {
	io = hdcp_ctrl->init_data.core_io;
	hdcp_io = hdcp_ctrl->init_data.hdcp_io;

	if (HDCP_STATE_AUTHENTICATING != hdcp_ctrl->hdcp_state) {
		DEV_ERR("%s: %s: invalid state. returning\n", __func__,
		DEV_ERR("%s: %s: invalid state. returning\n", __func__,
			HDCP_STATE_NAME);
			HDCP_STATE_NAME);
		rc = -EINVAL;
		rc = -EINVAL;
		goto error;
		goto end;
	}
	}


	/* On compatible hardware, use SW aksv */
	io = hdcp_ctrl->init_data.core_io;
	reg_val = DSS_REG_R(hdcp_ctrl->init_data.qfprom_io,
	qfprom_io = hdcp_ctrl->init_data.qfprom_io;
			SEC_CTRL_HW_VERSION);

	/* On compatible hardware, use SW keys */
	reg_val = DSS_REG_R(qfprom_io, SEC_CTRL_HW_VERSION);
	if (reg_val >= HDCP_SEL_MIN_SEC_VERSION) {
	if (reg_val >= HDCP_SEL_MIN_SEC_VERSION) {
		reg_val = DSS_REG_R(hdcp_ctrl->init_data.qfprom_io,
		reg_val = DSS_REG_R(qfprom_io,
			QFPROM_RAW_FEAT_CONFIG_ROW0_MSB +
			QFPROM_RAW_FEAT_CONFIG_ROW0_MSB +
			QFPROM_RAW_VERSION_4);
			QFPROM_RAW_VERSION_4);

		if (!(reg_val & BIT(23)))
		if (!(reg_val & BIT(23)))
			use_sw_keys = true;
			use_sw_keys = true;
	}
	}


	if (use_sw_keys) {
	if (use_sw_keys) {
		if (hdcp1_set_keys(&qfprom_aksv_msb, &qfprom_aksv_lsb)) {
		if (hdcp1_set_keys(&aksv_msb, &aksv_lsb)) {
			pr_err("%s: setting of hdcp SW keys failed\n",
			pr_err("%s: setting hdcp SW keys failed\n", __func__);
						__func__);
			rc = -EINVAL;
			rc = -EINVAL;
			goto error;
			goto end;
		}
		}
	} else {
	} else {
		/* Fetch aksv from QFPROM, this info should be public. */
		/* Fetch aksv from QFPROM, this info should be public. */
		ksv_lsb_addr = HDCP_KSV_LSB;
		ksv_lsb_addr = HDCP_KSV_LSB;
		ksv_msb_addr = HDCP_KSV_MSB;
		ksv_msb_addr = HDCP_KSV_MSB;

		if (hdcp_ctrl->hdmi_tx_ver_4) {
		if (hdcp_ctrl->hdmi_tx_ver_4) {
			ksv_lsb_addr += HDCP_KSV_VERSION_4_OFFSET;
			ksv_lsb_addr += HDCP_KSV_VERSION_4_OFFSET;
			ksv_msb_addr += HDCP_KSV_VERSION_4_OFFSET;
			ksv_msb_addr += HDCP_KSV_VERSION_4_OFFSET;
		}
		}
		qfprom_aksv_lsb = DSS_REG_R(hdcp_ctrl->init_data.qfprom_io,

			ksv_lsb_addr);
		aksv_lsb = DSS_REG_R(qfprom_io, ksv_lsb_addr);
		qfprom_aksv_msb = DSS_REG_R(hdcp_ctrl->init_data.qfprom_io,
		aksv_msb = DSS_REG_R(qfprom_io, ksv_msb_addr);
			ksv_msb_addr);
	}
	}


	aksv[0] =  qfprom_aksv_lsb        & 0xFF;
	DEV_DBG("%s: %s: AKSV=%02x%08x\n", __func__, HDCP_STATE_NAME,
	aksv[1] = (qfprom_aksv_lsb >> 8)  & 0xFF;
		aksv_msb, aksv_lsb);
	aksv[2] = (qfprom_aksv_lsb >> 16) & 0xFF;

	aksv[3] = (qfprom_aksv_lsb >> 24) & 0xFF;
	aksv[0] =  aksv_lsb        & 0xFF;
	aksv[4] =  qfprom_aksv_msb        & 0xFF;
	aksv[1] = (aksv_lsb >> 8)  & 0xFF;
	aksv[2] = (aksv_lsb >> 16) & 0xFF;
	aksv[3] = (aksv_lsb >> 24) & 0xFF;
	aksv[4] =  aksv_msb        & 0xFF;


	/* check there are 20 ones in AKSV */
	/* check there are 20 ones in AKSV */
	if (hdmi_hdcp_count_one(aksv, 5) != 20) {
	if (hdmi_hdcp_count_one(aksv, 5) != 20) {
		DEV_ERR("%s: %s: AKSV QFPROM doesn't have 20 1's, 20 0's\n",
		DEV_ERR("%s: AKSV bit count failed\n", __func__);
			__func__, HDCP_STATE_NAME);
		rc = -EINVAL;
		DEV_ERR("%s: %s: QFPROM AKSV chk failed (AKSV=%02x%08x)\n",
		goto end;
			__func__, HDCP_STATE_NAME, qfprom_aksv_msb,
	}
			qfprom_aksv_lsb);

	DSS_REG_W(io, HDMI_HDCP_SW_LOWER_AKSV, aksv_lsb);
	DSS_REG_W(io, HDMI_HDCP_SW_UPPER_AKSV, aksv_msb);

	/* Setup seed values for random number An */
	DSS_REG_W(io, HDMI_HDCP_ENTROPY_CTRL0, 0xB1FFB0FF);
	DSS_REG_W(io, HDMI_HDCP_ENTROPY_CTRL1, 0xF00DFACE);

	/* Disable the RngCipher state */
	DSS_REG_W(io, HDMI_HDCP_DEBUG_CTRL,
		DSS_REG_R(io, HDMI_HDCP_DEBUG_CTRL) & ~(BIT(2)));

	/* make sure hw is programmed */
	wmb();

	DSS_REG_W(io, HDMI_HDCP_CTRL, BIT(0));

	hdcp_ctrl->hdcp_state = HDCP_STATE_AUTHENTICATING;
end:
	return rc;
}

static int hdmi_hdcp_authentication_part1(struct hdmi_hdcp_ctrl *hdcp_ctrl)
{
	int rc;
	u32 link0_aksv_0, link0_aksv_1;
	u32 link0_bksv_0, link0_bksv_1;
	u32 link0_an_0, link0_an_1;
	u32 timeout_count;
	bool is_match;
	struct dss_io_data *io;
	struct dss_io_data *hdcp_io;
	u8 aksv[5], *bksv = NULL;
	u8 an[8];
	u8 bcaps;
	struct hdmi_tx_ddc_data ddc_data;
	u32 link0_status, an_ready, keys_state;
	u8 buf[0xFF];

	struct scm_hdcp_req scm_buf[SCM_HDCP_MAX_REG];
	u32 phy_addr;
	u32 ret  = 0;
	u32 resp = 0;

	if (!hdcp_ctrl || !hdcp_ctrl->init_data.core_io ||
		!hdcp_ctrl->init_data.qfprom_io) {
		DEV_ERR("%s: invalid input\n", __func__);
		rc = -EINVAL;
		rc = -EINVAL;
		goto error;
		goto error;
	}
	}
	DEV_DBG("%s: %s: AKSV=%02x%08x\n", __func__, HDCP_STATE_NAME,
		qfprom_aksv_msb, qfprom_aksv_lsb);


	/*
	phy_addr = hdcp_ctrl->init_data.phy_addr;
	 * Write AKSV read from QFPROM to the HDCP registers.
	bksv = hdcp_ctrl->current_tp.bksv;
	 * This step is needed for HDCP authentication and must be
	io = hdcp_ctrl->init_data.core_io;
	 * written before enabling HDCP.
	hdcp_io = hdcp_ctrl->init_data.hdcp_io;
	 */
	DSS_REG_W(io, HDMI_HDCP_SW_LOWER_AKSV, qfprom_aksv_lsb);
	DSS_REG_W(io, HDMI_HDCP_SW_UPPER_AKSV, qfprom_aksv_msb);


	/* Check to see if link0_Status has stale values for An ready bit */
	if (HDCP_STATE_AUTHENTICATING != hdcp_ctrl->hdcp_state) {
	link0_status = DSS_REG_R(io, HDMI_HDCP_LINK0_STATUS);
		DEV_ERR("%s: %s: invalid state. returning\n", __func__,
	DEV_DBG("%s: %s: Before enabling cipher Link0_status=0x%08x\n",
			HDCP_STATE_NAME);
		__func__, HDCP_STATE_NAME, link0_status);
		rc = -EINVAL;
	if (link0_status & (BIT(8) | BIT(9))) {
		goto error;
		DEV_DBG("%s: %s: An ready even before enabling HDCP\n",
		__func__, HDCP_STATE_NAME);
		stale_an = true;
	}
	}


	/* Clear any DDC failures from previous tries */
	reset_hdcp_ddc_failures(hdcp_ctrl);

	/*
	/*
	 * Read BCAPS
	 * Read BCAPS
	 * We need to first try to read an HDCP register on the sink to see if
	 * We need to first try to read an HDCP register on the sink to see if
@@ -387,35 +415,6 @@ static int hdmi_hdcp_authentication_part1(struct hdmi_hdcp_ctrl *hdcp_ctrl)
	hdcp_ctrl->current_tp.ds_type =
	hdcp_ctrl->current_tp.ds_type =
		(bcaps & BIT(6)) >> 6 ? DS_REPEATER : DS_RECEIVER;
		(bcaps & BIT(6)) >> 6 ? DS_REPEATER : DS_RECEIVER;


	/*
	 * HDCP setup prior to enabling HDCP_CTRL.
	 * Setup seed values for random number An.
	 */
	DSS_REG_W(io, HDMI_HDCP_ENTROPY_CTRL0, 0xB1FFB0FF);
	DSS_REG_W(io, HDMI_HDCP_ENTROPY_CTRL1, 0xF00DFACE);

	/* Disable the RngCipher state */
	DSS_REG_W(io, HDMI_HDCP_DEBUG_CTRL,
		DSS_REG_R(io, HDMI_HDCP_DEBUG_CTRL) & ~(BIT(2)));
	DEV_DBG("%s: %s: HDCP_DEBUG_CTRL=0x%08x\n", __func__, HDCP_STATE_NAME,
		DSS_REG_R(io, HDMI_HDCP_DEBUG_CTRL));

	/*
	 * Ensure that all register writes are completed before
	 * enabling HDCP cipher
	 */
	wmb();

	/*
	 * Enable HDCP
	 * This needs to be done as early as possible in order for the
	 * hardware to make An available to read
	 */
	DSS_REG_W(io, HDMI_HDCP_CTRL, BIT(0));

	/* Clear any DDC failures from previous tries */
	reset_hdcp_ddc_failures(hdcp_ctrl);

	/* Write BCAPS to the hardware */
	/* Write BCAPS to the hardware */
	if (hdcp_ctrl->tz_hdcp) {
	if (hdcp_ctrl->tz_hdcp) {
		memset(scm_buf, 0x00, sizeof(scm_buf));
		memset(scm_buf, 0x00, sizeof(scm_buf));
@@ -437,19 +436,6 @@ static int hdmi_hdcp_authentication_part1(struct hdmi_hdcp_ctrl *hdcp_ctrl)
		DSS_REG_W(io, HDMI_HDCP_RCVPORT_DATA12, bcaps);
		DSS_REG_W(io, HDMI_HDCP_RCVPORT_DATA12, bcaps);
	}
	}


	/*
	 * If we had stale values for the An ready bit, it should most
	 * likely be cleared now after enabling HDCP cipher
	 */
	link0_status = DSS_REG_R(io, HDMI_HDCP_LINK0_STATUS);
	DEV_DBG("%s: %s: After enabling HDCP Link0_Status=0x%08x\n",
		__func__, HDCP_STATE_NAME, link0_status);
	if (!(link0_status & (BIT(8) | BIT(9)))) {
		DEV_DBG("%s: %s: An not ready after enabling HDCP\n",
			__func__, HDCP_STATE_NAME);
		stale_an = false;
	}

	/* Wait for HDCP keys to be checked and validated */
	/* Wait for HDCP keys to be checked and validated */
	timeout_count = 100;
	timeout_count = 100;
	keys_state = (link0_status >> 28) & 0x7;
	keys_state = (link0_status >> 28) & 0x7;
@@ -497,15 +483,8 @@ static int hdmi_hdcp_authentication_part1(struct hdmi_hdcp_ctrl *hdcp_ctrl)
		goto error;
		goto error;
	}
	}


	/*
	/* As per hardware recommendations, wait before reading An */
	 * In cases where An_ready bits had stale values, it would be
	msleep(20);
	 * better to delay reading of An to avoid any potential of this
	 * read being blocked
	 */
	if (stale_an) {
		msleep(200);
		stale_an = false;
	}


	/* Read An0 and An1 */
	/* Read An0 and An1 */
	link0_an_0 = DSS_REG_R(io, HDMI_HDCP_RCVPORT_DATA5);
	link0_an_0 = DSS_REG_R(io, HDMI_HDCP_RCVPORT_DATA5);
@@ -1334,11 +1313,13 @@ int hdmi_hdcp_authenticate(void *input)


	DEV_DBG("%s: %s: Queuing work to start HDCP authentication", __func__,
	DEV_DBG("%s: %s: Queuing work to start HDCP authentication", __func__,
		HDCP_STATE_NAME);
		HDCP_STATE_NAME);
	mutex_lock(hdcp_ctrl->init_data.mutex);

	hdcp_ctrl->hdcp_state = HDCP_STATE_AUTHENTICATING;
	if (!hdmi_hdcp_load_keys(input))
	mutex_unlock(hdcp_ctrl->init_data.mutex);
		queue_delayed_work(hdcp_ctrl->init_data.workq,
		queue_delayed_work(hdcp_ctrl->init_data.workq,
		&hdcp_ctrl->hdcp_auth_work, 0);
			&hdcp_ctrl->hdcp_auth_work, HZ/2);
	else
		queue_work(hdcp_ctrl->init_data.workq,
			&hdcp_ctrl->hdcp_int_work);


	return 0;
	return 0;
} /* hdmi_hdcp_authenticate */
} /* hdmi_hdcp_authenticate */
@@ -1380,14 +1361,12 @@ int hdmi_hdcp_reauthenticate(void *input)
	/* Disable encryption and disable the HDCP block */
	/* Disable encryption and disable the HDCP block */
	DSS_REG_W(io, HDMI_HDCP_CTRL, 0);
	DSS_REG_W(io, HDMI_HDCP_CTRL, 0);


	/* Restart authentication attempt */
	if (!hdmi_hdcp_load_keys(input))
	DEV_DBG("%s: %s: Scheduling work to start HDCP authentication",
		__func__, HDCP_STATE_NAME);
	mutex_lock(hdcp_ctrl->init_data.mutex);
	hdcp_ctrl->hdcp_state = HDCP_STATE_AUTHENTICATING;
	mutex_unlock(hdcp_ctrl->init_data.mutex);
		queue_delayed_work(hdcp_ctrl->init_data.workq,
		queue_delayed_work(hdcp_ctrl->init_data.workq,
			&hdcp_ctrl->hdcp_auth_work, HZ/2);
			&hdcp_ctrl->hdcp_auth_work, HZ/2);
	else
		queue_work(hdcp_ctrl->init_data.workq,
			&hdcp_ctrl->hdcp_int_work);


	return ret;
	return ret;
} /* hdmi_hdcp_reauthenticate */
} /* hdmi_hdcp_reauthenticate */