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

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

Merge "drm/msm: add support for parsing hdmi/hdcp capabilities"

parents 68717de4 7c1f3156
Loading
Loading
Loading
Loading
+95 −0
Original line number Diff line number Diff line
@@ -29,6 +29,7 @@
#include "sde_connector.h"
#include "msm_drv.h"
#include "sde_hdmi.h"
#include "sde_hdmi_regs.h"

static DEFINE_MUTEX(sde_hdmi_list_lock);
static LIST_HEAD(sde_hdmi_list);
@@ -921,6 +922,16 @@ static void _sde_hdmi_cec_update_phys_addr(struct sde_hdmi *display)
			CEC_PHYS_ADDR_INVALID);
}

static void _sde_hdmi_map_regs(struct sde_hdmi *display, struct hdmi *hdmi)
{
	display->io[HDMI_TX_CORE_IO].base = hdmi->mmio;
	display->io[HDMI_TX_CORE_IO].len = hdmi->mmio_len;
	display->io[HDMI_TX_QFPROM_IO].base = hdmi->qfprom_mmio;
	display->io[HDMI_TX_QFPROM_IO].len = hdmi->qfprom_mmio_len;
	display->io[HDMI_TX_HDCP_IO].base = hdmi->hdcp_mmio;
	display->io[HDMI_TX_HDCP_IO].len = hdmi->hdcp_mmio_len;
}

static void _sde_hdmi_hotplug_work(struct work_struct *work)
{
	struct sde_hdmi *sde_hdmi =
@@ -1540,6 +1551,86 @@ int sde_hdmi_connector_pre_deinit(struct drm_connector *connector,
	return 0;
}

static void _sde_hdmi_get_tx_version(struct sde_hdmi *sde_hdmi)
{
	struct hdmi *hdmi = sde_hdmi->ctrl.ctrl;

	sde_hdmi->hdmi_tx_version = hdmi_read(hdmi, REG_HDMI_VERSION);
	sde_hdmi->hdmi_tx_major_version =
		SDE_GET_MAJOR_VER(sde_hdmi->hdmi_tx_version);

	switch (sde_hdmi->hdmi_tx_major_version) {
	case (HDMI_TX_VERSION_3):
		sde_hdmi->max_pclk_khz = HDMI_TX_3_MAX_PCLK_RATE;
		break;
	case (HDMI_TX_VERSION_4):
		sde_hdmi->max_pclk_khz = HDMI_TX_4_MAX_PCLK_RATE;
		break;
	default:
		sde_hdmi->max_pclk_khz = HDMI_DEFAULT_MAX_PCLK_RATE;
		break;
	}
	SDE_DEBUG("sde_hdmi->hdmi_tx_version = 0x%x\n",
		sde_hdmi->hdmi_tx_version);
	SDE_DEBUG("sde_hdmi->hdmi_tx_major_version = 0x%x\n",
		sde_hdmi->hdmi_tx_major_version);
	SDE_DEBUG("sde_hdmi->max_pclk_khz = 0x%x\n",
		sde_hdmi->max_pclk_khz);
}

static int sde_hdmi_tx_check_capability(struct sde_hdmi *sde_hdmi)
{
	u32 hdmi_disabled, hdcp_disabled, reg_val;
	int ret = 0;
	struct hdmi *hdmi = sde_hdmi->ctrl.ctrl;

	/* check if hdmi and hdcp are disabled */
	if (sde_hdmi->hdmi_tx_major_version < HDMI_TX_VERSION_4) {
		hdcp_disabled = hdmi_qfprom_read(hdmi,
		QFPROM_RAW_FEAT_CONFIG_ROW0_LSB) & BIT(31);

		hdmi_disabled = hdmi_qfprom_read(hdmi,
		QFPROM_RAW_FEAT_CONFIG_ROW0_MSB) & BIT(0);
	} else {
		reg_val = hdmi_qfprom_read(hdmi,
		QFPROM_RAW_FEAT_CONFIG_ROW0_LSB + QFPROM_RAW_VERSION_4);
		hdcp_disabled = reg_val & BIT(12);

		hdmi_disabled = reg_val & BIT(13);

		reg_val = hdmi_qfprom_read(hdmi, SEC_CTRL_HW_VERSION);

		SDE_DEBUG("SEC_CTRL_HW_VERSION reg_val = 0x%x\n", reg_val);
		/*
		 * With HDCP enabled on capable hardware, check if HW
		 * or SW keys should be used.
		 */
		if (!hdcp_disabled && (reg_val >= HDCP_SEL_MIN_SEC_VERSION)) {
			reg_val = hdmi_qfprom_read(hdmi,
			QFPROM_RAW_FEAT_CONFIG_ROW0_MSB +
			QFPROM_RAW_VERSION_4);

			if (!(reg_val & BIT(23)))
				sde_hdmi->hdcp1_use_sw_keys = true;
		}
	}

	SDE_DEBUG("%s: Features <HDMI:%s, HDCP:%s>\n", __func__,
			hdmi_disabled ? "OFF" : "ON",
			hdcp_disabled ? "OFF" : "ON");

	if (hdmi_disabled) {
		DEV_ERR("%s: HDMI disabled\n", __func__);
		ret = -ENODEV;
		goto end;
	}

	sde_hdmi->hdcp14_present = !hdcp_disabled;

 end:
	return ret;
} /* hdmi_tx_check_capability */

int sde_hdmi_connector_post_init(struct drm_connector *connector,
		void *info,
		void *display)
@@ -1572,6 +1663,8 @@ int sde_hdmi_connector_post_init(struct drm_connector *connector,
	if (rc)
		SDE_ERROR("failed to enable HPD: %d\n", rc);

	_sde_hdmi_get_tx_version(sde_hdmi);
	sde_hdmi_tx_check_capability(sde_hdmi);
	return rc;
}

@@ -1770,6 +1863,8 @@ static int sde_hdmi_bind(struct device *dev, struct device *master, void *data)
	display_ctrl->ctrl = priv->hdmi;
	display->drm_dev = drm;

	_sde_hdmi_map_regs(display, priv->hdmi);

	mutex_unlock(&display->display_lock);
	return rc;

+25 −2
Original line number Diff line number Diff line
@@ -25,7 +25,9 @@
#include <drm/drm_crtc.h>
#include <media/cec-notifier.h>
#include "hdmi.h"

#include "sde_kms.h"
#include "sde_connector.h"
#include "msm_drv.h"
#include "sde_edid_parser.h"

#ifdef HDMI_DEBUG_ENABLE
@@ -34,6 +36,10 @@
#define SDE_HDMI_DEBUG(fmt, args...)   SDE_DEBUG(fmt, ##args)
#endif

/* HW Revisions for different SDE targets */
#define SDE_GET_MAJOR_VER(rev)((rev) >> 28)
#define SDE_GET_MINOR_VER(rev)(((rev) >> 16) & 0xFFF)

/**
 * struct sde_hdmi_info - defines hdmi display properties
 * @display_type:      Display type as defined by device tree.
@@ -69,6 +75,13 @@ struct sde_hdmi_ctrl {
	u32 hdmi_ctrl_idx;
};

enum hdmi_tx_io_type {
	HDMI_TX_CORE_IO,
	HDMI_TX_QFPROM_IO,
	HDMI_TX_HDCP_IO,
	HDMI_TX_MAX_IO
};

/**
 * struct sde_hdmi - hdmi display information
 * @pdev:             Pointer to platform device.
@@ -112,7 +125,11 @@ struct sde_hdmi {
	struct drm_display_mode mode;
	bool connected;
	bool is_tpg_enabled;

	u32 hdmi_tx_version;
	u32 hdmi_tx_major_version;
	u32 max_pclk_khz;
	bool hdcp1_use_sw_keys;
	u32 hdcp14_present;
	struct work_struct hpd_work;
	bool codec_ready;
	bool client_notify_pending;
@@ -120,6 +137,7 @@ struct sde_hdmi {
	struct irq_domain *irq_domain;
	struct cec_notifier *notifier;

	struct dss_io_data io[HDMI_TX_MAX_IO];
	/* DEBUG FS */
	struct dentry *root;
};
@@ -144,6 +162,11 @@ enum hdmi_tx_scdc_access_type {

#define HDMI_KHZ_TO_HZ 1000
#define HDMI_MHZ_TO_HZ 1000000

/* Maximum pixel clock rates for hdmi tx */
#define HDMI_DEFAULT_MAX_PCLK_RATE	148500
#define HDMI_TX_3_MAX_PCLK_RATE		297000
#define HDMI_TX_4_MAX_PCLK_RATE		600000
/**
 * hdmi_tx_ddc_timer_type() - hdmi DDC timer functionalities.
 */
+39 −2
Original line number Diff line number Diff line
@@ -95,7 +95,7 @@ static struct hdmi *hdmi_init(struct platform_device *pdev)
	struct hdmi_platform_config *config = pdev->dev.platform_data;
	struct hdmi *hdmi = NULL;
	struct resource *res;
	int i, ret;
	int i, ret = 0;

	hdmi = devm_kzalloc(&pdev->dev, sizeof(*hdmi), GFP_KERNEL);
	if (!hdmi) {
@@ -119,9 +119,19 @@ static struct hdmi *hdmi_init(struct platform_device *pdev)
		}
	}

	res = platform_get_resource_byname(pdev,
			IORESOURCE_MEM, config->mmio_name);
	if (!res) {
		dev_err(&pdev->dev, "failed to find ctrl resource\n");
		ret = -ENOMEM;
		goto fail;
	}
	hdmi->mmio_len = (u32)resource_size(res);
	hdmi->mmio = msm_ioremap(pdev, config->mmio_name, "HDMI");
	if (IS_ERR(hdmi->mmio)) {
		ret = PTR_ERR(hdmi->mmio);
		dev_info(&pdev->dev, "can't map hdmi resource\n");
		hdmi->mmio = NULL;
		goto fail;
	}

@@ -130,13 +140,39 @@ static struct hdmi *hdmi_init(struct platform_device *pdev)
		config->mmio_name);
	hdmi->mmio_phy_addr = res->start;

	res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
	config->qfprom_mmio_name);

	if (!res) {
		dev_err(&pdev->dev, "failed to find qfprom resource\n");
		ret = -ENOMEM;
		goto fail;
	}
	hdmi->qfprom_mmio_len = (u32)resource_size(res);

	hdmi->qfprom_mmio = msm_ioremap(pdev,
		config->qfprom_mmio_name, "HDMI_QFPROM");

	if (IS_ERR(hdmi->qfprom_mmio)) {
		dev_info(&pdev->dev, "can't find qfprom resource\n");
		dev_info(&pdev->dev, "can't map qfprom resource\n");
		hdmi->qfprom_mmio = NULL;
	}

	res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
			config->hdcp_mmio_name);
	if (!res) {
		dev_err(&pdev->dev, "failed to find hdcp resource: %d\n", ret);
		ret = -ENOMEM;
		goto fail;
	}
	hdmi->hdcp_mmio_len = (u32)resource_size(res);
	hdmi->hdcp_mmio = msm_ioremap(pdev,
		config->hdcp_mmio_name, "HDMI_HDCP");
	if (IS_ERR(hdmi->hdcp_mmio)) {
		dev_info(&pdev->dev, "can't map hdcp resource\n");
		hdmi->hdcp_mmio = NULL;
	}

	hdmi->hpd_regs = devm_kzalloc(&pdev->dev, sizeof(hdmi->hpd_regs[0]) *
			config->hpd_reg_cnt, GFP_KERNEL);
	if (!hdmi->hpd_regs) {
@@ -468,6 +504,7 @@ static int hdmi_bind(struct device *dev, struct device *master, void *data)

	hdmi_cfg->mmio_name     = "core_physical";
	hdmi_cfg->qfprom_mmio_name = "qfprom_physical";
	hdmi_cfg->hdcp_mmio_name = "hdcp_physical";
	hdmi_cfg->ddc_clk_gpio  = get_gpio(dev, of_node, "qcom,hdmi-tx-ddc-clk");
	hdmi_cfg->ddc_data_gpio = get_gpio(dev, of_node, "qcom,hdmi-tx-ddc-data");
	hdmi_cfg->hpd_gpio      = get_gpio(dev, of_node, "qcom,hdmi-tx-hpd");
+5 −1
Original line number Diff line number Diff line
@@ -54,6 +54,10 @@ struct hdmi {

	void __iomem *mmio;
	void __iomem *qfprom_mmio;
	void __iomem *hdcp_mmio;
	u32 mmio_len;
	u32 qfprom_mmio_len;
	u32 hdcp_mmio_len;
	phys_addr_t mmio_phy_addr;

	struct regulator **hpd_regs;
@@ -91,7 +95,7 @@ struct hdmi_platform_config {
	struct hdmi_phy *(*phy_init)(struct hdmi *hdmi);
	const char *mmio_name;
	const char *qfprom_mmio_name;

	const char *hdcp_mmio_name;
	/* regulators that need to be on for hpd: */
	const char **hpd_reg_names;
	int hpd_reg_cnt;
+1 −1
Original line number Diff line number Diff line
/* Copyright (c) 2010-2016, The Linux Foundation. All rights reserved.
/* Copyright (c) 2010-2017, The Linux Foundation. All rights reserved.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 and