diff options
Diffstat (limited to 'drivers/gpu/drm/bridge/analogix/anx7625.c')
-rw-r--r-- | drivers/gpu/drm/bridge/analogix/anx7625.c | 177 |
1 files changed, 75 insertions, 102 deletions
diff --git a/drivers/gpu/drm/bridge/analogix/anx7625.c b/drivers/gpu/drm/bridge/analogix/anx7625.c index 29d91493b101..4be34d5c7a3b 100644 --- a/drivers/gpu/drm/bridge/analogix/anx7625.c +++ b/drivers/gpu/drm/bridge/analogix/anx7625.c @@ -464,9 +464,11 @@ static int anx7625_odfc_config(struct anx7625_data *ctx, */ static int anx7625_set_k_value(struct anx7625_data *ctx) { - struct edid *edid = (struct edid *)ctx->slimport_edid_p.edid_raw_data; + struct drm_edid_product_id id; - if (edid->mfg_id[0] == IVO_MID0 && edid->mfg_id[1] == IVO_MID1) + drm_edid_get_product_id(ctx->cached_drm_edid, &id); + + if (be16_to_cpu(id.manufacturer_name) == IVO_MID) return anx7625_reg_write(ctx, ctx->i2c.rx_p1_client, MIPI_DIGITAL_ADJ_1, 0x3B); @@ -1526,7 +1528,8 @@ static int anx7625_wait_hpd_asserted(struct drm_dp_aux *aux, static void anx7625_remove_edid(struct anx7625_data *ctx) { - ctx->slimport_edid_p.edid_block_num = -1; + drm_edid_free(ctx->cached_drm_edid); + ctx->cached_drm_edid = NULL; } static void anx7625_dp_adjust_swing(struct anx7625_data *ctx) @@ -1644,25 +1647,15 @@ static int anx7625_get_swing_setting(struct device *dev, { int num_regs; - if (of_get_property(dev->of_node, - "analogix,lane0-swing", &num_regs)) { - if (num_regs > DP_TX_SWING_REG_CNT) - num_regs = DP_TX_SWING_REG_CNT; - + num_regs = of_property_read_variable_u8_array(dev->of_node, "analogix,lane0-swing", + pdata->lane0_reg_data, 1, DP_TX_SWING_REG_CNT); + if (num_regs > 0) pdata->dp_lane0_swing_reg_cnt = num_regs; - of_property_read_u8_array(dev->of_node, "analogix,lane0-swing", - pdata->lane0_reg_data, num_regs); - } - - if (of_get_property(dev->of_node, - "analogix,lane1-swing", &num_regs)) { - if (num_regs > DP_TX_SWING_REG_CNT) - num_regs = DP_TX_SWING_REG_CNT; + num_regs = of_property_read_variable_u8_array(dev->of_node, "analogix,lane1-swing", + pdata->lane1_reg_data, 1, DP_TX_SWING_REG_CNT); + if (num_regs > 0) pdata->dp_lane1_swing_reg_cnt = num_regs; - of_property_read_u8_array(dev->of_node, "analogix,lane1-swing", - pdata->lane1_reg_data, num_regs); - } return 0; } @@ -1784,40 +1777,35 @@ static ssize_t anx7625_aux_transfer(struct drm_dp_aux *aux, return ret; } -static struct edid *anx7625_get_edid(struct anx7625_data *ctx) +static const struct drm_edid *anx7625_edid_read(struct anx7625_data *ctx) { struct device *dev = ctx->dev; - struct s_edid_data *p_edid = &ctx->slimport_edid_p; + u8 *edid_buf; int edid_num; - u8 *edid; - edid = kmalloc(FOUR_BLOCK_SIZE, GFP_KERNEL); - if (!edid) { - DRM_DEV_ERROR(dev, "Fail to allocate buffer\n"); - return NULL; - } + if (ctx->cached_drm_edid) + goto out; - if (ctx->slimport_edid_p.edid_block_num > 0) { - memcpy(edid, ctx->slimport_edid_p.edid_raw_data, - FOUR_BLOCK_SIZE); - return (struct edid *)edid; - } + edid_buf = kmalloc(FOUR_BLOCK_SIZE, GFP_KERNEL); + if (!edid_buf) + return NULL; pm_runtime_get_sync(dev); _anx7625_hpd_polling(ctx, 5000 * 100); - edid_num = sp_tx_edid_read(ctx, p_edid->edid_raw_data); + edid_num = sp_tx_edid_read(ctx, edid_buf); pm_runtime_put_sync(dev); if (edid_num < 1) { DRM_DEV_ERROR(dev, "Fail to read EDID: %d\n", edid_num); - kfree(edid); + kfree(edid_buf); return NULL; } - p_edid->edid_block_num = edid_num; + ctx->cached_drm_edid = drm_edid_alloc(edid_buf, FOUR_BLOCK_SIZE); + kfree(edid_buf); - memcpy(edid, ctx->slimport_edid_p.edid_raw_data, FOUR_BLOCK_SIZE); - return (struct edid *)edid; +out: + return drm_edid_dup(ctx->cached_drm_edid); } static enum drm_connector_status anx7625_sink_detect(struct anx7625_data *ctx) @@ -1964,7 +1952,8 @@ static void anx7625_audio_shutdown(struct device *dev, void *data) } static int anx7625_hdmi_i2s_get_dai_id(struct snd_soc_component *component, - struct device_node *endpoint) + struct device_node *endpoint, + void *data) { struct of_endpoint of_ep; int ret; @@ -2014,8 +2003,10 @@ static int anx7625_audio_get_eld(struct device *dev, void *data, memset(buf, 0, len); } else { dev_dbg(dev, "audio copy eld\n"); + mutex_lock(&ctx->connector->eld_mutex); memcpy(buf, ctx->connector->eld, min(sizeof(ctx->connector->eld), len)); + mutex_unlock(&ctx->connector->eld_mutex); } return 0; @@ -2076,10 +2067,8 @@ static int anx7625_setup_dsi_device(struct anx7625_data *ctx) }; host = of_find_mipi_dsi_host_by_node(ctx->pdata.mipi_host_node); - if (!host) { - DRM_DEV_ERROR(dev, "fail to find dsi host.\n"); - return -EPROBE_DEFER; - } + if (!host) + return dev_err_probe(dev, -EPROBE_DEFER, "fail to find dsi host.\n"); dsi = devm_mipi_dsi_device_register_full(dev, host, &info); if (IS_ERR(dsi)) { @@ -2151,49 +2140,6 @@ static void hdcp_check_work_func(struct work_struct *work) drm_modeset_unlock(&drm_dev->mode_config.connection_mutex); } -static int anx7625_connector_atomic_check(struct anx7625_data *ctx, - struct drm_connector_state *state) -{ - struct device *dev = ctx->dev; - int cp; - - dev_dbg(dev, "hdcp state check\n"); - cp = state->content_protection; - - if (cp == ctx->hdcp_cp) - return 0; - - if (cp == DRM_MODE_CONTENT_PROTECTION_DESIRED) { - if (ctx->dp_en) { - dev_dbg(dev, "enable HDCP\n"); - anx7625_hdcp_enable(ctx); - - queue_delayed_work(ctx->hdcp_workqueue, - &ctx->hdcp_work, - msecs_to_jiffies(2000)); - } - } - - if (cp == DRM_MODE_CONTENT_PROTECTION_UNDESIRED) { - if (ctx->hdcp_cp != DRM_MODE_CONTENT_PROTECTION_ENABLED) { - dev_err(dev, "current CP is not ENABLED\n"); - return -EINVAL; - } - anx7625_hdcp_disable(ctx); - ctx->hdcp_cp = DRM_MODE_CONTENT_PROTECTION_UNDESIRED; - drm_hdcp_update_content_protection(ctx->connector, - ctx->hdcp_cp); - dev_dbg(dev, "update CP to UNDESIRE\n"); - } - - if (cp == DRM_MODE_CONTENT_PROTECTION_ENABLED) { - dev_err(dev, "Userspace illegal set to PROTECTION ENABLE\n"); - return -EINVAL; - } - - return 0; -} - static int anx7625_bridge_attach(struct drm_bridge *bridge, enum drm_bridge_attach_flags flags) { @@ -2205,11 +2151,6 @@ static int anx7625_bridge_attach(struct drm_bridge *bridge, if (!(flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR)) return -EINVAL; - if (!bridge->encoder) { - DRM_DEV_ERROR(dev, "Parent encoder object not found"); - return -ENODEV; - } - ctx->aux.drm_dev = bridge->dev; err = drm_dp_aux_register(&ctx->aux); if (err) { @@ -2435,7 +2376,7 @@ static int anx7625_bridge_atomic_check(struct drm_bridge *bridge, anx7625_bridge_mode_fixup(bridge, &crtc_state->mode, &crtc_state->adjusted_mode); - return anx7625_connector_atomic_check(ctx, conn_state); + return 0; } static void anx7625_bridge_atomic_enable(struct drm_bridge *bridge, @@ -2444,14 +2385,10 @@ static void anx7625_bridge_atomic_enable(struct drm_bridge *bridge, struct anx7625_data *ctx = bridge_to_anx7625(bridge); struct device *dev = ctx->dev; struct drm_connector *connector; + struct drm_connector_state *conn_state; dev_dbg(dev, "drm atomic enable\n"); - if (!bridge->encoder) { - dev_err(dev, "Parent encoder object not found"); - return; - } - connector = drm_atomic_get_new_connector_for_encoder(state->base.state, bridge->encoder); if (!connector) @@ -2463,6 +2400,22 @@ static void anx7625_bridge_atomic_enable(struct drm_bridge *bridge, _anx7625_hpd_polling(ctx, 5000 * 100); anx7625_dp_start(ctx); + + conn_state = drm_atomic_get_new_connector_state(state->base.state, connector); + + if (WARN_ON(!conn_state)) + return; + + if (conn_state->content_protection == DRM_MODE_CONTENT_PROTECTION_DESIRED) { + if (ctx->dp_en) { + dev_dbg(dev, "enable HDCP\n"); + anx7625_hdcp_enable(ctx); + + queue_delayed_work(ctx->hdcp_workqueue, + &ctx->hdcp_work, + msecs_to_jiffies(2000)); + } + } } static void anx7625_bridge_atomic_disable(struct drm_bridge *bridge, @@ -2473,6 +2426,17 @@ static void anx7625_bridge_atomic_disable(struct drm_bridge *bridge, dev_dbg(dev, "drm atomic disable\n"); + flush_workqueue(ctx->hdcp_workqueue); + + if (ctx->connector && + ctx->hdcp_cp == DRM_MODE_CONTENT_PROTECTION_ENABLED) { + anx7625_hdcp_disable(ctx); + ctx->hdcp_cp = DRM_MODE_CONTENT_PROTECTION_DESIRED; + drm_hdcp_update_content_protection(ctx->connector, + ctx->hdcp_cp); + dev_dbg(dev, "update CP to DESIRE\n"); + } + ctx->connector = NULL; anx7625_dp_stop(ctx); @@ -2481,26 +2445,33 @@ static void anx7625_bridge_atomic_disable(struct drm_bridge *bridge, mutex_unlock(&ctx->aux_lock); } +static void +anx7625_audio_update_connector_status(struct anx7625_data *ctx, + enum drm_connector_status status); + static enum drm_connector_status anx7625_bridge_detect(struct drm_bridge *bridge) { struct anx7625_data *ctx = bridge_to_anx7625(bridge); struct device *dev = ctx->dev; + enum drm_connector_status status; DRM_DEV_DEBUG_DRIVER(dev, "drm bridge detect\n"); - return anx7625_sink_detect(ctx); + status = anx7625_sink_detect(ctx); + anx7625_audio_update_connector_status(ctx, status); + return status; } -static struct edid *anx7625_bridge_get_edid(struct drm_bridge *bridge, - struct drm_connector *connector) +static const struct drm_edid *anx7625_bridge_edid_read(struct drm_bridge *bridge, + struct drm_connector *connector) { struct anx7625_data *ctx = bridge_to_anx7625(bridge); struct device *dev = ctx->dev; DRM_DEV_DEBUG_DRIVER(dev, "drm bridge get edid\n"); - return anx7625_get_edid(ctx); + return anx7625_edid_read(ctx); } static const struct drm_bridge_funcs anx7625_bridge_funcs = { @@ -2515,7 +2486,7 @@ static const struct drm_bridge_funcs anx7625_bridge_funcs = { .atomic_destroy_state = drm_atomic_helper_bridge_destroy_state, .atomic_reset = drm_atomic_helper_bridge_reset, .detect = anx7625_bridge_detect, - .get_edid = anx7625_bridge_get_edid, + .edid_read = anx7625_bridge_edid_read, }; static int anx7625_register_i2c_dummy_clients(struct anx7625_data *ctx, @@ -2568,6 +2539,8 @@ static int __maybe_unused anx7625_runtime_pm_suspend(struct device *dev) mutex_lock(&ctx->lock); anx7625_stop_dp_work(ctx); + if (!ctx->pdata.panel_bridge) + anx7625_remove_edid(ctx); anx7625_power_standby(ctx); mutex_unlock(&ctx->lock); @@ -2810,7 +2783,7 @@ static void anx7625_i2c_remove(struct i2c_client *client) } static const struct i2c_device_id anx7625_id[] = { - {"anx7625", 0}, + { "anx7625" }, {} }; |