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

Commit 3cae69ec authored by Alhad Purnapatre's avatar Alhad Purnapatre Committed by Matt Wagantall
Browse files

msm: mdss: hdmi: Add support for reading new secure register offsets



In HDMI Tx controller version 4 and beyond, HDCP registers have been
moved out of secure domain and can be accessed directly, in an
address range of their own. Add support to map this address range and
access these registers directly if we are running on HDMI controller
version 4 and above.

Change-Id: I2d790bf60f42055ba3e10d0ec82812be292826a3
Signed-off-by: default avatarAlhad Purnapatre <alhadp@codeaurora.org>
parent 16fadda8
Loading
Loading
Loading
Loading
+4 −2
Original line number Diff line number Diff line
@@ -61,8 +61,10 @@ Example:
		compatible = "qcom,hdmi-tx";
		reg =	<0xfd922100 0x35C>,
			<0xfd922500 0x7C>,
			<0xfc4b8000 0x60F0>;
		reg-names = "core_physical", "phy_physical", "qfprom_physical";
			<0xfc4b8000 0x60F0>,
			<0xfe2a0000 0xFFF>;
		reg-names = "core_physical", "phy_physical", "qfprom_physical",
			"hdcp_physical";

		hpd-gdsc-supply = <&gdsc_mdss>;
		hpd-5v-supply = <&pm8941_mvs2>;
+3 −2
Original line number Diff line number Diff line
@@ -426,8 +426,9 @@
		compatible = "qcom,hdmi-tx";

		reg =	<0x9a0000 0x50c>,
			<0x70000 0x6158>;
		reg-names = "core_physical", "qfprom_physical";
			<0x70000 0x6158>,
			<0x9e0000 0xFFF>;
		reg-names = "core_physical", "qfprom_physical", "hdcp_physical";

		hpd-gdsc-supply = <&gdsc_mdss>;
		hpd-mmagic-mdss-gdsc-supply = <&gdsc_mmagic_mdss>;
+98 −36
Original line number Diff line number Diff line
@@ -57,6 +57,7 @@ struct hdmi_hdcp_ctrl {
	struct completion r0_checked;
	struct hdmi_hdcp_init_data init_data;
	struct hdmi_hdcp_ops *ops;
	bool hdmi_tx_ver_4;
};

const char *hdcp_state_name(enum hdmi_hdcp_state hdcp_state)
@@ -248,12 +249,14 @@ static int hdmi_hdcp_authentication_part1(struct hdmi_hdcp_ctrl *hdcp_ctrl)
	bool is_match;
	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;

	struct scm_hdcp_req scm_buf[SCM_HDCP_MAX_REG];
	u32 phy_addr;
@@ -268,30 +271,28 @@ static int hdmi_hdcp_authentication_part1(struct hdmi_hdcp_ctrl *hdcp_ctrl)
	}

	phy_addr = hdcp_ctrl->init_data.phy_addr;
	bksv = hdcp_ctrl->current_tp.bksv;
	io = hdcp_ctrl->init_data.core_io;
	hdcp_io = hdcp_ctrl->init_data.hdcp_io;

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

	bksv = hdcp_ctrl->current_tp.bksv;

	io = hdcp_ctrl->init_data.core_io;

	/* Fetch aksv from QFPROM, this info should be public. */
	if (hdcp_ctrl->init_data.hdmi_tx_ver < HDMI_TX_VERSION_4) {
		qfprom_aksv_lsb = DSS_REG_R(hdcp_ctrl->init_data.qfprom_io,
			HDCP_KSV_LSB);
		qfprom_aksv_msb = DSS_REG_R(hdcp_ctrl->init_data.qfprom_io,
			HDCP_KSV_MSB);
	} else {
	ksv_lsb_addr = HDCP_KSV_LSB;
	ksv_msb_addr = HDCP_KSV_MSB;
	if (hdcp_ctrl->hdmi_tx_ver_4) {
		ksv_lsb_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,
			HDCP_KSV_LSB + HDCP_KSV_VERSION_4);
		ksv_lsb_addr);
	qfprom_aksv_msb = DSS_REG_R(hdcp_ctrl->init_data.qfprom_io,
			HDCP_KSV_MSB + HDCP_KSV_VERSION_4);
	}
		ksv_msb_addr);

	aksv[0] =  qfprom_aksv_lsb        & 0xFF;
	aksv[1] = (qfprom_aksv_lsb >> 8)  & 0xFF;
@@ -369,7 +370,8 @@ static int hdmi_hdcp_authentication_part1(struct hdmi_hdcp_ctrl *hdcp_ctrl)
	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
	/*
	 * Ensure that all register writes are completed before
	 * enabling HDCP cipher
	 */
	wmb();
@@ -385,22 +387,22 @@ static int hdmi_hdcp_authentication_part1(struct hdmi_hdcp_ctrl *hdcp_ctrl)
	reset_hdcp_ddc_failures(hdcp_ctrl);

	/* Write BCAPS to the hardware */

	if (hdcp_ctrl->tz_hdcp) {
		memset(scm_buf, 0x00, sizeof(scm_buf));

		/* Write BCAPS to hardware */
		scm_buf[0].addr = phy_addr + HDMI_HDCP_RCVPORT_DATA12;
		scm_buf[0].val  = bcaps;

		ret = hdcp_scm_call(scm_buf, &resp);

		if (ret || resp) {
			DEV_ERR("%s: error: scm_call ret = %d, resp = %d\n",
				__func__, ret, resp);
			rc = -EINVAL;
			goto error;
		}
	} else if (hdcp_ctrl->hdmi_tx_ver_4) {
		DSS_REG_W(hdcp_io, HDCP_SEC_TZ_HV_HLOS_HDCP_RCVPORT_DATA12,
				bcaps);
	} else {
		DSS_REG_W(io, HDMI_HDCP_RCVPORT_DATA12, bcaps);
	}
@@ -564,7 +566,6 @@ static int hdmi_hdcp_authentication_part1(struct hdmi_hdcp_ctrl *hdcp_ctrl)
	DEV_DBG("%s: %s: BKSV=%02x%08x\n", __func__, HDCP_STATE_NAME,
		link0_bksv_1, link0_bksv_0);

	/* Write BKSV read from sink to HDCP registers */
	if (hdcp_ctrl->tz_hdcp) {
		memset(scm_buf, 0x00, sizeof(scm_buf));

@@ -581,6 +582,11 @@ static int hdmi_hdcp_authentication_part1(struct hdmi_hdcp_ctrl *hdcp_ctrl)
			rc = -EINVAL;
			goto error;
		}
	} else if (hdcp_ctrl->hdmi_tx_ver_4) {
		DSS_REG_W(hdcp_io, HDCP_SEC_TZ_HV_HLOS_HDCP_RCVPORT_DATA0,
			link0_bksv_0);
		DSS_REG_W(hdcp_io, HDCP_SEC_TZ_HV_HLOS_HDCP_RCVPORT_DATA1,
			link0_bksv_1);
	} else {
		DSS_REG_W(io, HDMI_HDCP_RCVPORT_DATA0, link0_bksv_0);
		DSS_REG_W(io, HDMI_HDCP_RCVPORT_DATA1, link0_bksv_1);
@@ -652,7 +658,7 @@ error:
	return rc;
} /* hdmi_hdcp_authentication_part1 */

#define READ_WRITE_V_H(off, name, reg, wr) \
#define READ_WRITE_V_H(io, off, name, reg, wr) \
do { \
	ddc_data.offset = (off); \
	memset(what, 0, sizeof(what)); \
@@ -667,7 +673,7 @@ do { \
			__func__, HDCP_STATE_NAME, what, buf[0], buf[1], \
			buf[2], buf[3]); \
	if (wr) { \
		DSS_REG_W(io, (reg), \
		DSS_REG_W((io), (reg), \
			(buf[3] << 24 | buf[2] << 16 | buf[1] << 8 | buf[0])); \
	} \
} while (0);
@@ -718,7 +724,7 @@ static int hdmi_hdcp_transfer_v_h(struct hdmi_hdcp_ctrl *hdcp_ctrl)
		for (iter = 0; iter < size && iter < SCM_HDCP_MAX_REG; iter++) {
			struct hdmi_hdcp_reg_data *rd = reg_data + iter;

			READ_WRITE_V_H(rd->off, rd->name, 0, false);
			READ_WRITE_V_H(io, rd->off, rd->name, 0, false);

			rd->reg_val = buf[3] << 24 | buf[2] << 16 |
				buf[1] << 8 | buf[0];
@@ -734,21 +740,48 @@ static int hdmi_hdcp_transfer_v_h(struct hdmi_hdcp_ctrl *hdcp_ctrl)
			rc = -EINVAL;
			goto error;
		}
	} else if (hdcp_ctrl->hdmi_tx_ver_4) {
		struct dss_io_data *hdcp_io = hdcp_ctrl->init_data.hdcp_io;

		/* Read V'.HO 4 Byte at offset 0x20 */
		READ_WRITE_V_H(hdcp_io, 0x20, "V' H0",
				HDCP_SEC_TZ_HV_HLOS_HDCP_RCVPORT_DATA7, true);

		/* Read V'.H1 4 Byte at offset 0x24 */
		READ_WRITE_V_H(hdcp_io, 0x24, "V' H1",
				HDCP_SEC_TZ_HV_HLOS_HDCP_RCVPORT_DATA8, true);

		/* Read V'.H2 4 Byte at offset 0x28 */
		READ_WRITE_V_H(hdcp_io, 0x28, "V' H2",
				HDCP_SEC_TZ_HV_HLOS_HDCP_RCVPORT_DATA9, true);

		/* Read V'.H3 4 Byte at offset 0x2C */
		READ_WRITE_V_H(hdcp_io, 0x2C, "V' H3",
				HDCP_SEC_TZ_HV_HLOS_HDCP_RCVPORT_DATA10, true);

		/* Read V'.H4 4 Byte at offset 0x30 */
		READ_WRITE_V_H(hdcp_io, 0x30, "V' H4",
				HDCP_SEC_TZ_HV_HLOS_HDCP_RCVPORT_DATA11, true);
	} else {
		/* Read V'.HO 4 Byte at offset 0x20 */
		READ_WRITE_V_H(0x20, "V' H0", HDMI_HDCP_RCVPORT_DATA7, true);
		READ_WRITE_V_H(io, 0x20, "V' H0", HDMI_HDCP_RCVPORT_DATA7,
				true);

		/* Read V'.H1 4 Byte at offset 0x24 */
		READ_WRITE_V_H(0x24, "V' H1", HDMI_HDCP_RCVPORT_DATA8, true);
		READ_WRITE_V_H(io, 0x24, "V' H1", HDMI_HDCP_RCVPORT_DATA8,
				true);

		/* Read V'.H2 4 Byte at offset 0x28 */
		READ_WRITE_V_H(0x28, "V' H2", HDMI_HDCP_RCVPORT_DATA9, true);
		READ_WRITE_V_H(io, 0x28, "V' H2", HDMI_HDCP_RCVPORT_DATA9,
				true);

		/* Read V'.H3 4 Byte at offset 0x2C */
		READ_WRITE_V_H(0x2C, "V' H3", HDMI_HDCP_RCVPORT_DATA10, true);
		READ_WRITE_V_H(io, 0x2C, "V' H3", HDMI_HDCP_RCVPORT_DATA10,
				true);

		/* Read V'.H4 4 Byte at offset 0x30 */
		READ_WRITE_V_H(0x30, "V' H4", HDMI_HDCP_RCVPORT_DATA11, true);
		READ_WRITE_V_H(io, 0x30, "V' H4", HDMI_HDCP_RCVPORT_DATA11,
				true);
	}

error:
@@ -856,6 +889,10 @@ static int hdmi_hdcp_authentication_part2(struct hdmi_hdcp_ctrl *hdcp_ctrl)
			rc = -EINVAL;
			goto error;
		}
	} else if (hdcp_ctrl->hdmi_tx_ver_4) {
		DSS_REG_W(hdcp_ctrl->init_data.hdcp_io,
				HDCP_SEC_TZ_HV_HLOS_HDCP_RCVPORT_DATA12,
				bcaps | (bstatus << 8));
	} else {
		DSS_REG_W(io, HDMI_HDCP_RCVPORT_DATA12, bcaps | (bstatus << 8));
	}
@@ -969,6 +1006,13 @@ static int hdmi_hdcp_authentication_part2(struct hdmi_hdcp_ctrl *hdcp_ctrl)
			rc = -EINVAL;
			goto error;
		}
	} else if (hdcp_ctrl->hdmi_tx_ver_4) {
		DSS_REG_W(hdcp_ctrl->init_data.hdcp_io,
				HDCP_SEC_TZ_HV_HLOS_HDCP_SHA_CTRL,
				HDCP_REG_ENABLE);
		DSS_REG_W(hdcp_ctrl->init_data.hdcp_io,
				HDCP_SEC_TZ_HV_HLOS_HDCP_SHA_CTRL,
				HDCP_REG_DISABLE);
	} else {
		DSS_REG_W(io, HDMI_HDCP_SHA_CTRL, HDCP_REG_ENABLE);
		DSS_REG_W(io, HDMI_HDCP_SHA_CTRL, HDCP_REG_DISABLE);
@@ -989,6 +1033,10 @@ static int hdmi_hdcp_authentication_part2(struct hdmi_hdcp_ctrl *hdcp_ctrl)
				rc = -EINVAL;
				goto error;
			}
		} else if (hdcp_ctrl->hdmi_tx_ver_4) {
			DSS_REG_W_ND(hdcp_ctrl->init_data.hdcp_io,
					HDCP_SEC_TZ_HV_HLOS_HDCP_SHA_DATA,
					ksv_fifo[i] << 16);
		} else {
			DSS_REG_W_ND(io, HDMI_HDCP_SHA_DATA, ksv_fifo[i] << 16);
		}
@@ -1001,7 +1049,7 @@ static int hdmi_hdcp_authentication_part2(struct hdmi_hdcp_ctrl *hdcp_ctrl)
			timeout_count = 100;
			while (!(DSS_REG_R(io, HDMI_HDCP_SHA_STATUS) & BIT(0))
				&& (--timeout_count)) {
				DEV_DBG("%s: %s: Wrote 64 bytes KVS FIFO\n",
				DEV_DBG("%s: %s: Wrote 64 bytes KSV FIFO\n",
					__func__, HDCP_STATE_NAME);
				DEV_DBG("%s: %s: HDCP_SHA_STATUS=%08x\n",
					__func__, HDCP_STATE_NAME,
@@ -1032,6 +1080,10 @@ static int hdmi_hdcp_authentication_part2(struct hdmi_hdcp_ctrl *hdcp_ctrl)
			rc = -EINVAL;
			goto error;
		}
	} else if (hdcp_ctrl->hdmi_tx_ver_4) {
		DSS_REG_W_ND(hdcp_ctrl->init_data.hdcp_io,
				HDCP_SEC_TZ_HV_HLOS_HDCP_SHA_DATA,
				(ksv_fifo[ksv_bytes - 1] << 16) | 0x1);
	} else {
		DSS_REG_W_ND(io, HDMI_HDCP_SHA_DATA,
			(ksv_fifo[ksv_bytes - 1] << 16) | 0x1);
@@ -1561,6 +1613,12 @@ void *hdmi_hdcp_init(struct hdmi_hdcp_init_data *init_data)
		goto error;
	}

	if (init_data->hdmi_tx_ver >= HDMI_TX_VERSION_4
			&& !init_data->hdcp_io) {
		DEV_ERR("%s: hdcp_io required for HDMI Tx Ver 4\n", __func__);
		goto error;
	}

	hdcp_ctrl = kzalloc(sizeof(*hdcp_ctrl), GFP_KERNEL);
	if (!hdcp_ctrl) {
		DEV_ERR("%s: Out of memory\n", __func__);
@@ -1569,6 +1627,8 @@ void *hdmi_hdcp_init(struct hdmi_hdcp_init_data *init_data)

	hdcp_ctrl->init_data = *init_data;
	hdcp_ctrl->ops = &ops;
	hdcp_ctrl->hdmi_tx_ver_4 =
		(init_data->hdmi_tx_ver >= HDMI_TX_VERSION_4);

	if (sysfs_create_group(init_data->sysfs_kobj,
				&hdmi_hdcp_fs_attr_group)) {
@@ -1582,14 +1642,16 @@ void *hdmi_hdcp_init(struct hdmi_hdcp_init_data *init_data)
	hdcp_ctrl->hdcp_state = HDCP_STATE_INACTIVE;
	init_completion(&hdcp_ctrl->r0_checked);

	if (!hdcp_ctrl->hdmi_tx_ver_4) {
		ret = scm_is_call_available(SCM_SVC_HDCP, SCM_CMD_HDCP);
		if (ret <= 0) {
		DEV_ERR("%s: error: secure hdcp service unavailable, ret = %d",
			DEV_ERR("%s: secure hdcp service unavailable, ret = %d",
				 __func__, ret);
		} else {
			DEV_DBG("%s: tz_hdcp = 1\n", __func__);
			hdcp_ctrl->tz_hdcp = 1;
		}
	}

	DEV_DBG("%s: HDCP module initialized. HDCP_STATE=%s", __func__,
		HDCP_STATE_NAME);
+1 −0
Original line number Diff line number Diff line
@@ -26,6 +26,7 @@ enum hdmi_hdcp_state {
struct hdmi_hdcp_init_data {
	struct dss_io_data *core_io;
	struct dss_io_data *qfprom_io;
	struct dss_io_data *hdcp_io;
	struct mutex *mutex;
	struct kobject *sysfs_kobj;
	struct workqueue_struct *workq;
+3 −3
Original line number Diff line number Diff line
@@ -415,6 +415,7 @@ static const char *hdmi_tx_io_name(u32 type)
	case HDMI_TX_CORE_IO:	return "core_physical";
	case HDMI_TX_PHY_IO:	return "phy_physical";
	case HDMI_TX_QFPROM_IO:	return "qfprom_physical";
	case HDMI_TX_HDCP_IO:	return "hdcp_physical";
	default:		return NULL;
	}
} /* hdmi_tx_io_name */
@@ -1207,6 +1208,8 @@ static int hdmi_tx_init_features(struct hdmi_tx_ctrl *hdmi_ctrl)
	hdcp_init_data.core_io = &hdmi_ctrl->pdata.io[HDMI_TX_CORE_IO];
	hdcp_init_data.qfprom_io =
		&hdmi_ctrl->pdata.io[HDMI_TX_QFPROM_IO];
	hdcp_init_data.hdcp_io =
		&hdmi_ctrl->pdata.io[HDMI_TX_HDCP_IO];
	hdcp_init_data.mutex = &hdmi_ctrl->mutex;
	hdcp_init_data.sysfs_kobj = hdmi_ctrl->kobj;
	hdcp_init_data.ddc_ctrl = &hdmi_ctrl->ddc_ctrl;
@@ -1389,9 +1392,6 @@ static void hdmi_tx_hpd_int_work(struct work_struct *work)

		hdmi_tx_send_cable_notification(hdmi_ctrl, true);
	} else {
		hdmi_ctrl->hdcp_ops = NULL;
		hdmi_ctrl->hdcp_feature_data = NULL;
		hdmi_ctrl->hdcp22_present = false;
		hdmi_tx_set_audio_switch_node(hdmi_ctrl, 0);
		hdmi_tx_wait_for_audio_engine(hdmi_ctrl);

Loading