drm/msm/hdmi: add hdmi hdcp support (V3)
Add HDMI HDCP support including HDCP PartI/II/III authentication. V1: Initial Change V2: Address Bjorn&Rob's comments Refactor the authentication process to use single work instead of multiple work for different authentication stages. V3: Update to align with qcom SCM api. Signed-off-by: Jilai Wang <jilaiw@codeaurora.org> Signed-off-by: Rob Clark <robdclark@gmail.com>
This commit is contained in:
parent
2d3584eb87
commit
c6a57a50ad
|
@ -9,6 +9,7 @@ config DRM_MSM
|
||||||
select DRM_PANEL
|
select DRM_PANEL
|
||||||
select SHMEM
|
select SHMEM
|
||||||
select TMPFS
|
select TMPFS
|
||||||
|
select QCOM_SCM
|
||||||
default y
|
default y
|
||||||
help
|
help
|
||||||
DRM/KMS driver for MSM/snapdragon.
|
DRM/KMS driver for MSM/snapdragon.
|
||||||
|
|
|
@ -10,6 +10,7 @@ msm-y := \
|
||||||
hdmi/hdmi_audio.o \
|
hdmi/hdmi_audio.o \
|
||||||
hdmi/hdmi_bridge.o \
|
hdmi/hdmi_bridge.o \
|
||||||
hdmi/hdmi_connector.o \
|
hdmi/hdmi_connector.o \
|
||||||
|
hdmi/hdmi_hdcp.o \
|
||||||
hdmi/hdmi_i2c.o \
|
hdmi/hdmi_i2c.o \
|
||||||
hdmi/hdmi_phy_8960.o \
|
hdmi/hdmi_phy_8960.o \
|
||||||
hdmi/hdmi_phy_8x60.o \
|
hdmi/hdmi_phy_8x60.o \
|
||||||
|
|
|
@ -22,7 +22,9 @@
|
||||||
void hdmi_set_mode(struct hdmi *hdmi, bool power_on)
|
void hdmi_set_mode(struct hdmi *hdmi, bool power_on)
|
||||||
{
|
{
|
||||||
uint32_t ctrl = 0;
|
uint32_t ctrl = 0;
|
||||||
|
unsigned long flags;
|
||||||
|
|
||||||
|
spin_lock_irqsave(&hdmi->reg_lock, flags);
|
||||||
if (power_on) {
|
if (power_on) {
|
||||||
ctrl |= HDMI_CTRL_ENABLE;
|
ctrl |= HDMI_CTRL_ENABLE;
|
||||||
if (!hdmi->hdmi_mode) {
|
if (!hdmi->hdmi_mode) {
|
||||||
|
@ -37,6 +39,7 @@ void hdmi_set_mode(struct hdmi *hdmi, bool power_on)
|
||||||
}
|
}
|
||||||
|
|
||||||
hdmi_write(hdmi, REG_HDMI_CTRL, ctrl);
|
hdmi_write(hdmi, REG_HDMI_CTRL, ctrl);
|
||||||
|
spin_unlock_irqrestore(&hdmi->reg_lock, flags);
|
||||||
DBG("HDMI Core: %s, HDMI_CTRL=0x%08x",
|
DBG("HDMI Core: %s, HDMI_CTRL=0x%08x",
|
||||||
power_on ? "Enable" : "Disable", ctrl);
|
power_on ? "Enable" : "Disable", ctrl);
|
||||||
}
|
}
|
||||||
|
@ -51,6 +54,10 @@ static irqreturn_t hdmi_irq(int irq, void *dev_id)
|
||||||
/* Process DDC: */
|
/* Process DDC: */
|
||||||
hdmi_i2c_irq(hdmi->i2c);
|
hdmi_i2c_irq(hdmi->i2c);
|
||||||
|
|
||||||
|
/* Process HDCP: */
|
||||||
|
if (hdmi->hdcp_ctrl)
|
||||||
|
hdmi_hdcp_irq(hdmi->hdcp_ctrl);
|
||||||
|
|
||||||
/* TODO audio.. */
|
/* TODO audio.. */
|
||||||
|
|
||||||
return IRQ_HANDLED;
|
return IRQ_HANDLED;
|
||||||
|
@ -60,6 +67,15 @@ static void hdmi_destroy(struct hdmi *hdmi)
|
||||||
{
|
{
|
||||||
struct hdmi_phy *phy = hdmi->phy;
|
struct hdmi_phy *phy = hdmi->phy;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* at this point, hpd has been disabled,
|
||||||
|
* after flush workq, it's safe to deinit hdcp
|
||||||
|
*/
|
||||||
|
if (hdmi->workq) {
|
||||||
|
flush_workqueue(hdmi->workq);
|
||||||
|
destroy_workqueue(hdmi->workq);
|
||||||
|
}
|
||||||
|
hdmi_hdcp_destroy(hdmi);
|
||||||
if (phy)
|
if (phy)
|
||||||
phy->funcs->destroy(phy);
|
phy->funcs->destroy(phy);
|
||||||
|
|
||||||
|
@ -77,6 +93,7 @@ static struct hdmi *hdmi_init(struct platform_device *pdev)
|
||||||
{
|
{
|
||||||
struct hdmi_platform_config *config = pdev->dev.platform_data;
|
struct hdmi_platform_config *config = pdev->dev.platform_data;
|
||||||
struct hdmi *hdmi = NULL;
|
struct hdmi *hdmi = NULL;
|
||||||
|
struct resource *res;
|
||||||
int i, ret;
|
int i, ret;
|
||||||
|
|
||||||
hdmi = devm_kzalloc(&pdev->dev, sizeof(*hdmi), GFP_KERNEL);
|
hdmi = devm_kzalloc(&pdev->dev, sizeof(*hdmi), GFP_KERNEL);
|
||||||
|
@ -87,6 +104,7 @@ static struct hdmi *hdmi_init(struct platform_device *pdev)
|
||||||
|
|
||||||
hdmi->pdev = pdev;
|
hdmi->pdev = pdev;
|
||||||
hdmi->config = config;
|
hdmi->config = config;
|
||||||
|
spin_lock_init(&hdmi->reg_lock);
|
||||||
|
|
||||||
/* not sure about which phy maps to which msm.. probably I miss some */
|
/* not sure about which phy maps to which msm.. probably I miss some */
|
||||||
if (config->phy_init)
|
if (config->phy_init)
|
||||||
|
@ -107,6 +125,18 @@ static struct hdmi *hdmi_init(struct platform_device *pdev)
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* HDCP needs physical address of hdmi register */
|
||||||
|
res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
|
||||||
|
config->mmio_name);
|
||||||
|
hdmi->mmio_phy_addr = res->start;
|
||||||
|
|
||||||
|
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");
|
||||||
|
hdmi->qfprom_mmio = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
hdmi->hpd_regs = devm_kzalloc(&pdev->dev, sizeof(hdmi->hpd_regs[0]) *
|
hdmi->hpd_regs = devm_kzalloc(&pdev->dev, sizeof(hdmi->hpd_regs[0]) *
|
||||||
config->hpd_reg_cnt, GFP_KERNEL);
|
config->hpd_reg_cnt, GFP_KERNEL);
|
||||||
if (!hdmi->hpd_regs) {
|
if (!hdmi->hpd_regs) {
|
||||||
|
@ -189,6 +219,8 @@ static struct hdmi *hdmi_init(struct platform_device *pdev)
|
||||||
hdmi->pwr_clks[i] = clk;
|
hdmi->pwr_clks[i] = clk;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
hdmi->workq = alloc_ordered_workqueue("msm_hdmi", 0);
|
||||||
|
|
||||||
hdmi->i2c = hdmi_i2c_init(hdmi);
|
hdmi->i2c = hdmi_i2c_init(hdmi);
|
||||||
if (IS_ERR(hdmi->i2c)) {
|
if (IS_ERR(hdmi->i2c)) {
|
||||||
ret = PTR_ERR(hdmi->i2c);
|
ret = PTR_ERR(hdmi->i2c);
|
||||||
|
@ -197,6 +229,12 @@ static struct hdmi *hdmi_init(struct platform_device *pdev)
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
hdmi->hdcp_ctrl = hdmi_hdcp_init(hdmi);
|
||||||
|
if (IS_ERR(hdmi->hdcp_ctrl)) {
|
||||||
|
dev_warn(&pdev->dev, "failed to init hdcp: disabled\n");
|
||||||
|
hdmi->hdcp_ctrl = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
return hdmi;
|
return hdmi;
|
||||||
|
|
||||||
fail:
|
fail:
|
||||||
|
@ -376,6 +414,7 @@ static int hdmi_bind(struct device *dev, struct device *master, void *data)
|
||||||
}
|
}
|
||||||
|
|
||||||
hdmi_cfg->mmio_name = "core_physical";
|
hdmi_cfg->mmio_name = "core_physical";
|
||||||
|
hdmi_cfg->qfprom_mmio_name = "qfprom_physical";
|
||||||
hdmi_cfg->ddc_clk_gpio = get_gpio(dev, of_node, "qcom,hdmi-tx-ddc-clk");
|
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->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");
|
hdmi_cfg->hpd_gpio = get_gpio(dev, of_node, "qcom,hdmi-tx-hpd");
|
||||||
|
@ -391,7 +430,6 @@ static int hdmi_bind(struct device *dev, struct device *master, void *data)
|
||||||
if (cpu_is_apq8064()) {
|
if (cpu_is_apq8064()) {
|
||||||
static const char *hpd_reg_names[] = {"8921_hdmi_mvs"};
|
static const char *hpd_reg_names[] = {"8921_hdmi_mvs"};
|
||||||
config.phy_init = hdmi_phy_8960_init;
|
config.phy_init = hdmi_phy_8960_init;
|
||||||
config.mmio_name = "hdmi_msm_hdmi_addr";
|
|
||||||
config.hpd_reg_names = hpd_reg_names;
|
config.hpd_reg_names = hpd_reg_names;
|
||||||
config.hpd_reg_cnt = ARRAY_SIZE(hpd_reg_names);
|
config.hpd_reg_cnt = ARRAY_SIZE(hpd_reg_names);
|
||||||
config.hpd_clk_names = hpd_clk_names;
|
config.hpd_clk_names = hpd_clk_names;
|
||||||
|
@ -404,7 +442,6 @@ static int hdmi_bind(struct device *dev, struct device *master, void *data)
|
||||||
} else if (cpu_is_msm8960() || cpu_is_msm8960ab()) {
|
} else if (cpu_is_msm8960() || cpu_is_msm8960ab()) {
|
||||||
static const char *hpd_reg_names[] = {"8921_hdmi_mvs"};
|
static const char *hpd_reg_names[] = {"8921_hdmi_mvs"};
|
||||||
config.phy_init = hdmi_phy_8960_init;
|
config.phy_init = hdmi_phy_8960_init;
|
||||||
config.mmio_name = "hdmi_msm_hdmi_addr";
|
|
||||||
config.hpd_reg_names = hpd_reg_names;
|
config.hpd_reg_names = hpd_reg_names;
|
||||||
config.hpd_reg_cnt = ARRAY_SIZE(hpd_reg_names);
|
config.hpd_reg_cnt = ARRAY_SIZE(hpd_reg_names);
|
||||||
config.hpd_clk_names = hpd_clk_names;
|
config.hpd_clk_names = hpd_clk_names;
|
||||||
|
@ -419,7 +456,6 @@ static int hdmi_bind(struct device *dev, struct device *master, void *data)
|
||||||
"8901_hdmi_mvs", "8901_mpp0"
|
"8901_hdmi_mvs", "8901_mpp0"
|
||||||
};
|
};
|
||||||
config.phy_init = hdmi_phy_8x60_init;
|
config.phy_init = hdmi_phy_8x60_init;
|
||||||
config.mmio_name = "hdmi_msm_hdmi_addr";
|
|
||||||
config.hpd_reg_names = hpd_reg_names;
|
config.hpd_reg_names = hpd_reg_names;
|
||||||
config.hpd_reg_cnt = ARRAY_SIZE(hpd_reg_names);
|
config.hpd_reg_cnt = ARRAY_SIZE(hpd_reg_names);
|
||||||
config.hpd_clk_names = hpd_clk_names;
|
config.hpd_clk_names = hpd_clk_names;
|
||||||
|
@ -430,6 +466,9 @@ static int hdmi_bind(struct device *dev, struct device *master, void *data)
|
||||||
config.mux_en_gpio = -1;
|
config.mux_en_gpio = -1;
|
||||||
config.mux_sel_gpio = -1;
|
config.mux_sel_gpio = -1;
|
||||||
}
|
}
|
||||||
|
config.mmio_name = "hdmi_msm_hdmi_addr";
|
||||||
|
config.qfprom_mmio_name = "hdmi_msm_qfprom_addr";
|
||||||
|
|
||||||
hdmi_cfg = &config;
|
hdmi_cfg = &config;
|
||||||
#endif
|
#endif
|
||||||
dev->platform_data = hdmi_cfg;
|
dev->platform_data = hdmi_cfg;
|
||||||
|
|
|
@ -37,6 +37,8 @@ struct hdmi_audio {
|
||||||
int rate;
|
int rate;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct hdmi_hdcp_ctrl;
|
||||||
|
|
||||||
struct hdmi {
|
struct hdmi {
|
||||||
struct drm_device *dev;
|
struct drm_device *dev;
|
||||||
struct platform_device *pdev;
|
struct platform_device *pdev;
|
||||||
|
@ -51,6 +53,8 @@ struct hdmi {
|
||||||
unsigned long int pixclock;
|
unsigned long int pixclock;
|
||||||
|
|
||||||
void __iomem *mmio;
|
void __iomem *mmio;
|
||||||
|
void __iomem *qfprom_mmio;
|
||||||
|
phys_addr_t mmio_phy_addr;
|
||||||
|
|
||||||
struct regulator **hpd_regs;
|
struct regulator **hpd_regs;
|
||||||
struct regulator **pwr_regs;
|
struct regulator **pwr_regs;
|
||||||
|
@ -68,12 +72,25 @@ struct hdmi {
|
||||||
bool hdmi_mode; /* are we in hdmi mode? */
|
bool hdmi_mode; /* are we in hdmi mode? */
|
||||||
|
|
||||||
int irq;
|
int irq;
|
||||||
|
struct workqueue_struct *workq;
|
||||||
|
|
||||||
|
struct hdmi_hdcp_ctrl *hdcp_ctrl;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* spinlock to protect registers shared by different execution
|
||||||
|
* REG_HDMI_CTRL
|
||||||
|
* REG_HDMI_DDC_ARBITRATION
|
||||||
|
* REG_HDMI_HDCP_INT_CTRL
|
||||||
|
* REG_HDMI_HPD_CTRL
|
||||||
|
*/
|
||||||
|
spinlock_t reg_lock;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* platform config data (ie. from DT, or pdata) */
|
/* platform config data (ie. from DT, or pdata) */
|
||||||
struct hdmi_platform_config {
|
struct hdmi_platform_config {
|
||||||
struct hdmi_phy *(*phy_init)(struct hdmi *hdmi);
|
struct hdmi_phy *(*phy_init)(struct hdmi *hdmi);
|
||||||
const char *mmio_name;
|
const char *mmio_name;
|
||||||
|
const char *qfprom_mmio_name;
|
||||||
|
|
||||||
/* regulators that need to be on for hpd: */
|
/* regulators that need to be on for hpd: */
|
||||||
const char **hpd_reg_names;
|
const char **hpd_reg_names;
|
||||||
|
@ -109,6 +126,11 @@ static inline u32 hdmi_read(struct hdmi *hdmi, u32 reg)
|
||||||
return msm_readl(hdmi->mmio + reg);
|
return msm_readl(hdmi->mmio + reg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline u32 hdmi_qfprom_read(struct hdmi *hdmi, u32 reg)
|
||||||
|
{
|
||||||
|
return msm_readl(hdmi->qfprom_mmio + reg);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The phy appears to be different, for example between 8960 and 8x60,
|
* The phy appears to be different, for example between 8960 and 8x60,
|
||||||
* so split the phy related functions out and load the correct one at
|
* so split the phy related functions out and load the correct one at
|
||||||
|
@ -163,4 +185,13 @@ void hdmi_i2c_irq(struct i2c_adapter *i2c);
|
||||||
void hdmi_i2c_destroy(struct i2c_adapter *i2c);
|
void hdmi_i2c_destroy(struct i2c_adapter *i2c);
|
||||||
struct i2c_adapter *hdmi_i2c_init(struct hdmi *hdmi);
|
struct i2c_adapter *hdmi_i2c_init(struct hdmi *hdmi);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* hdcp
|
||||||
|
*/
|
||||||
|
struct hdmi_hdcp_ctrl *hdmi_hdcp_init(struct hdmi *hdmi);
|
||||||
|
void hdmi_hdcp_destroy(struct hdmi *hdmi);
|
||||||
|
void hdmi_hdcp_on(struct hdmi_hdcp_ctrl *hdcp_ctrl);
|
||||||
|
void hdmi_hdcp_off(struct hdmi_hdcp_ctrl *hdcp_ctrl);
|
||||||
|
void hdmi_hdcp_irq(struct hdmi_hdcp_ctrl *hdcp_ctrl);
|
||||||
|
|
||||||
#endif /* __HDMI_CONNECTOR_H__ */
|
#endif /* __HDMI_CONNECTOR_H__ */
|
||||||
|
|
|
@ -203,7 +203,6 @@ int hdmi_audio_update(struct hdmi *hdmi)
|
||||||
audio_config |= HDMI_AUDIO_CFG_FIFO_WATERMARK(4);
|
audio_config |= HDMI_AUDIO_CFG_FIFO_WATERMARK(4);
|
||||||
audio_config |= HDMI_AUDIO_CFG_ENGINE_ENABLE;
|
audio_config |= HDMI_AUDIO_CFG_ENGINE_ENABLE;
|
||||||
} else {
|
} else {
|
||||||
hdmi_write(hdmi, REG_HDMI_GC, HDMI_GC_MUTE);
|
|
||||||
acr_pkt_ctrl &= ~HDMI_ACR_PKT_CTRL_CONT;
|
acr_pkt_ctrl &= ~HDMI_ACR_PKT_CTRL_CONT;
|
||||||
acr_pkt_ctrl &= ~HDMI_ACR_PKT_CTRL_SEND;
|
acr_pkt_ctrl &= ~HDMI_ACR_PKT_CTRL_SEND;
|
||||||
vbi_pkt_ctrl &= ~HDMI_VBI_PKT_CTRL_GC_ENABLE;
|
vbi_pkt_ctrl &= ~HDMI_VBI_PKT_CTRL_GC_ENABLE;
|
||||||
|
|
|
@ -102,6 +102,9 @@ static void hdmi_bridge_pre_enable(struct drm_bridge *bridge)
|
||||||
|
|
||||||
phy->funcs->powerup(phy, hdmi->pixclock);
|
phy->funcs->powerup(phy, hdmi->pixclock);
|
||||||
hdmi_set_mode(hdmi, true);
|
hdmi_set_mode(hdmi, true);
|
||||||
|
|
||||||
|
if (hdmi->hdcp_ctrl)
|
||||||
|
hdmi_hdcp_on(hdmi->hdcp_ctrl);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void hdmi_bridge_enable(struct drm_bridge *bridge)
|
static void hdmi_bridge_enable(struct drm_bridge *bridge)
|
||||||
|
@ -118,6 +121,9 @@ static void hdmi_bridge_post_disable(struct drm_bridge *bridge)
|
||||||
struct hdmi *hdmi = hdmi_bridge->hdmi;
|
struct hdmi *hdmi = hdmi_bridge->hdmi;
|
||||||
struct hdmi_phy *phy = hdmi->phy;
|
struct hdmi_phy *phy = hdmi->phy;
|
||||||
|
|
||||||
|
if (hdmi->hdcp_ctrl)
|
||||||
|
hdmi_hdcp_off(hdmi->hdcp_ctrl);
|
||||||
|
|
||||||
DBG("power down");
|
DBG("power down");
|
||||||
hdmi_set_mode(hdmi, false);
|
hdmi_set_mode(hdmi, false);
|
||||||
phy->funcs->powerdown(phy);
|
phy->funcs->powerdown(phy);
|
||||||
|
@ -142,8 +148,6 @@ static void hdmi_bridge_mode_set(struct drm_bridge *bridge,
|
||||||
|
|
||||||
hdmi->pixclock = mode->clock * 1000;
|
hdmi->pixclock = mode->clock * 1000;
|
||||||
|
|
||||||
hdmi->hdmi_mode = drm_match_cea_mode(mode) > 1;
|
|
||||||
|
|
||||||
hstart = mode->htotal - mode->hsync_start;
|
hstart = mode->htotal - mode->hsync_start;
|
||||||
hend = mode->htotal - mode->hsync_start + mode->hdisplay;
|
hend = mode->htotal - mode->hsync_start + mode->hdisplay;
|
||||||
|
|
||||||
|
|
|
@ -141,6 +141,7 @@ static int hpd_enable(struct hdmi_connector *hdmi_connector)
|
||||||
struct hdmi_phy *phy = hdmi->phy;
|
struct hdmi_phy *phy = hdmi->phy;
|
||||||
uint32_t hpd_ctrl;
|
uint32_t hpd_ctrl;
|
||||||
int i, ret;
|
int i, ret;
|
||||||
|
unsigned long flags;
|
||||||
|
|
||||||
for (i = 0; i < config->hpd_reg_cnt; i++) {
|
for (i = 0; i < config->hpd_reg_cnt; i++) {
|
||||||
ret = regulator_enable(hdmi->hpd_regs[i]);
|
ret = regulator_enable(hdmi->hpd_regs[i]);
|
||||||
|
@ -192,6 +193,7 @@ static int hpd_enable(struct hdmi_connector *hdmi_connector)
|
||||||
HDMI_HPD_INT_CTRL_INT_EN);
|
HDMI_HPD_INT_CTRL_INT_EN);
|
||||||
|
|
||||||
/* set timeout to 4.1ms (max) for hardware debounce */
|
/* set timeout to 4.1ms (max) for hardware debounce */
|
||||||
|
spin_lock_irqsave(&hdmi->reg_lock, flags);
|
||||||
hpd_ctrl = hdmi_read(hdmi, REG_HDMI_HPD_CTRL);
|
hpd_ctrl = hdmi_read(hdmi, REG_HDMI_HPD_CTRL);
|
||||||
hpd_ctrl |= HDMI_HPD_CTRL_TIMEOUT(0x1fff);
|
hpd_ctrl |= HDMI_HPD_CTRL_TIMEOUT(0x1fff);
|
||||||
|
|
||||||
|
@ -200,6 +202,7 @@ static int hpd_enable(struct hdmi_connector *hdmi_connector)
|
||||||
~HDMI_HPD_CTRL_ENABLE & hpd_ctrl);
|
~HDMI_HPD_CTRL_ENABLE & hpd_ctrl);
|
||||||
hdmi_write(hdmi, REG_HDMI_HPD_CTRL,
|
hdmi_write(hdmi, REG_HDMI_HPD_CTRL,
|
||||||
HDMI_HPD_CTRL_ENABLE | hpd_ctrl);
|
HDMI_HPD_CTRL_ENABLE | hpd_ctrl);
|
||||||
|
spin_unlock_irqrestore(&hdmi->reg_lock, flags);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
@ -250,7 +253,6 @@ hotplug_work(struct work_struct *work)
|
||||||
void hdmi_connector_irq(struct drm_connector *connector)
|
void hdmi_connector_irq(struct drm_connector *connector)
|
||||||
{
|
{
|
||||||
struct hdmi_connector *hdmi_connector = to_hdmi_connector(connector);
|
struct hdmi_connector *hdmi_connector = to_hdmi_connector(connector);
|
||||||
struct msm_drm_private *priv = connector->dev->dev_private;
|
|
||||||
struct hdmi *hdmi = hdmi_connector->hdmi;
|
struct hdmi *hdmi = hdmi_connector->hdmi;
|
||||||
uint32_t hpd_int_status, hpd_int_ctrl;
|
uint32_t hpd_int_status, hpd_int_ctrl;
|
||||||
|
|
||||||
|
@ -274,7 +276,7 @@ void hdmi_connector_irq(struct drm_connector *connector)
|
||||||
hpd_int_ctrl |= HDMI_HPD_INT_CTRL_INT_CONNECT;
|
hpd_int_ctrl |= HDMI_HPD_INT_CTRL_INT_CONNECT;
|
||||||
hdmi_write(hdmi, REG_HDMI_HPD_INT_CTRL, hpd_int_ctrl);
|
hdmi_write(hdmi, REG_HDMI_HPD_INT_CTRL, hpd_int_ctrl);
|
||||||
|
|
||||||
queue_work(priv->wq, &hdmi_connector->hpd_work);
|
queue_work(hdmi->workq, &hdmi_connector->hpd_work);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -350,6 +352,7 @@ static int hdmi_connector_get_modes(struct drm_connector *connector)
|
||||||
|
|
||||||
hdmi_write(hdmi, REG_HDMI_CTRL, hdmi_ctrl);
|
hdmi_write(hdmi, REG_HDMI_CTRL, hdmi_ctrl);
|
||||||
|
|
||||||
|
hdmi->hdmi_mode = drm_detect_hdmi_monitor(edid);
|
||||||
drm_mode_connector_update_edid_property(connector, edid);
|
drm_mode_connector_update_edid_property(connector, edid);
|
||||||
|
|
||||||
if (edid) {
|
if (edid) {
|
||||||
|
|
1437
drivers/gpu/drm/msm/hdmi/hdmi_hdcp.c
Normal file
1437
drivers/gpu/drm/msm/hdmi/hdmi_hdcp.c
Normal file
File diff suppressed because it is too large
Load diff
Loading…
Reference in a new issue