Loading drivers/gpu/drm/msm/Makefile +4 −1 Original line number Diff line number Diff line Loading @@ -13,6 +13,7 @@ msm_drm-y := \ hdmi/hdmi_connector.o \ hdmi/hdmi_hdcp.o \ hdmi/hdmi_i2c.o \ hdmi/hdmi_util.o \ hdmi/hdmi_phy_8960.o \ hdmi/hdmi_phy_8x60.o \ hdmi/hdmi_phy_8x74.o \ Loading Loading @@ -50,7 +51,8 @@ msm_drm-y := \ sde_dbg_evtlog.o \ sde_io_util.o \ dba_bridge.o \ sde_edid_parser.o sde_edid_parser.o \ sde_hdcp_1x.o # use drm gpu driver only if qcom_kgsl driver not available ifneq ($(CONFIG_QCOM_KGSL),y) Loading Loading @@ -101,6 +103,7 @@ msm_drm-$(CONFIG_DRM_MSM_DSI_STAGING) += dsi-staging/dsi_phy.o \ dsi-staging/dsi_display_test.o msm_drm-$(CONFIG_DRM_SDE_HDMI) += \ hdmi-staging/sde_hdmi_util.o \ hdmi-staging/sde_hdmi.o \ hdmi-staging/sde_hdmi_bridge.o \ hdmi-staging/sde_hdmi_audio.o \ Loading drivers/gpu/drm/msm/hdmi-staging/sde_hdmi.c +213 −82 Original line number Diff line number Diff line Loading @@ -30,6 +30,7 @@ #include "msm_drv.h" #include "sde_hdmi.h" #include "sde_hdmi_regs.h" #include "hdmi.h" static DEFINE_MUTEX(sde_hdmi_list_lock); static LIST_HEAD(sde_hdmi_list); Loading Loading @@ -426,6 +427,118 @@ static u64 _sde_hdmi_clip_valid_pclk(struct drm_display_mode *mode, u64 pclk_in) return pclk_clip; } static void sde_hdmi_tx_hdcp_cb(void *ptr, enum sde_hdcp_states status) { struct sde_hdmi *hdmi_ctrl = (struct sde_hdmi *)ptr; struct hdmi *hdmi; if (!hdmi_ctrl) { DEV_ERR("%s: invalid input\n", __func__); return; } hdmi = hdmi_ctrl->ctrl.ctrl; hdmi_ctrl->hdcp_status = status; queue_delayed_work(hdmi->workq, &hdmi_ctrl->hdcp_cb_work, HZ/4); } void sde_hdmi_hdcp_off(struct sde_hdmi *hdmi_ctrl) { if (!hdmi_ctrl) { SDE_ERROR("%s: invalid input\n", __func__); return; } if (hdmi_ctrl->hdcp_ops) hdmi_ctrl->hdcp_ops->off(hdmi_ctrl->hdcp_data); flush_delayed_work(&hdmi_ctrl->hdcp_cb_work); hdmi_ctrl->hdcp_ops = NULL; } static void sde_hdmi_tx_hdcp_cb_work(struct work_struct *work) { struct sde_hdmi *hdmi_ctrl = NULL; struct delayed_work *dw = to_delayed_work(work); int rc = 0; struct hdmi *hdmi; hdmi_ctrl = container_of(dw, struct sde_hdmi, hdcp_cb_work); if (!hdmi_ctrl) { DEV_DBG("%s: invalid input\n", __func__); return; } hdmi = hdmi_ctrl->ctrl.ctrl; switch (hdmi_ctrl->hdcp_status) { case HDCP_STATE_AUTHENTICATED: hdmi_ctrl->auth_state = true; if (sde_hdmi_tx_is_panel_on(hdmi_ctrl) && sde_hdmi_tx_is_stream_shareable(hdmi_ctrl)) { rc = sde_hdmi_config_avmute(hdmi, false); } if (hdmi_ctrl->hdcp1_use_sw_keys && hdmi_ctrl->hdcp14_present) { if (!hdmi_ctrl->hdcp22_present) hdcp1_set_enc(true); } break; case HDCP_STATE_AUTH_FAIL: if (hdmi_ctrl->hdcp1_use_sw_keys && hdmi_ctrl->hdcp14_present) { if (hdmi_ctrl->auth_state && !hdmi_ctrl->hdcp22_present) hdcp1_set_enc(false); } hdmi_ctrl->auth_state = false; if (sde_hdmi_tx_is_encryption_set(hdmi_ctrl) || !sde_hdmi_tx_is_stream_shareable(hdmi_ctrl)) rc = sde_hdmi_config_avmute(hdmi, true); if (sde_hdmi_tx_is_panel_on(hdmi_ctrl)) { pr_debug("%s: Reauthenticating\n", __func__); if (hdmi_ctrl->hdcp_ops && hdmi_ctrl->hdcp_data) { rc = hdmi_ctrl->hdcp_ops->reauthenticate( hdmi_ctrl->hdcp_data); if (rc) pr_err("%s: HDCP reauth failed. rc=%d\n", __func__, rc); } else pr_err("%s: NULL HDCP Ops and Data\n", __func__); } else { pr_debug("%s: Not reauthenticating. Cable not conn\n", __func__); } break; case HDCP_STATE_AUTH_ENC_NONE: hdmi_ctrl->enc_lvl = HDCP_STATE_AUTH_ENC_NONE; if (sde_hdmi_tx_is_panel_on(hdmi_ctrl)) rc = sde_hdmi_config_avmute(hdmi, false); break; case HDCP_STATE_AUTH_ENC_1X: case HDCP_STATE_AUTH_ENC_2P2: hdmi_ctrl->enc_lvl = hdmi_ctrl->hdcp_status; if (sde_hdmi_tx_is_panel_on(hdmi_ctrl) && sde_hdmi_tx_is_stream_shareable(hdmi_ctrl)) { rc = sde_hdmi_config_avmute(hdmi, false); } else { rc = sde_hdmi_config_avmute(hdmi, true); } break; default: break; /* do nothing */ } } /** * _sde_hdmi_update_pll_delta() - Update the HDMI pixel clock as per input ppm * Loading Loading @@ -920,6 +1033,12 @@ static void _sde_hdmi_cec_update_phys_addr(struct sde_hdmi *display) else cec_notifier_set_phys_addr(display->notifier, CEC_PHYS_ADDR_INVALID); } static void _sde_hdmi_init_ddc(struct sde_hdmi *display, struct hdmi *hdmi) { display->ddc_ctrl.io = &display->io[HDMI_TX_CORE_IO]; } static void _sde_hdmi_map_regs(struct sde_hdmi *display, struct hdmi *hdmi) Loading Loading @@ -1023,8 +1142,14 @@ static irqreturn_t _sde_hdmi_irq(int irq, void *dev_id) hdmi_i2c_irq(hdmi->i2c); /* Process HDCP: */ if (hdmi->hdcp_ctrl && hdmi->is_hdcp_supported) hdmi_hdcp_ctrl_irq(hdmi->hdcp_ctrl); if (sde_hdmi->hdcp_ops && sde_hdmi->hdcp_data) { if (sde_hdmi->hdcp_ops->isr) { if (sde_hdmi->hdcp_ops->isr( sde_hdmi->hdcp_data)) DEV_ERR("%s: hdcp_1x_isr failed\n", __func__); } } /* Process CEC: */ _sde_hdmi_cec_irq(sde_hdmi); Loading Loading @@ -1203,84 +1328,8 @@ void sde_hdmi_set_mode(struct hdmi *hdmi, bool power_on) power_on ? "Enable" : "Disable", ctrl); } int sde_hdmi_ddc_read(struct hdmi *hdmi, u16 addr, u8 offset, u8 *data, u16 data_len) { int rc; int retry = 5; struct i2c_msg msgs[] = { { .addr = addr >> 1, .flags = 0, .len = 1, .buf = &offset, }, { .addr = addr >> 1, .flags = I2C_M_RD, .len = data_len, .buf = data, } }; SDE_HDMI_DEBUG("Start DDC read"); retry: rc = i2c_transfer(hdmi->i2c, msgs, 2); retry--; if (rc == 2) rc = 0; else if (retry > 0) goto retry; else rc = -EIO; SDE_HDMI_DEBUG("End DDC read %d", rc); return rc; } #define DDC_WRITE_MAX_BYTE_NUM 32 int sde_hdmi_ddc_write(struct hdmi *hdmi, u16 addr, u8 offset, u8 *data, u16 data_len) { int rc; int retry = 10; u8 buf[DDC_WRITE_MAX_BYTE_NUM]; struct i2c_msg msgs[] = { { .addr = addr >> 1, .flags = 0, .len = 1, } }; SDE_HDMI_DEBUG("Start DDC write"); if (data_len > (DDC_WRITE_MAX_BYTE_NUM - 1)) { SDE_ERROR("%s: write size too big\n", __func__); return -ERANGE; } buf[0] = offset; memcpy(&buf[1], data, data_len); msgs[0].buf = buf; msgs[0].len = data_len + 1; retry: rc = i2c_transfer(hdmi->i2c, msgs, 1); retry--; if (rc == 1) rc = 0; else if (retry > 0) goto retry; else rc = -EIO; SDE_HDMI_DEBUG("End DDC write %d", rc); return rc; } int sde_hdmi_scdc_read(struct hdmi *hdmi, u32 data_type, u32 *val) { int rc = 0; Loading Loading @@ -1337,7 +1386,8 @@ int sde_hdmi_scdc_read(struct hdmi *hdmi, u32 data_type, u32 *val) break; } rc = sde_hdmi_ddc_read(hdmi, dev_addr, offset, data_buf, data_len); rc = hdmi_ddc_read(hdmi, dev_addr, offset, data_buf, data_len, true); if (rc) { SDE_ERROR("DDC Read failed for %d\n", data_type); return rc; Loading Loading @@ -1409,8 +1459,8 @@ int sde_hdmi_scdc_write(struct hdmi *hdmi, u32 data_type, u32 val) dev_addr = 0xA8; data_len = 1; offset = HDMI_SCDC_TMDS_CONFIG; rc = sde_hdmi_ddc_read(hdmi, dev_addr, offset, &read_val, data_len); rc = hdmi_ddc_read(hdmi, dev_addr, offset, &read_val, data_len, true); if (rc) { SDE_ERROR("scdc read failed\n"); return rc; Loading @@ -1434,7 +1484,8 @@ int sde_hdmi_scdc_write(struct hdmi *hdmi, u32 data_type, u32 val) return -EINVAL; } rc = sde_hdmi_ddc_write(hdmi, dev_addr, offset, data_buf, data_len); rc = hdmi_ddc_write(hdmi, dev_addr, offset, data_buf, data_len, true); if (rc) { SDE_ERROR("DDC Read failed for %d\n", data_type); return rc; Loading Loading @@ -1631,6 +1682,50 @@ static int sde_hdmi_tx_check_capability(struct sde_hdmi *sde_hdmi) return ret; } /* hdmi_tx_check_capability */ static int _sde_hdmi_init_hdcp(struct sde_hdmi *hdmi_ctrl) { struct sde_hdcp_init_data hdcp_init_data; void *hdcp_data; int rc = 0; struct hdmi *hdmi; if (!hdmi_ctrl) { SDE_ERROR("sde_hdmi is NULL\n"); return -EINVAL; } hdmi = hdmi_ctrl->ctrl.ctrl; hdcp_init_data.phy_addr = hdmi->mmio_phy_addr; hdcp_init_data.core_io = &hdmi_ctrl->io[HDMI_TX_CORE_IO]; hdcp_init_data.qfprom_io = &hdmi_ctrl->io[HDMI_TX_QFPROM_IO]; hdcp_init_data.hdcp_io = &hdmi_ctrl->io[HDMI_TX_HDCP_IO]; hdcp_init_data.mutex = &hdmi_ctrl->hdcp_mutex; hdcp_init_data.workq = hdmi->workq; hdcp_init_data.notify_status = sde_hdmi_tx_hdcp_cb; hdcp_init_data.cb_data = (void *)hdmi_ctrl; hdcp_init_data.hdmi_tx_ver = hdmi_ctrl->hdmi_tx_major_version; hdcp_init_data.sec_access = true; hdcp_init_data.client_id = HDCP_CLIENT_HDMI; hdcp_init_data.ddc_ctrl = &hdmi_ctrl->ddc_ctrl; if (hdmi_ctrl->hdcp14_present) { hdcp_data = sde_hdcp_1x_init(&hdcp_init_data); if (IS_ERR_OR_NULL(hdcp_data)) { DEV_ERR("%s: hdcp 1.4 init failed\n", __func__); rc = -EINVAL; kfree(hdcp_data); goto end; } else { hdmi_ctrl->hdcp_feature_data[SDE_HDCP_1x] = hdcp_data; SDE_HDMI_DEBUG("%s: HDCP 1.4 initialized\n", __func__); } } end: return rc; } int sde_hdmi_connector_post_init(struct drm_connector *connector, void *info, void *display) Loading Loading @@ -1664,7 +1759,36 @@ int sde_hdmi_connector_post_init(struct drm_connector *connector, SDE_ERROR("failed to enable HPD: %d\n", rc); _sde_hdmi_get_tx_version(sde_hdmi); sde_hdmi_tx_check_capability(sde_hdmi); _sde_hdmi_init_hdcp(sde_hdmi); return rc; } int sde_hdmi_start_hdcp(struct drm_connector *connector) { int rc; struct sde_connector *c_conn = to_sde_connector(connector); struct sde_hdmi *display = (struct sde_hdmi *)c_conn->display; struct hdmi *hdmi = display->ctrl.ctrl; if (!hdmi) { SDE_ERROR("%s: invalid input\n", __func__); return -EINVAL; } if (!sde_hdmi_tx_is_hdcp_enabled(display)) return 0; if (sde_hdmi_tx_is_encryption_set(display)) sde_hdmi_config_avmute(hdmi, true); rc = display->hdcp_ops->authenticate(display->hdcp_data); if (rc) SDE_ERROR("%s: hdcp auth failed. rc=%d\n", __func__, rc); return rc; } Loading Loading @@ -1781,6 +1905,9 @@ int sde_hdmi_dev_deinit(struct sde_hdmi *display) SDE_ERROR("Invalid params\n"); return -EINVAL; } if (display->hdcp_feature_data[SDE_HDCP_1x]) sde_hdcp_1x_deinit(display->hdcp_feature_data[SDE_HDCP_1x]); return 0; } Loading Loading @@ -1864,7 +1991,11 @@ static int sde_hdmi_bind(struct device *dev, struct device *master, void *data) display->drm_dev = drm; _sde_hdmi_map_regs(display, priv->hdmi); _sde_hdmi_init_ddc(display, priv->hdmi); INIT_DELAYED_WORK(&display->hdcp_cb_work, sde_hdmi_tx_hdcp_cb_work); mutex_init(&display->hdcp_mutex); mutex_unlock(&display->display_lock); return rc; Loading drivers/gpu/drm/msm/hdmi-staging/sde_hdmi.h +59 −27 Original line number Diff line number Diff line Loading @@ -20,6 +20,7 @@ #include <linux/debugfs.h> #include <linux/of_device.h> #include <linux/msm_ext_display.h> #include <linux/hdcp_qseecom.h> #include <drm/drmP.h> #include <drm/drm_crtc.h> Loading @@ -29,6 +30,8 @@ #include "sde_connector.h" #include "msm_drv.h" #include "sde_edid_parser.h" #include "sde_hdmi_util.h" #include "sde_hdcp.h" #ifdef HDMI_DEBUG_ENABLE #define SDE_HDMI_DEBUG(fmt, args...) SDE_ERROR(fmt, ##args) Loading Loading @@ -82,6 +85,11 @@ enum hdmi_tx_io_type { HDMI_TX_MAX_IO }; enum hdmi_tx_feature_type { SDE_HDCP_1x, SDE_HDCP_2P2 }; /** * struct sde_hdmi - hdmi display information * @pdev: Pointer to platform device. Loading Loading @@ -112,7 +120,7 @@ struct sde_hdmi { const char *display_type; struct list_head list; struct mutex display_lock; struct mutex hdcp_mutex; struct sde_hdmi_ctrl ctrl; struct platform_device *ext_pdev; Loading @@ -130,6 +138,18 @@ struct sde_hdmi { u32 max_pclk_khz; bool hdcp1_use_sw_keys; u32 hdcp14_present; u32 hdcp22_present; u8 hdcp_status; u32 enc_lvl; bool auth_state; /*hold final data *based on hdcp support */ void *hdcp_data; /*hold hdcp init data*/ void *hdcp_feature_data[2]; struct sde_hdcp_ops *hdcp_ops; struct sde_hdmi_tx_ddc_ctrl ddc_ctrl; struct work_struct hpd_work; bool codec_ready; bool client_notify_pending; Loading @@ -137,6 +157,7 @@ struct sde_hdmi { struct irq_domain *irq_domain; struct cec_notifier *notifier; struct delayed_work hdcp_cb_work; struct dss_io_data io[HDMI_TX_MAX_IO]; /* DEBUG FS */ struct dentry *root; Loading Loading @@ -337,32 +358,6 @@ struct drm_bridge *sde_hdmi_bridge_init(struct hdmi *hdmi); */ void sde_hdmi_set_mode(struct hdmi *hdmi, bool power_on); /** * sde_hdmi_ddc_read() - common hdmi ddc read API. * @hdmi: Handle to the hdmi. * @addr: Command address. * @offset: Command offset. * @data: Data buffer for read back. * @data_len: Data buffer length. * * Return: error code. */ int sde_hdmi_ddc_read(struct hdmi *hdmi, u16 addr, u8 offset, u8 *data, u16 data_len); /** * sde_hdmi_ddc_write() - common hdmi ddc write API. * @hdmi: Handle to the hdmi. * @addr: Command address. * @offset: Command offset. * @data: Data buffer for write. * @data_len: Data buffer length. * * Return: error code. */ int sde_hdmi_ddc_write(struct hdmi *hdmi, u16 addr, u8 offset, u8 *data, u16 data_len); /** * sde_hdmi_scdc_read() - hdmi 2.0 ddc read API. * @hdmi: Handle to the hdmi. Loading Loading @@ -429,6 +424,13 @@ void sde_hdmi_notify_clients(struct sde_hdmi *display, bool connected); void sde_hdmi_ack_state(struct drm_connector *connector, enum drm_connector_status status); bool sde_hdmi_tx_is_hdcp_enabled(struct sde_hdmi *hdmi_ctrl); bool sde_hdmi_tx_is_encryption_set(struct sde_hdmi *hdmi_ctrl); bool sde_hdmi_tx_is_stream_shareable(struct sde_hdmi *hdmi_ctrl); bool sde_hdmi_tx_is_panel_on(struct sde_hdmi *hdmi_ctrl); int sde_hdmi_start_hdcp(struct drm_connector *connector); void sde_hdmi_hdcp_off(struct sde_hdmi *hdmi_ctrl); #else /*#ifdef CONFIG_DRM_SDE_HDMI*/ static inline u32 sde_hdmi_get_num_of_displays(void) Loading Loading @@ -487,12 +489,42 @@ static inline int sde_hdmi_dev_deinit(struct sde_hdmi *display) return 0; } bool hdmi_tx_is_hdcp_enabled(struct sde_hdmi *hdmi_ctrl) { return false; } bool sde_hdmi_tx_is_encryption_set(struct sde_hdmi *hdmi_ctrl) { return false; } bool sde_hdmi_tx_is_stream_shareable(struct sde_hdmi *hdmi_ctrl) { return false; } bool sde_hdmi_tx_is_panel_on(struct sde_hdmi *hdmi_ctrl) { return false; } static inline int sde_hdmi_drm_init(struct sde_hdmi *display, struct drm_encoder *enc) { return 0; } int sde_hdmi_start_hdcp(struct drm_connector *connector) { return 0; } void sde_hdmi_hdcp_off(struct sde_hdmi *hdmi_ctrl) { } static inline int sde_hdmi_drm_deinit(struct sde_hdmi *display) { return 0; Loading drivers/gpu/drm/msm/hdmi-staging/sde_hdmi_audio.c +0 −34 Original line number Diff line number Diff line Loading @@ -355,37 +355,3 @@ void sde_hdmi_audio_off(struct hdmi *hdmi) SDE_DEBUG("HDMI Audio: Disabled\n"); } int sde_hdmi_config_avmute(struct hdmi *hdmi, bool set) { u32 av_mute_status; bool av_pkt_en = false; if (!hdmi) { SDE_ERROR("invalid HDMI Ctrl\n"); return -ENODEV; } av_mute_status = hdmi_read(hdmi, HDMI_GC); if (set) { if (!(av_mute_status & BIT(0))) { hdmi_write(hdmi, HDMI_GC, av_mute_status | BIT(0)); av_pkt_en = true; } } else { if (av_mute_status & BIT(0)) { hdmi_write(hdmi, HDMI_GC, av_mute_status & ~BIT(0)); av_pkt_en = true; } } /* Enable AV Mute tranmission here */ if (av_pkt_en) hdmi_write(hdmi, HDMI_VBI_PKT_CTRL, hdmi_read(hdmi, HDMI_VBI_PKT_CTRL) | (BIT(4) & BIT(5))); SDE_DEBUG("AVMUTE %s\n", set ? "set" : "cleared"); return 0; } drivers/gpu/drm/msm/hdmi-staging/sde_hdmi_bridge.c +39 −2 Original line number Diff line number Diff line Loading @@ -396,8 +396,45 @@ static void _sde_hdmi_bridge_pre_enable(struct drm_bridge *bridge) mutex_unlock(&display->display_lock); } static void sde_hdmi_update_hdcp_info(struct drm_connector *connector) { void *fd = NULL; struct sde_hdcp_ops *ops = NULL; struct sde_connector *c_conn = to_sde_connector(connector); struct sde_hdmi *display = (struct sde_hdmi *)c_conn->display; if (!display) { DEV_ERR("%s: invalid input\n", __func__); return; } if (!display->hdcp22_present) { if (display->hdcp1_use_sw_keys) { display->hdcp14_present = hdcp1_check_if_supported_load_app(); } if (display->hdcp14_present) { fd = display->hdcp_feature_data[SDE_HDCP_1x]; if (fd) ops = sde_hdcp_1x_start(fd); } } /* update internal data about hdcp */ display->hdcp_data = fd; display->hdcp_ops = ops; } static void _sde_hdmi_bridge_enable(struct drm_bridge *bridge) { struct sde_hdmi_bridge *sde_hdmi_bridge = to_hdmi_bridge(bridge); struct hdmi *hdmi = sde_hdmi_bridge->hdmi; /* need to update hdcp info here to ensure right HDCP support*/ sde_hdmi_update_hdcp_info(hdmi->connector); /* start HDCP authentication */ sde_hdmi_start_hdcp(hdmi->connector); } static void _sde_hdmi_bridge_disable(struct drm_bridge *bridge) Loading @@ -414,8 +451,8 @@ static void _sde_hdmi_bridge_post_disable(struct drm_bridge *bridge) sde_hdmi_notify_clients(display, display->connected); if (hdmi->hdcp_ctrl && hdmi->is_hdcp_supported) hdmi_hdcp_ctrl_off(hdmi->hdcp_ctrl); if (sde_hdmi_tx_is_hdcp_enabled(display)) sde_hdmi_hdcp_off(display); sde_hdmi_audio_off(hdmi); Loading Loading
drivers/gpu/drm/msm/Makefile +4 −1 Original line number Diff line number Diff line Loading @@ -13,6 +13,7 @@ msm_drm-y := \ hdmi/hdmi_connector.o \ hdmi/hdmi_hdcp.o \ hdmi/hdmi_i2c.o \ hdmi/hdmi_util.o \ hdmi/hdmi_phy_8960.o \ hdmi/hdmi_phy_8x60.o \ hdmi/hdmi_phy_8x74.o \ Loading Loading @@ -50,7 +51,8 @@ msm_drm-y := \ sde_dbg_evtlog.o \ sde_io_util.o \ dba_bridge.o \ sde_edid_parser.o sde_edid_parser.o \ sde_hdcp_1x.o # use drm gpu driver only if qcom_kgsl driver not available ifneq ($(CONFIG_QCOM_KGSL),y) Loading Loading @@ -101,6 +103,7 @@ msm_drm-$(CONFIG_DRM_MSM_DSI_STAGING) += dsi-staging/dsi_phy.o \ dsi-staging/dsi_display_test.o msm_drm-$(CONFIG_DRM_SDE_HDMI) += \ hdmi-staging/sde_hdmi_util.o \ hdmi-staging/sde_hdmi.o \ hdmi-staging/sde_hdmi_bridge.o \ hdmi-staging/sde_hdmi_audio.o \ Loading
drivers/gpu/drm/msm/hdmi-staging/sde_hdmi.c +213 −82 Original line number Diff line number Diff line Loading @@ -30,6 +30,7 @@ #include "msm_drv.h" #include "sde_hdmi.h" #include "sde_hdmi_regs.h" #include "hdmi.h" static DEFINE_MUTEX(sde_hdmi_list_lock); static LIST_HEAD(sde_hdmi_list); Loading Loading @@ -426,6 +427,118 @@ static u64 _sde_hdmi_clip_valid_pclk(struct drm_display_mode *mode, u64 pclk_in) return pclk_clip; } static void sde_hdmi_tx_hdcp_cb(void *ptr, enum sde_hdcp_states status) { struct sde_hdmi *hdmi_ctrl = (struct sde_hdmi *)ptr; struct hdmi *hdmi; if (!hdmi_ctrl) { DEV_ERR("%s: invalid input\n", __func__); return; } hdmi = hdmi_ctrl->ctrl.ctrl; hdmi_ctrl->hdcp_status = status; queue_delayed_work(hdmi->workq, &hdmi_ctrl->hdcp_cb_work, HZ/4); } void sde_hdmi_hdcp_off(struct sde_hdmi *hdmi_ctrl) { if (!hdmi_ctrl) { SDE_ERROR("%s: invalid input\n", __func__); return; } if (hdmi_ctrl->hdcp_ops) hdmi_ctrl->hdcp_ops->off(hdmi_ctrl->hdcp_data); flush_delayed_work(&hdmi_ctrl->hdcp_cb_work); hdmi_ctrl->hdcp_ops = NULL; } static void sde_hdmi_tx_hdcp_cb_work(struct work_struct *work) { struct sde_hdmi *hdmi_ctrl = NULL; struct delayed_work *dw = to_delayed_work(work); int rc = 0; struct hdmi *hdmi; hdmi_ctrl = container_of(dw, struct sde_hdmi, hdcp_cb_work); if (!hdmi_ctrl) { DEV_DBG("%s: invalid input\n", __func__); return; } hdmi = hdmi_ctrl->ctrl.ctrl; switch (hdmi_ctrl->hdcp_status) { case HDCP_STATE_AUTHENTICATED: hdmi_ctrl->auth_state = true; if (sde_hdmi_tx_is_panel_on(hdmi_ctrl) && sde_hdmi_tx_is_stream_shareable(hdmi_ctrl)) { rc = sde_hdmi_config_avmute(hdmi, false); } if (hdmi_ctrl->hdcp1_use_sw_keys && hdmi_ctrl->hdcp14_present) { if (!hdmi_ctrl->hdcp22_present) hdcp1_set_enc(true); } break; case HDCP_STATE_AUTH_FAIL: if (hdmi_ctrl->hdcp1_use_sw_keys && hdmi_ctrl->hdcp14_present) { if (hdmi_ctrl->auth_state && !hdmi_ctrl->hdcp22_present) hdcp1_set_enc(false); } hdmi_ctrl->auth_state = false; if (sde_hdmi_tx_is_encryption_set(hdmi_ctrl) || !sde_hdmi_tx_is_stream_shareable(hdmi_ctrl)) rc = sde_hdmi_config_avmute(hdmi, true); if (sde_hdmi_tx_is_panel_on(hdmi_ctrl)) { pr_debug("%s: Reauthenticating\n", __func__); if (hdmi_ctrl->hdcp_ops && hdmi_ctrl->hdcp_data) { rc = hdmi_ctrl->hdcp_ops->reauthenticate( hdmi_ctrl->hdcp_data); if (rc) pr_err("%s: HDCP reauth failed. rc=%d\n", __func__, rc); } else pr_err("%s: NULL HDCP Ops and Data\n", __func__); } else { pr_debug("%s: Not reauthenticating. Cable not conn\n", __func__); } break; case HDCP_STATE_AUTH_ENC_NONE: hdmi_ctrl->enc_lvl = HDCP_STATE_AUTH_ENC_NONE; if (sde_hdmi_tx_is_panel_on(hdmi_ctrl)) rc = sde_hdmi_config_avmute(hdmi, false); break; case HDCP_STATE_AUTH_ENC_1X: case HDCP_STATE_AUTH_ENC_2P2: hdmi_ctrl->enc_lvl = hdmi_ctrl->hdcp_status; if (sde_hdmi_tx_is_panel_on(hdmi_ctrl) && sde_hdmi_tx_is_stream_shareable(hdmi_ctrl)) { rc = sde_hdmi_config_avmute(hdmi, false); } else { rc = sde_hdmi_config_avmute(hdmi, true); } break; default: break; /* do nothing */ } } /** * _sde_hdmi_update_pll_delta() - Update the HDMI pixel clock as per input ppm * Loading Loading @@ -920,6 +1033,12 @@ static void _sde_hdmi_cec_update_phys_addr(struct sde_hdmi *display) else cec_notifier_set_phys_addr(display->notifier, CEC_PHYS_ADDR_INVALID); } static void _sde_hdmi_init_ddc(struct sde_hdmi *display, struct hdmi *hdmi) { display->ddc_ctrl.io = &display->io[HDMI_TX_CORE_IO]; } static void _sde_hdmi_map_regs(struct sde_hdmi *display, struct hdmi *hdmi) Loading Loading @@ -1023,8 +1142,14 @@ static irqreturn_t _sde_hdmi_irq(int irq, void *dev_id) hdmi_i2c_irq(hdmi->i2c); /* Process HDCP: */ if (hdmi->hdcp_ctrl && hdmi->is_hdcp_supported) hdmi_hdcp_ctrl_irq(hdmi->hdcp_ctrl); if (sde_hdmi->hdcp_ops && sde_hdmi->hdcp_data) { if (sde_hdmi->hdcp_ops->isr) { if (sde_hdmi->hdcp_ops->isr( sde_hdmi->hdcp_data)) DEV_ERR("%s: hdcp_1x_isr failed\n", __func__); } } /* Process CEC: */ _sde_hdmi_cec_irq(sde_hdmi); Loading Loading @@ -1203,84 +1328,8 @@ void sde_hdmi_set_mode(struct hdmi *hdmi, bool power_on) power_on ? "Enable" : "Disable", ctrl); } int sde_hdmi_ddc_read(struct hdmi *hdmi, u16 addr, u8 offset, u8 *data, u16 data_len) { int rc; int retry = 5; struct i2c_msg msgs[] = { { .addr = addr >> 1, .flags = 0, .len = 1, .buf = &offset, }, { .addr = addr >> 1, .flags = I2C_M_RD, .len = data_len, .buf = data, } }; SDE_HDMI_DEBUG("Start DDC read"); retry: rc = i2c_transfer(hdmi->i2c, msgs, 2); retry--; if (rc == 2) rc = 0; else if (retry > 0) goto retry; else rc = -EIO; SDE_HDMI_DEBUG("End DDC read %d", rc); return rc; } #define DDC_WRITE_MAX_BYTE_NUM 32 int sde_hdmi_ddc_write(struct hdmi *hdmi, u16 addr, u8 offset, u8 *data, u16 data_len) { int rc; int retry = 10; u8 buf[DDC_WRITE_MAX_BYTE_NUM]; struct i2c_msg msgs[] = { { .addr = addr >> 1, .flags = 0, .len = 1, } }; SDE_HDMI_DEBUG("Start DDC write"); if (data_len > (DDC_WRITE_MAX_BYTE_NUM - 1)) { SDE_ERROR("%s: write size too big\n", __func__); return -ERANGE; } buf[0] = offset; memcpy(&buf[1], data, data_len); msgs[0].buf = buf; msgs[0].len = data_len + 1; retry: rc = i2c_transfer(hdmi->i2c, msgs, 1); retry--; if (rc == 1) rc = 0; else if (retry > 0) goto retry; else rc = -EIO; SDE_HDMI_DEBUG("End DDC write %d", rc); return rc; } int sde_hdmi_scdc_read(struct hdmi *hdmi, u32 data_type, u32 *val) { int rc = 0; Loading Loading @@ -1337,7 +1386,8 @@ int sde_hdmi_scdc_read(struct hdmi *hdmi, u32 data_type, u32 *val) break; } rc = sde_hdmi_ddc_read(hdmi, dev_addr, offset, data_buf, data_len); rc = hdmi_ddc_read(hdmi, dev_addr, offset, data_buf, data_len, true); if (rc) { SDE_ERROR("DDC Read failed for %d\n", data_type); return rc; Loading Loading @@ -1409,8 +1459,8 @@ int sde_hdmi_scdc_write(struct hdmi *hdmi, u32 data_type, u32 val) dev_addr = 0xA8; data_len = 1; offset = HDMI_SCDC_TMDS_CONFIG; rc = sde_hdmi_ddc_read(hdmi, dev_addr, offset, &read_val, data_len); rc = hdmi_ddc_read(hdmi, dev_addr, offset, &read_val, data_len, true); if (rc) { SDE_ERROR("scdc read failed\n"); return rc; Loading @@ -1434,7 +1484,8 @@ int sde_hdmi_scdc_write(struct hdmi *hdmi, u32 data_type, u32 val) return -EINVAL; } rc = sde_hdmi_ddc_write(hdmi, dev_addr, offset, data_buf, data_len); rc = hdmi_ddc_write(hdmi, dev_addr, offset, data_buf, data_len, true); if (rc) { SDE_ERROR("DDC Read failed for %d\n", data_type); return rc; Loading Loading @@ -1631,6 +1682,50 @@ static int sde_hdmi_tx_check_capability(struct sde_hdmi *sde_hdmi) return ret; } /* hdmi_tx_check_capability */ static int _sde_hdmi_init_hdcp(struct sde_hdmi *hdmi_ctrl) { struct sde_hdcp_init_data hdcp_init_data; void *hdcp_data; int rc = 0; struct hdmi *hdmi; if (!hdmi_ctrl) { SDE_ERROR("sde_hdmi is NULL\n"); return -EINVAL; } hdmi = hdmi_ctrl->ctrl.ctrl; hdcp_init_data.phy_addr = hdmi->mmio_phy_addr; hdcp_init_data.core_io = &hdmi_ctrl->io[HDMI_TX_CORE_IO]; hdcp_init_data.qfprom_io = &hdmi_ctrl->io[HDMI_TX_QFPROM_IO]; hdcp_init_data.hdcp_io = &hdmi_ctrl->io[HDMI_TX_HDCP_IO]; hdcp_init_data.mutex = &hdmi_ctrl->hdcp_mutex; hdcp_init_data.workq = hdmi->workq; hdcp_init_data.notify_status = sde_hdmi_tx_hdcp_cb; hdcp_init_data.cb_data = (void *)hdmi_ctrl; hdcp_init_data.hdmi_tx_ver = hdmi_ctrl->hdmi_tx_major_version; hdcp_init_data.sec_access = true; hdcp_init_data.client_id = HDCP_CLIENT_HDMI; hdcp_init_data.ddc_ctrl = &hdmi_ctrl->ddc_ctrl; if (hdmi_ctrl->hdcp14_present) { hdcp_data = sde_hdcp_1x_init(&hdcp_init_data); if (IS_ERR_OR_NULL(hdcp_data)) { DEV_ERR("%s: hdcp 1.4 init failed\n", __func__); rc = -EINVAL; kfree(hdcp_data); goto end; } else { hdmi_ctrl->hdcp_feature_data[SDE_HDCP_1x] = hdcp_data; SDE_HDMI_DEBUG("%s: HDCP 1.4 initialized\n", __func__); } } end: return rc; } int sde_hdmi_connector_post_init(struct drm_connector *connector, void *info, void *display) Loading Loading @@ -1664,7 +1759,36 @@ int sde_hdmi_connector_post_init(struct drm_connector *connector, SDE_ERROR("failed to enable HPD: %d\n", rc); _sde_hdmi_get_tx_version(sde_hdmi); sde_hdmi_tx_check_capability(sde_hdmi); _sde_hdmi_init_hdcp(sde_hdmi); return rc; } int sde_hdmi_start_hdcp(struct drm_connector *connector) { int rc; struct sde_connector *c_conn = to_sde_connector(connector); struct sde_hdmi *display = (struct sde_hdmi *)c_conn->display; struct hdmi *hdmi = display->ctrl.ctrl; if (!hdmi) { SDE_ERROR("%s: invalid input\n", __func__); return -EINVAL; } if (!sde_hdmi_tx_is_hdcp_enabled(display)) return 0; if (sde_hdmi_tx_is_encryption_set(display)) sde_hdmi_config_avmute(hdmi, true); rc = display->hdcp_ops->authenticate(display->hdcp_data); if (rc) SDE_ERROR("%s: hdcp auth failed. rc=%d\n", __func__, rc); return rc; } Loading Loading @@ -1781,6 +1905,9 @@ int sde_hdmi_dev_deinit(struct sde_hdmi *display) SDE_ERROR("Invalid params\n"); return -EINVAL; } if (display->hdcp_feature_data[SDE_HDCP_1x]) sde_hdcp_1x_deinit(display->hdcp_feature_data[SDE_HDCP_1x]); return 0; } Loading Loading @@ -1864,7 +1991,11 @@ static int sde_hdmi_bind(struct device *dev, struct device *master, void *data) display->drm_dev = drm; _sde_hdmi_map_regs(display, priv->hdmi); _sde_hdmi_init_ddc(display, priv->hdmi); INIT_DELAYED_WORK(&display->hdcp_cb_work, sde_hdmi_tx_hdcp_cb_work); mutex_init(&display->hdcp_mutex); mutex_unlock(&display->display_lock); return rc; Loading
drivers/gpu/drm/msm/hdmi-staging/sde_hdmi.h +59 −27 Original line number Diff line number Diff line Loading @@ -20,6 +20,7 @@ #include <linux/debugfs.h> #include <linux/of_device.h> #include <linux/msm_ext_display.h> #include <linux/hdcp_qseecom.h> #include <drm/drmP.h> #include <drm/drm_crtc.h> Loading @@ -29,6 +30,8 @@ #include "sde_connector.h" #include "msm_drv.h" #include "sde_edid_parser.h" #include "sde_hdmi_util.h" #include "sde_hdcp.h" #ifdef HDMI_DEBUG_ENABLE #define SDE_HDMI_DEBUG(fmt, args...) SDE_ERROR(fmt, ##args) Loading Loading @@ -82,6 +85,11 @@ enum hdmi_tx_io_type { HDMI_TX_MAX_IO }; enum hdmi_tx_feature_type { SDE_HDCP_1x, SDE_HDCP_2P2 }; /** * struct sde_hdmi - hdmi display information * @pdev: Pointer to platform device. Loading Loading @@ -112,7 +120,7 @@ struct sde_hdmi { const char *display_type; struct list_head list; struct mutex display_lock; struct mutex hdcp_mutex; struct sde_hdmi_ctrl ctrl; struct platform_device *ext_pdev; Loading @@ -130,6 +138,18 @@ struct sde_hdmi { u32 max_pclk_khz; bool hdcp1_use_sw_keys; u32 hdcp14_present; u32 hdcp22_present; u8 hdcp_status; u32 enc_lvl; bool auth_state; /*hold final data *based on hdcp support */ void *hdcp_data; /*hold hdcp init data*/ void *hdcp_feature_data[2]; struct sde_hdcp_ops *hdcp_ops; struct sde_hdmi_tx_ddc_ctrl ddc_ctrl; struct work_struct hpd_work; bool codec_ready; bool client_notify_pending; Loading @@ -137,6 +157,7 @@ struct sde_hdmi { struct irq_domain *irq_domain; struct cec_notifier *notifier; struct delayed_work hdcp_cb_work; struct dss_io_data io[HDMI_TX_MAX_IO]; /* DEBUG FS */ struct dentry *root; Loading Loading @@ -337,32 +358,6 @@ struct drm_bridge *sde_hdmi_bridge_init(struct hdmi *hdmi); */ void sde_hdmi_set_mode(struct hdmi *hdmi, bool power_on); /** * sde_hdmi_ddc_read() - common hdmi ddc read API. * @hdmi: Handle to the hdmi. * @addr: Command address. * @offset: Command offset. * @data: Data buffer for read back. * @data_len: Data buffer length. * * Return: error code. */ int sde_hdmi_ddc_read(struct hdmi *hdmi, u16 addr, u8 offset, u8 *data, u16 data_len); /** * sde_hdmi_ddc_write() - common hdmi ddc write API. * @hdmi: Handle to the hdmi. * @addr: Command address. * @offset: Command offset. * @data: Data buffer for write. * @data_len: Data buffer length. * * Return: error code. */ int sde_hdmi_ddc_write(struct hdmi *hdmi, u16 addr, u8 offset, u8 *data, u16 data_len); /** * sde_hdmi_scdc_read() - hdmi 2.0 ddc read API. * @hdmi: Handle to the hdmi. Loading Loading @@ -429,6 +424,13 @@ void sde_hdmi_notify_clients(struct sde_hdmi *display, bool connected); void sde_hdmi_ack_state(struct drm_connector *connector, enum drm_connector_status status); bool sde_hdmi_tx_is_hdcp_enabled(struct sde_hdmi *hdmi_ctrl); bool sde_hdmi_tx_is_encryption_set(struct sde_hdmi *hdmi_ctrl); bool sde_hdmi_tx_is_stream_shareable(struct sde_hdmi *hdmi_ctrl); bool sde_hdmi_tx_is_panel_on(struct sde_hdmi *hdmi_ctrl); int sde_hdmi_start_hdcp(struct drm_connector *connector); void sde_hdmi_hdcp_off(struct sde_hdmi *hdmi_ctrl); #else /*#ifdef CONFIG_DRM_SDE_HDMI*/ static inline u32 sde_hdmi_get_num_of_displays(void) Loading Loading @@ -487,12 +489,42 @@ static inline int sde_hdmi_dev_deinit(struct sde_hdmi *display) return 0; } bool hdmi_tx_is_hdcp_enabled(struct sde_hdmi *hdmi_ctrl) { return false; } bool sde_hdmi_tx_is_encryption_set(struct sde_hdmi *hdmi_ctrl) { return false; } bool sde_hdmi_tx_is_stream_shareable(struct sde_hdmi *hdmi_ctrl) { return false; } bool sde_hdmi_tx_is_panel_on(struct sde_hdmi *hdmi_ctrl) { return false; } static inline int sde_hdmi_drm_init(struct sde_hdmi *display, struct drm_encoder *enc) { return 0; } int sde_hdmi_start_hdcp(struct drm_connector *connector) { return 0; } void sde_hdmi_hdcp_off(struct sde_hdmi *hdmi_ctrl) { } static inline int sde_hdmi_drm_deinit(struct sde_hdmi *display) { return 0; Loading
drivers/gpu/drm/msm/hdmi-staging/sde_hdmi_audio.c +0 −34 Original line number Diff line number Diff line Loading @@ -355,37 +355,3 @@ void sde_hdmi_audio_off(struct hdmi *hdmi) SDE_DEBUG("HDMI Audio: Disabled\n"); } int sde_hdmi_config_avmute(struct hdmi *hdmi, bool set) { u32 av_mute_status; bool av_pkt_en = false; if (!hdmi) { SDE_ERROR("invalid HDMI Ctrl\n"); return -ENODEV; } av_mute_status = hdmi_read(hdmi, HDMI_GC); if (set) { if (!(av_mute_status & BIT(0))) { hdmi_write(hdmi, HDMI_GC, av_mute_status | BIT(0)); av_pkt_en = true; } } else { if (av_mute_status & BIT(0)) { hdmi_write(hdmi, HDMI_GC, av_mute_status & ~BIT(0)); av_pkt_en = true; } } /* Enable AV Mute tranmission here */ if (av_pkt_en) hdmi_write(hdmi, HDMI_VBI_PKT_CTRL, hdmi_read(hdmi, HDMI_VBI_PKT_CTRL) | (BIT(4) & BIT(5))); SDE_DEBUG("AVMUTE %s\n", set ? "set" : "cleared"); return 0; }
drivers/gpu/drm/msm/hdmi-staging/sde_hdmi_bridge.c +39 −2 Original line number Diff line number Diff line Loading @@ -396,8 +396,45 @@ static void _sde_hdmi_bridge_pre_enable(struct drm_bridge *bridge) mutex_unlock(&display->display_lock); } static void sde_hdmi_update_hdcp_info(struct drm_connector *connector) { void *fd = NULL; struct sde_hdcp_ops *ops = NULL; struct sde_connector *c_conn = to_sde_connector(connector); struct sde_hdmi *display = (struct sde_hdmi *)c_conn->display; if (!display) { DEV_ERR("%s: invalid input\n", __func__); return; } if (!display->hdcp22_present) { if (display->hdcp1_use_sw_keys) { display->hdcp14_present = hdcp1_check_if_supported_load_app(); } if (display->hdcp14_present) { fd = display->hdcp_feature_data[SDE_HDCP_1x]; if (fd) ops = sde_hdcp_1x_start(fd); } } /* update internal data about hdcp */ display->hdcp_data = fd; display->hdcp_ops = ops; } static void _sde_hdmi_bridge_enable(struct drm_bridge *bridge) { struct sde_hdmi_bridge *sde_hdmi_bridge = to_hdmi_bridge(bridge); struct hdmi *hdmi = sde_hdmi_bridge->hdmi; /* need to update hdcp info here to ensure right HDCP support*/ sde_hdmi_update_hdcp_info(hdmi->connector); /* start HDCP authentication */ sde_hdmi_start_hdcp(hdmi->connector); } static void _sde_hdmi_bridge_disable(struct drm_bridge *bridge) Loading @@ -414,8 +451,8 @@ static void _sde_hdmi_bridge_post_disable(struct drm_bridge *bridge) sde_hdmi_notify_clients(display, display->connected); if (hdmi->hdcp_ctrl && hdmi->is_hdcp_supported) hdmi_hdcp_ctrl_off(hdmi->hdcp_ctrl); if (sde_hdmi_tx_is_hdcp_enabled(display)) sde_hdmi_hdcp_off(display); sde_hdmi_audio_off(hdmi); Loading