diff options
author | Dave Airlie <airlied@redhat.com> | 2020-06-30 14:03:38 +1000 |
---|---|---|
committer | Dave Airlie <airlied@redhat.com> | 2020-06-30 14:04:00 +1000 |
commit | f75020fcb97a54c0d2ade1f4918db82f44d225ad (patch) | |
tree | 072b3166af21b80dcdc7e76e58b32059806951f6 /drivers/gpu/drm/bridge | |
parent | 0a19b068acc47d05212f03e494381926dc0381e2 (diff) | |
parent | 41752663b410c6265e24ff0570350b0b05ecdafe (diff) |
Merge tag 'drm-misc-next-2020-06-26' of git://anongit.freedesktop.org/drm/drm-misc into drm-next
drm-misc-next for v5.9:
Cross-subsystem Changes:
- Improve dma-buf docs.
Core Changes:
- Add NV15, Q410, Q401 yuv formats.
- Add uncompressed AFBC modifier.
- Add DP helepr for reading Ignore MSA from DPCD.
- Add missing panel type for some panels
- Optimize drm/mm hole handling.
- Constify connector to infoframe functions.
- Add debugfs for VRR monitor range.
Driver Changes:
- Assorted small bugfixes in panfrost, malidp, panel/otm8009a.
- Convert tfp410 dt bindings to yaml, and rework time calculations.
- Add support for a few more simple panels.
- Cleanups and optimizations for ast.
- Allow adv7511 and simple-bridge to be used without connector creation.
- Cleanups to dw-hdmi function prototypes.
- Remove enabled bool from tiny/repaper and mipi-dbi, atomic handles it.
- Remove unused header file from dw-mipi-dsi
- Begin removing ttm_bo->offset.
Signed-off-by: Dave Airlie <airlied@redhat.com>
From: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/b1e53620-7937-895c-bfcf-ed208be59c7c@linux.intel.com
Diffstat (limited to 'drivers/gpu/drm/bridge')
-rw-r--r-- | drivers/gpu/drm/bridge/adv7511/adv7511_drv.c | 137 | ||||
-rw-r--r-- | drivers/gpu/drm/bridge/analogix/analogix-anx6345.c | 1 | ||||
-rw-r--r-- | drivers/gpu/drm/bridge/analogix/analogix-anx78xx.c | 1 | ||||
-rw-r--r-- | drivers/gpu/drm/bridge/cdns-dsi.c | 1 | ||||
-rw-r--r-- | drivers/gpu/drm/bridge/chrontel-ch7033.c | 1 | ||||
-rw-r--r-- | drivers/gpu/drm/bridge/nwl-dsi.c | 1 | ||||
-rw-r--r-- | drivers/gpu/drm/bridge/sii9234.c | 1 | ||||
-rw-r--r-- | drivers/gpu/drm/bridge/sil-sii8620.c | 1 | ||||
-rw-r--r-- | drivers/gpu/drm/bridge/simple-bridge.c | 113 | ||||
-rw-r--r-- | drivers/gpu/drm/bridge/synopsys/dw-hdmi.c | 307 | ||||
-rw-r--r-- | drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c | 2 | ||||
-rw-r--r-- | drivers/gpu/drm/bridge/tc358767.c | 1 | ||||
-rw-r--r-- | drivers/gpu/drm/bridge/tc358768.c | 1 | ||||
-rw-r--r-- | drivers/gpu/drm/bridge/thc63lvd1024.c | 1 | ||||
-rw-r--r-- | drivers/gpu/drm/bridge/ti-tfp410.c | 21 |
15 files changed, 359 insertions, 231 deletions
diff --git a/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c b/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c index 87b58c1acff4..f45cdca9cce5 100644 --- a/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c +++ b/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c @@ -443,9 +443,14 @@ static void adv7511_hpd_work(struct work_struct *work) if (adv7511->connector.status != status) { adv7511->connector.status = status; - if (status == connector_status_disconnected) - cec_phys_addr_invalidate(adv7511->cec_adap); - drm_kms_helper_hotplug_event(adv7511->connector.dev); + + if (adv7511->connector.dev) { + if (status == connector_status_disconnected) + cec_phys_addr_invalidate(adv7511->cec_adap); + drm_kms_helper_hotplug_event(adv7511->connector.dev); + } else { + drm_bridge_hpd_notify(&adv7511->bridge, status); + } } } @@ -589,11 +594,10 @@ static int adv7511_get_edid_block(void *data, u8 *buf, unsigned int block, * ADV75xx helpers */ -static int adv7511_get_modes(struct adv7511 *adv7511, - struct drm_connector *connector) +static struct edid *adv7511_get_edid(struct adv7511 *adv7511, + struct drm_connector *connector) { struct edid *edid; - unsigned int count; /* Reading the EDID only works if the device is powered */ if (!adv7511->powered) { @@ -612,15 +616,25 @@ static int adv7511_get_modes(struct adv7511 *adv7511, if (!adv7511->powered) __adv7511_power_off(adv7511); - - drm_connector_update_edid_property(connector, edid); - count = drm_add_edid_modes(connector, edid); - adv7511_set_config_csc(adv7511, connector, adv7511->rgb, drm_detect_hdmi_monitor(edid)); cec_s_phys_addr_from_edid(adv7511->cec_adap, edid); + return edid; +} + +static int adv7511_get_modes(struct adv7511 *adv7511, + struct drm_connector *connector) +{ + struct edid *edid; + unsigned int count; + + edid = adv7511_get_edid(adv7511, connector); + + drm_connector_update_edid_property(connector, edid); + count = drm_add_edid_modes(connector, edid); + kfree(edid); return count; @@ -652,7 +666,8 @@ adv7511_detect(struct adv7511 *adv7511, struct drm_connector *connector) if (status == connector_status_connected && hpd && adv7511->powered) { regcache_mark_dirty(adv7511->regmap); adv7511_power_on(adv7511); - adv7511_get_modes(adv7511, connector); + if (connector) + adv7511_get_modes(adv7511, connector); if (adv7511->status == connector_status_connected) status = connector_status_disconnected; } else { @@ -774,7 +789,10 @@ static void adv7511_mode_set(struct adv7511 *adv7511, adv7511->f_tmds = mode->clock; } -/* Connector funcs */ +/* ----------------------------------------------------------------------------- + * DRM Connector Operations + */ + static struct adv7511 *connector_to_adv7511(struct drm_connector *connector) { return container_of(connector, struct adv7511, connector); @@ -818,7 +836,40 @@ static const struct drm_connector_funcs adv7511_connector_funcs = { .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, }; -/* Bridge funcs */ +static int adv7511_connector_init(struct adv7511 *adv) +{ + struct drm_bridge *bridge = &adv->bridge; + int ret; + + if (!bridge->encoder) { + DRM_ERROR("Parent encoder object not found"); + return -ENODEV; + } + + if (adv->i2c_main->irq) + adv->connector.polled = DRM_CONNECTOR_POLL_HPD; + else + adv->connector.polled = DRM_CONNECTOR_POLL_CONNECT | + DRM_CONNECTOR_POLL_DISCONNECT; + + ret = drm_connector_init(bridge->dev, &adv->connector, + &adv7511_connector_funcs, + DRM_MODE_CONNECTOR_HDMIA); + if (ret < 0) { + DRM_ERROR("Failed to initialize connector with drm\n"); + return ret; + } + drm_connector_helper_add(&adv->connector, + &adv7511_connector_helper_funcs); + drm_connector_attach_encoder(&adv->connector, bridge->encoder); + + return 0; +} + +/* ----------------------------------------------------------------------------- + * DRM Bridge Operations + */ + static struct adv7511 *bridge_to_adv7511(struct drm_bridge *bridge) { return container_of(bridge, struct adv7511, bridge); @@ -851,34 +902,13 @@ static int adv7511_bridge_attach(struct drm_bridge *bridge, enum drm_bridge_attach_flags flags) { struct adv7511 *adv = bridge_to_adv7511(bridge); - int ret; - - if (flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR) { - DRM_ERROR("Fix bridge driver to make connector optional!"); - return -EINVAL; - } - - if (!bridge->encoder) { - DRM_ERROR("Parent encoder object not found"); - return -ENODEV; - } - - if (adv->i2c_main->irq) - adv->connector.polled = DRM_CONNECTOR_POLL_HPD; - else - adv->connector.polled = DRM_CONNECTOR_POLL_CONNECT | - DRM_CONNECTOR_POLL_DISCONNECT; + int ret = 0; - ret = drm_connector_init(bridge->dev, &adv->connector, - &adv7511_connector_funcs, - DRM_MODE_CONNECTOR_HDMIA); - if (ret) { - DRM_ERROR("Failed to initialize connector with drm\n"); - return ret; + if (!(flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR)) { + ret = adv7511_connector_init(adv); + if (ret < 0) + return ret; } - drm_connector_helper_add(&adv->connector, - &adv7511_connector_helper_funcs); - drm_connector_attach_encoder(&adv->connector, bridge->encoder); if (adv->type == ADV7533 || adv->type == ADV7535) ret = adv7533_attach_dsi(adv); @@ -890,11 +920,38 @@ static int adv7511_bridge_attach(struct drm_bridge *bridge, return ret; } +static enum drm_connector_status adv7511_bridge_detect(struct drm_bridge *bridge) +{ + struct adv7511 *adv = bridge_to_adv7511(bridge); + + return adv7511_detect(adv, NULL); +} + +static struct edid *adv7511_bridge_get_edid(struct drm_bridge *bridge, + struct drm_connector *connector) +{ + struct adv7511 *adv = bridge_to_adv7511(bridge); + + return adv7511_get_edid(adv, connector); +} + +static void adv7511_bridge_hpd_notify(struct drm_bridge *bridge, + enum drm_connector_status status) +{ + struct adv7511 *adv = bridge_to_adv7511(bridge); + + if (status == connector_status_disconnected) + cec_phys_addr_invalidate(adv->cec_adap); +} + static const struct drm_bridge_funcs adv7511_bridge_funcs = { .enable = adv7511_bridge_enable, .disable = adv7511_bridge_disable, .mode_set = adv7511_bridge_mode_set, .attach = adv7511_bridge_attach, + .detect = adv7511_bridge_detect, + .get_edid = adv7511_bridge_get_edid, + .hpd_notify = adv7511_bridge_hpd_notify, }; /* ----------------------------------------------------------------------------- @@ -1223,6 +1280,8 @@ static int adv7511_probe(struct i2c_client *i2c, const struct i2c_device_id *id) goto err_unregister_cec; adv7511->bridge.funcs = &adv7511_bridge_funcs; + adv7511->bridge.ops = DRM_BRIDGE_OP_DETECT | DRM_BRIDGE_OP_EDID + | DRM_BRIDGE_OP_HPD; adv7511->bridge.of_node = dev->of_node; drm_bridge_add(&adv7511->bridge); diff --git a/drivers/gpu/drm/bridge/analogix/analogix-anx6345.c b/drivers/gpu/drm/bridge/analogix/analogix-anx6345.c index 9af39ec958db..f082b4ed4878 100644 --- a/drivers/gpu/drm/bridge/analogix/analogix-anx6345.c +++ b/drivers/gpu/drm/bridge/analogix/analogix-anx6345.c @@ -588,6 +588,7 @@ static int anx6345_bridge_attach(struct drm_bridge *bridge, static enum drm_mode_status anx6345_bridge_mode_valid(struct drm_bridge *bridge, + const struct drm_display_info *info, const struct drm_display_mode *mode) { if (mode->flags & DRM_MODE_FLAG_INTERLACE) diff --git a/drivers/gpu/drm/bridge/analogix/analogix-anx78xx.c b/drivers/gpu/drm/bridge/analogix/analogix-anx78xx.c index 0d5a5ad0c9ee..81debd02c169 100644 --- a/drivers/gpu/drm/bridge/analogix/analogix-anx78xx.c +++ b/drivers/gpu/drm/bridge/analogix/analogix-anx78xx.c @@ -944,6 +944,7 @@ static int anx78xx_bridge_attach(struct drm_bridge *bridge, static enum drm_mode_status anx78xx_bridge_mode_valid(struct drm_bridge *bridge, + const struct drm_display_info *info, const struct drm_display_mode *mode) { if (mode->flags & DRM_MODE_FLAG_INTERLACE) diff --git a/drivers/gpu/drm/bridge/cdns-dsi.c b/drivers/gpu/drm/bridge/cdns-dsi.c index 69c3892caee5..76373e31df92 100644 --- a/drivers/gpu/drm/bridge/cdns-dsi.c +++ b/drivers/gpu/drm/bridge/cdns-dsi.c @@ -663,6 +663,7 @@ static int cdns_dsi_bridge_attach(struct drm_bridge *bridge, static enum drm_mode_status cdns_dsi_bridge_mode_valid(struct drm_bridge *bridge, + const struct drm_display_info *info, const struct drm_display_mode *mode) { struct cdns_dsi_input *input = bridge_to_cdns_dsi_input(bridge); diff --git a/drivers/gpu/drm/bridge/chrontel-ch7033.c b/drivers/gpu/drm/bridge/chrontel-ch7033.c index f8675d82974b..486f405c2e16 100644 --- a/drivers/gpu/drm/bridge/chrontel-ch7033.c +++ b/drivers/gpu/drm/bridge/chrontel-ch7033.c @@ -317,6 +317,7 @@ static void ch7033_bridge_detach(struct drm_bridge *bridge) } static enum drm_mode_status ch7033_bridge_mode_valid(struct drm_bridge *bridge, + const struct drm_display_info *info, const struct drm_display_mode *mode) { if (mode->clock > 165000) diff --git a/drivers/gpu/drm/bridge/nwl-dsi.c b/drivers/gpu/drm/bridge/nwl-dsi.c index b14d725bf609..77a79af70914 100644 --- a/drivers/gpu/drm/bridge/nwl-dsi.c +++ b/drivers/gpu/drm/bridge/nwl-dsi.c @@ -818,6 +818,7 @@ static bool nwl_dsi_bridge_mode_fixup(struct drm_bridge *bridge, static enum drm_mode_status nwl_dsi_bridge_mode_valid(struct drm_bridge *bridge, + const struct drm_display_info *info, const struct drm_display_mode *mode) { struct nwl_dsi *dsi = bridge_to_dsi(bridge); diff --git a/drivers/gpu/drm/bridge/sii9234.c b/drivers/gpu/drm/bridge/sii9234.c index b1258f0ed205..15c98a7bd81c 100644 --- a/drivers/gpu/drm/bridge/sii9234.c +++ b/drivers/gpu/drm/bridge/sii9234.c @@ -873,6 +873,7 @@ static inline struct sii9234 *bridge_to_sii9234(struct drm_bridge *bridge) } static enum drm_mode_status sii9234_mode_valid(struct drm_bridge *bridge, + const struct drm_display_info *info, const struct drm_display_mode *mode) { if (mode->clock > MHL1_MAX_CLK) diff --git a/drivers/gpu/drm/bridge/sil-sii8620.c b/drivers/gpu/drm/bridge/sil-sii8620.c index 92acd336aa89..7c0c93c7e61f 100644 --- a/drivers/gpu/drm/bridge/sil-sii8620.c +++ b/drivers/gpu/drm/bridge/sil-sii8620.c @@ -2244,6 +2244,7 @@ static int sii8620_is_packing_required(struct sii8620 *ctx, } static enum drm_mode_status sii8620_mode_valid(struct drm_bridge *bridge, + const struct drm_display_info *info, const struct drm_display_mode *mode) { struct sii8620 *ctx = bridge_to_sii8620(bridge); diff --git a/drivers/gpu/drm/bridge/simple-bridge.c b/drivers/gpu/drm/bridge/simple-bridge.c index a2dca7a3ef03..d974282c12b2 100644 --- a/drivers/gpu/drm/bridge/simple-bridge.c +++ b/drivers/gpu/drm/bridge/simple-bridge.c @@ -29,7 +29,7 @@ struct simple_bridge { const struct simple_bridge_info *info; - struct i2c_adapter *ddc; + struct drm_bridge *next_bridge; struct regulator *vdd; struct gpio_desc *enable; }; @@ -52,29 +52,28 @@ static int simple_bridge_get_modes(struct drm_connector *connector) struct edid *edid; int ret; - if (!sbridge->ddc) - goto fallback; + if (sbridge->next_bridge->ops & DRM_BRIDGE_OP_EDID) { + edid = drm_bridge_get_edid(sbridge->next_bridge, connector); + if (!edid) + DRM_INFO("EDID read failed. Fallback to standard modes\n"); + } else { + edid = NULL; + } - edid = drm_get_edid(connector, sbridge->ddc); if (!edid) { - DRM_INFO("EDID readout failed, falling back to standard modes\n"); - goto fallback; + /* + * In case we cannot retrieve the EDIDs (missing or broken DDC + * bus from the next bridge), fallback on the XGA standards and + * prefer a mode pretty much anyone can handle. + */ + ret = drm_add_modes_noedid(connector, 1920, 1200); + drm_set_preferred_mode(connector, 1024, 768); + return ret; } drm_connector_update_edid_property(connector, edid); ret = drm_add_edid_modes(connector, edid); kfree(edid); - return ret; - -fallback: - /* - * In case we cannot retrieve the EDIDs (broken or missing i2c - * bus), fallback on the XGA standards - */ - ret = drm_add_modes_noedid(connector, 1920, 1200); - - /* And prefer a mode pretty much anyone can handle */ - drm_set_preferred_mode(connector, 1024, 768); return ret; } @@ -88,16 +87,7 @@ simple_bridge_connector_detect(struct drm_connector *connector, bool force) { struct simple_bridge *sbridge = drm_connector_to_simple_bridge(connector); - /* - * Even if we have an I2C bus, we can't assume that the cable - * is disconnected if drm_probe_ddc fails. Some cables don't - * wire the DDC pins, or the I2C bus might not be working at - * all. - */ - if (sbridge->ddc && drm_probe_ddc(sbridge->ddc)) - return connector_status_connected; - - return connector_status_unknown; + return drm_bridge_detect(sbridge->next_bridge); } static const struct drm_connector_funcs simple_bridge_con_funcs = { @@ -115,10 +105,13 @@ static int simple_bridge_attach(struct drm_bridge *bridge, struct simple_bridge *sbridge = drm_bridge_to_simple_bridge(bridge); int ret; - if (flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR) { - DRM_ERROR("Fix bridge driver to make connector optional!"); - return -EINVAL; - } + ret = drm_bridge_attach(bridge->encoder, sbridge->next_bridge, bridge, + DRM_BRIDGE_ATTACH_NO_CONNECTOR); + if (ret < 0) + return ret; + + if (flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR) + return 0; if (!bridge->encoder) { DRM_ERROR("Missing encoder\n"); @@ -130,14 +123,13 @@ static int simple_bridge_attach(struct drm_bridge *bridge, ret = drm_connector_init_with_ddc(bridge->dev, &sbridge->connector, &simple_bridge_con_funcs, sbridge->info->connector_type, - sbridge->ddc); + sbridge->next_bridge->ddc); if (ret) { DRM_ERROR("Failed to initialize connector\n"); return ret; } - drm_connector_attach_encoder(&sbridge->connector, - bridge->encoder); + drm_connector_attach_encoder(&sbridge->connector, bridge->encoder); return 0; } @@ -172,31 +164,10 @@ static const struct drm_bridge_funcs simple_bridge_bridge_funcs = { .disable = simple_bridge_disable, }; -static struct i2c_adapter *simple_bridge_retrieve_ddc(struct device *dev) -{ - struct device_node *phandle, *remote; - struct i2c_adapter *ddc; - - remote = of_graph_get_remote_node(dev->of_node, 1, -1); - if (!remote) - return ERR_PTR(-EINVAL); - - phandle = of_parse_phandle(remote, "ddc-i2c-bus", 0); - of_node_put(remote); - if (!phandle) - return ERR_PTR(-ENODEV); - - ddc = of_get_i2c_adapter_by_node(phandle); - of_node_put(phandle); - if (!ddc) - return ERR_PTR(-EPROBE_DEFER); - - return ddc; -} - static int simple_bridge_probe(struct platform_device *pdev) { struct simple_bridge *sbridge; + struct device_node *remote; sbridge = devm_kzalloc(&pdev->dev, sizeof(*sbridge), GFP_KERNEL); if (!sbridge) @@ -205,6 +176,20 @@ static int simple_bridge_probe(struct platform_device *pdev) sbridge->info = of_device_get_match_data(&pdev->dev); + /* Get the next bridge in the pipeline. */ + remote = of_graph_get_remote_node(pdev->dev.of_node, 1, -1); + if (!remote) + return -EINVAL; + + sbridge->next_bridge = of_drm_find_bridge(remote); + of_node_put(remote); + + if (!sbridge->next_bridge) { + dev_dbg(&pdev->dev, "Next bridge not found, deferring probe\n"); + return -EPROBE_DEFER; + } + + /* Get the regulator and GPIO resources. */ sbridge->vdd = devm_regulator_get_optional(&pdev->dev, "vdd"); if (IS_ERR(sbridge->vdd)) { int ret = PTR_ERR(sbridge->vdd); @@ -222,18 +207,7 @@ static int simple_bridge_probe(struct platform_device *pdev) return PTR_ERR(sbridge->enable); } - sbridge->ddc = simple_bridge_retrieve_ddc(&pdev->dev); - if (IS_ERR(sbridge->ddc)) { - if (PTR_ERR(sbridge->ddc) == -ENODEV) { - dev_dbg(&pdev->dev, - "No i2c bus specified. Disabling EDID readout\n"); - sbridge->ddc = NULL; - } else { - dev_err(&pdev->dev, "Couldn't retrieve i2c bus\n"); - return PTR_ERR(sbridge->ddc); - } - } - + /* Register the bridge. */ sbridge->bridge.funcs = &simple_bridge_bridge_funcs; sbridge->bridge.of_node = pdev->dev.of_node; sbridge->bridge.timings = sbridge->info->timings; @@ -249,9 +223,6 @@ static int simple_bridge_remove(struct platform_device *pdev) drm_bridge_remove(&sbridge->bridge); - if (sbridge->ddc) - i2c_put_adapter(sbridge->ddc); - return 0; } diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c index 30681398cfb0..6148a022569a 100644 --- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c +++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c @@ -181,6 +181,7 @@ struct dw_hdmi { struct mutex mutex; /* for state below and previous_mode */ enum drm_connector_force force; /* mutex-protected force state */ + struct drm_connector *curr_conn;/* current connector (only valid when !disabled) */ bool disabled; /* DRM has disabled our bridge */ bool bridge_is_on; /* indicates the bridge is on */ bool rxsense; /* rxsense state */ @@ -1241,10 +1242,9 @@ void dw_hdmi_phy_i2c_write(struct dw_hdmi *hdmi, unsigned short data, EXPORT_SYMBOL_GPL(dw_hdmi_phy_i2c_write); /* Filter out invalid setups to avoid configuring SCDC and scrambling */ -static bool dw_hdmi_support_scdc(struct dw_hdmi *hdmi) +static bool dw_hdmi_support_scdc(struct dw_hdmi *hdmi, + const struct drm_display_info *display) { - struct drm_display_info *display = &hdmi->connector.display_info; - /* Completely disable SCDC support for older controllers */ if (hdmi->version < 0x200a) return false; @@ -1282,12 +1282,13 @@ static bool dw_hdmi_support_scdc(struct dw_hdmi *hdmi) * helper should called right before enabling the TMDS Clock and Data in * the PHY configuration callback. */ -void dw_hdmi_set_high_tmds_clock_ratio(struct dw_hdmi *hdmi) +void dw_hdmi_set_high_tmds_clock_ratio(struct dw_hdmi *hdmi, + const struct drm_display_info *display) { unsigned long mtmdsclock = hdmi->hdmi_data.video_mode.mtmdsclock; /* Control for TMDS Bit Period/TMDS Clock-Period Ratio */ - if (dw_hdmi_support_scdc(hdmi)) { + if (dw_hdmi_support_scdc(hdmi, display)) { if (mtmdsclock > HDMI14_MAX_TMDSCLK) drm_scdc_set_high_tmds_clock_ratio(hdmi->ddc, 1); else @@ -1490,7 +1491,8 @@ static int hdmi_phy_configure_dwc_hdmi_3d_tx(struct dw_hdmi *hdmi, return 0; } -static int hdmi_phy_configure(struct dw_hdmi *hdmi) +static int hdmi_phy_configure(struct dw_hdmi *hdmi, + const struct drm_display_info *display) { const struct dw_hdmi_phy_data *phy = hdmi->phy.data; const struct dw_hdmi_plat_data *pdata = hdmi->plat_data; @@ -1500,7 +1502,7 @@ static int hdmi_phy_configure(struct dw_hdmi *hdmi) dw_hdmi_phy_power_off(hdmi); - dw_hdmi_set_high_tmds_clock_ratio(hdmi); + dw_hdmi_set_high_tmds_clock_ratio(hdmi, display); /* Leave low power consumption mode by asserting SVSRET. */ if (phy->has_svsret) @@ -1514,7 +1516,7 @@ static int hdmi_phy_configure(struct dw_hdmi *hdmi) /* Write to the PHY as configured by the platform */ if (pdata->configure_phy) - ret = pdata->configure_phy(hdmi, pdata, mpixelclock); + ret = pdata->configure_phy(hdmi, pdata->priv_data, mpixelclock); else ret = phy->configure(hdmi, pdata, mpixelclock); if (ret) { @@ -1531,7 +1533,8 @@ static int hdmi_phy_configure(struct dw_hdmi *hdmi) } static int dw_hdmi_phy_init(struct dw_hdmi *hdmi, void *data, - struct drm_display_mode *mode) + const struct drm_display_info *display, + const struct drm_display_mode *mode) { int i, ret; @@ -1540,7 +1543,7 @@ static int dw_hdmi_phy_init(struct dw_hdmi *hdmi, void *data, dw_hdmi_phy_sel_data_en_pol(hdmi, 1); dw_hdmi_phy_sel_interface_control(hdmi, 0); - ret = hdmi_phy_configure(hdmi); + ret = hdmi_phy_configure(hdmi, display); if (ret) return ret; } @@ -1628,18 +1631,18 @@ static void hdmi_tx_hdcp_config(struct dw_hdmi *hdmi) HDMI_A_HDCPCFG1_ENCRYPTIONDISABLE_MASK, HDMI_A_HDCPCFG1); } -static void hdmi_config_AVI(struct dw_hdmi *hdmi, struct drm_display_mode *mode) +static void hdmi_config_AVI(struct dw_hdmi *hdmi, + const struct drm_connector *connector, + const struct drm_display_mode *mode) { struct hdmi_avi_infoframe frame; u8 val; /* Initialise info frame from DRM mode */ - drm_hdmi_avi_infoframe_from_display_mode(&frame, - &hdmi->connector, mode); + drm_hdmi_avi_infoframe_from_display_mode(&frame, connector, mode); if (hdmi_bus_fmt_is_rgb(hdmi->hdmi_data.enc_out_bus_format)) { - drm_hdmi_avi_infoframe_quant_range(&frame, &hdmi->connector, - mode, + drm_hdmi_avi_infoframe_quant_range(&frame, connector, mode, hdmi->hdmi_data.rgb_limited_range ? HDMI_QUANTIZATION_RANGE_LIMITED : HDMI_QUANTIZATION_RANGE_FULL); @@ -1756,14 +1759,14 @@ static void hdmi_config_AVI(struct dw_hdmi *hdmi, struct drm_display_mode *mode) } static void hdmi_config_vendor_specific_infoframe(struct dw_hdmi *hdmi, - struct drm_display_mode *mode) + const struct drm_connector *connector, + const struct drm_display_mode *mode) { struct hdmi_vendor_infoframe frame; u8 buffer[10]; ssize_t err; - err = drm_hdmi_vendor_infoframe_from_display_mode(&frame, - &hdmi->connector, + err = drm_hdmi_vendor_infoframe_from_display_mode(&frame, connector, mode); if (err < 0) /* @@ -1809,9 +1812,10 @@ static void hdmi_config_vendor_specific_infoframe(struct dw_hdmi *hdmi, HDMI_FC_DATAUTO0_VSD_MASK); } -static void hdmi_config_drm_infoframe(struct dw_hdmi *hdmi) +static void hdmi_config_drm_infoframe(struct dw_hdmi *hdmi, + const struct drm_connector *connector) { - const struct drm_connector_state *conn_state = hdmi->connector.state; + const struct drm_connector_state *conn_state = connector->state; struct hdmi_drm_infoframe frame; u8 buffer[30]; ssize_t err; @@ -1845,10 +1849,11 @@ static void hdmi_config_drm_infoframe(struct dw_hdmi *hdmi) } static void hdmi_av_composer(struct dw_hdmi *hdmi, + const struct drm_display_info *display, const struct drm_display_mode *mode) { u8 inv_val, bytes; - struct drm_hdmi_info *hdmi_info = &hdmi->connector.display_info.hdmi; + const struct drm_hdmi_info *hdmi_info = &display->hdmi; struct hdmi_vmode *vmode = &hdmi->hdmi_data.video_mode; int hblank, vblank, h_de_hs, v_de_vs, hsync_len, vsync_len; unsigned int vdisplay, hdisplay; @@ -1881,7 +1886,7 @@ static void hdmi_av_composer(struct dw_hdmi *hdmi, /* Set up HDMI_FC_INVIDCONF */ inv_val = (hdmi->hdmi_data.hdcp_enable || - (dw_hdmi_support_scdc(hdmi) && + (dw_hdmi_support_scdc(hdmi, display) && (vmode->mtmdsclock > HDMI14_MAX_TMDSCLK || hdmi_info->scdc.scrambling.low_rates)) ? HDMI_FC_INVIDCONF_HDCP_KEEPOUT_ACTIVE : @@ -1949,7 +1954,7 @@ static void hdmi_av_composer(struct dw_hdmi *hdmi, } /* Scrambling Control */ - if (dw_hdmi_support_scdc(hdmi)) { + if (dw_hdmi_support_scdc(hdmi, display)) { if (vmode->mtmdsclock > HDMI14_MAX_TMDSCLK || hdmi_info->scdc.scrambling.low_rates) { /* @@ -2112,7 +2117,9 @@ static void hdmi_disable_overflow_interrupts(struct dw_hdmi *hdmi) HDMI_IH_MUTE_FC_STAT2); } -static int dw_hdmi_setup(struct dw_hdmi *hdmi, struct drm_display_mode *mode) +static int dw_hdmi_setup(struct dw_hdmi *hdmi, + const struct drm_connector *connector, + const struct drm_display_mode *mode) { int ret; @@ -2137,10 +2144,7 @@ static int dw_hdmi_setup(struct dw_hdmi *hdmi, struct drm_display_mode *mode) hdmi->hdmi_data.video_mode.mpixelrepetitionoutput = 0; hdmi->hdmi_data.video_mode.mpixelrepetitioninput = 0; - if (hdmi->plat_data->input_bus_format) - hdmi->hdmi_data.enc_in_bus_format = - hdmi->plat_data->input_bus_format; - else if (hdmi->hdmi_data.enc_in_bus_format == MEDIA_BUS_FMT_FIXED) + if (hdmi->hdmi_data.enc_in_bus_format == MEDIA_BUS_FMT_FIXED) hdmi->hdmi_data.enc_in_bus_format = MEDIA_BUS_FMT_RGB888_1X24; /* TOFIX: Get input encoding from plat data or fallback to none */ @@ -2162,10 +2166,12 @@ static int dw_hdmi_setup(struct dw_hdmi *hdmi, struct drm_display_mode *mode) hdmi->hdmi_data.video_mode.mdataenablepolarity = true; /* HDMI Initialization Step B.1 */ - hdmi_av_composer(hdmi, mode); + hdmi_av_composer(hdmi, &connector->display_info, mode); /* HDMI Initializateion Step B.2 */ - ret = hdmi->phy.ops->init(hdmi, hdmi->phy.data, &hdmi->previous_mode); + ret = hdmi->phy.ops->init(hdmi, hdmi->phy.data, + &connector->display_info, + &hdmi->previous_mode); if (ret) return ret; hdmi->phy.enabled = true; @@ -2186,9 +2192,9 @@ static int dw_hdmi_setup(struct dw_hdmi *hdmi, struct drm_display_mode *mode) dev_dbg(hdmi->dev, "%s HDMI mode\n", __func__); /* HDMI Initialization Step F - Configure AVI InfoFrame */ - hdmi_config_AVI(hdmi, mode); - hdmi_config_vendor_specific_infoframe(hdmi, mode); - hdmi_config_drm_infoframe(hdmi); + hdmi_config_AVI(hdmi, connector, mode); + hdmi_config_vendor_specific_infoframe(hdmi, connector, mode); + hdmi_config_drm_infoframe(hdmi, connector); } else { dev_dbg(hdmi->dev, "%s DVI mode\n", __func__); } @@ -2257,7 +2263,12 @@ static void initialize_hdmi_ih_mutes(struct dw_hdmi *hdmi) static void dw_hdmi_poweron(struct dw_hdmi *hdmi) { hdmi->bridge_is_on = true; - dw_hdmi_setup(hdmi, &hdmi->previous_mode); + + /* + * The curr_conn field is guaranteed to be valid here, as this function + * is only be called when !hdmi->disabled. + */ + dw_hdmi_setup(hdmi, hdmi->curr_conn, &hdmi->previous_mode); } static void dw_hdmi_poweroff(struct dw_hdmi *hdmi) @@ -2312,11 +2323,8 @@ static void dw_hdmi_update_phy_mask(struct dw_hdmi *hdmi) hdmi->rxsense); } -static enum drm_connector_status -dw_hdmi_connector_detect(struct drm_connector *connector, bool force) +static enum drm_connector_status dw_hdmi_detect(struct dw_hdmi *hdmi) { - struct dw_hdmi *hdmi = container_of(connector, struct dw_hdmi, - connector); enum drm_connector_status result; mutex_lock(&hdmi->mutex); @@ -2339,31 +2347,57 @@ dw_hdmi_connector_detect(struct drm_connector *connector, bool force) return result; } -static int dw_hdmi_connector_get_modes(struct drm_connector *connector) +static struct edid *dw_hdmi_get_edid(struct dw_hdmi *hdmi, + struct drm_connector *connector) { - struct dw_hdmi *hdmi = container_of(connector, struct dw_hdmi, - connector); struct edid *edid; - int ret = 0; if (!hdmi->ddc) - return 0; + return NULL; edid = drm_get_edid(connector, hdmi->ddc); - if (edid) { - dev_dbg(hdmi->dev, "got edid: width[%d] x height[%d]\n", - edid->width_cm, edid->height_cm); - - hdmi->sink_is_hdmi = drm_detect_hdmi_monitor(edid); - hdmi->sink_has_audio = drm_detect_monitor_audio(edid); - drm_connector_update_edid_property(connector, edid); - cec_notifier_set_phys_addr_from_edid(hdmi->cec_notifier, edid); - ret = drm_add_edid_modes(connector, edid); - kfree(edid); - } else { + if (!edid) { dev_dbg(hdmi->dev, "failed to get edid\n"); + return NULL; } + dev_dbg(hdmi->dev, "got edid: width[%d] x height[%d]\n", + edid->width_cm, edid->height_cm); + + hdmi->sink_is_hdmi = drm_detect_hdmi_monitor(edid); + hdmi->sink_has_audio = drm_detect_monitor_audio(edid); + + return edid; +} + +/* ----------------------------------------------------------------------------- + * DRM Connector Operations + */ + +static enum drm_connector_status +dw_hdmi_connector_detect(struct drm_connector *connector, bool force) +{ + struct dw_hdmi *hdmi = container_of(connector, struct dw_hdmi, + connector); + return dw_hdmi_detect(hdmi); +} + +static int dw_hdmi_connector_get_modes(struct drm_connector *connector) +{ + struct dw_hdmi *hdmi = container_of(connector, struct dw_hdmi, + connector); + struct edid *edid; + int ret; + + edid = dw_hdmi_get_edid(hdmi, connector); + if (!edid) + return 0; + + drm_connector_update_edid_property(connector, edid); + cec_notifier_set_phys_addr_from_edid(hdmi->cec_notifier, edid); + ret = drm_add_edid_modes(connector, edid); + kfree(edid); + return ret; } @@ -2433,6 +2467,59 @@ static const struct drm_connector_helper_funcs dw_hdmi_connector_helper_funcs = .atomic_check = dw_hdmi_connector_atomic_check, }; +static int dw_hdmi_connector_create(struct dw_hdmi *hdmi) +{ + struct drm_connector *connector = &hdmi->connector; + struct cec_connector_info conn_info; + struct cec_notifier *notifier; + + if (hdmi->version >= 0x200a) + connector->ycbcr_420_allowed = + hdmi->plat_data->ycbcr_420_allowed; + else + connector->ycbcr_420_allowed = false; + + connector->interlace_allowed = 1; + connector->polled = DRM_CONNECTOR_POLL_HPD; + + drm_connector_helper_add(connector, &dw_hdmi_connector_helper_funcs); + + drm_connector_init_with_ddc(hdmi->bridge.dev, connector, + &dw_hdmi_connector_funcs, + DRM_MODE_CONNECTOR_HDMIA, + hdmi->ddc); + + /* + * drm_connector_attach_max_bpc_property() requires the + * connector to have a state. + */ + drm_atomic_helper_connector_reset(connector); + + drm_connector_attach_max_bpc_property(connector, 8, 16); + + if (hdmi->version >= 0x200a && hdmi->plat_data->use_drm_infoframe) + drm_object_attach_property(&connector->base, + connector->dev->mode_config.hdr_output_metadata_property, 0); + + drm_connector_attach_encoder(connector, hdmi->bridge.encoder); + + cec_fill_conn_info_from_drm(&conn_info, connector); + + notifier = cec_notifier_conn_register(hdmi->dev, NULL, &conn_info); + if (!notifier) + return -ENOMEM; + + mutex_lock(&hdmi->cec_notifier_mutex); + hdmi->cec_notifier = notifier; + mutex_unlock(&hdmi->cec_notifier_mutex); + + return 0; +} + +/* ----------------------------------------------------------------------------- + * DRM Bridge Operations + */ + /* * Possible output formats : * - MEDIA_BUS_FMT_UYYVYY16_0_5X48, @@ -2708,51 +2795,11 @@ static int dw_hdmi_bridge_attach(struct drm_bridge *bridge, enum drm_bridge_attach_flags flags) { struct dw_hdmi *hdmi = bridge->driver_private; - struct drm_encoder *encoder = bridge->encoder; - struct drm_connector *connector = &hdmi->connector; - struct cec_connector_info conn_info; - struct cec_notifier *notifier; - - if (flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR) { - DRM_ERROR("Fix bridge driver to make connector optional!"); - return -EINVAL; - } - - connector->interlace_allowed = 1; - connector->polled = DRM_CONNECTOR_POLL_HPD; - - drm_connector_helper_add(connector, &dw_hdmi_connector_helper_funcs); - - drm_connector_init_with_ddc(bridge->dev, connector, - &dw_hdmi_connector_funcs, - DRM_MODE_CONNECTOR_HDMIA, - hdmi->ddc); - - /* - * drm_connector_attach_max_bpc_property() requires the - * connector to have a state. - */ - drm_atomic_helper_connector_reset(connector); - - drm_connector_attach_max_bpc_property(connector, 8, 16); - - if (hdmi->version >= 0x200a && hdmi->plat_data->use_drm_infoframe) - drm_object_attach_property(&connector->base, - connector->dev->mode_config.hdr_output_metadata_property, 0); - - drm_connector_attach_encoder(connector, encoder); - - cec_fill_conn_info_from_drm(&conn_info, connector); - notifier = cec_notifier_conn_register(hdmi->dev, NULL, &conn_info); - if (!notifier) - return -ENOMEM; - - mutex_lock(&hdmi->cec_notifier_mutex); - hdmi->cec_notifier = notifier; - mutex_unlock(&hdmi->cec_notifier_mutex); + if (flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR) + return 0; - return 0; + return dw_hdmi_connector_create(hdmi); } static void dw_hdmi_bridge_detach(struct drm_bridge *bridge) @@ -2767,18 +2814,20 @@ static void dw_hdmi_bridge_detach(struct drm_bridge *bridge) static enum drm_mode_status dw_hdmi_bridge_mode_valid(struct drm_bridge *bridge, + const struct drm_display_info *info, const struct drm_display_mode *mode) { struct dw_hdmi *hdmi = bridge->driver_private; - struct drm_connector *connector = &hdmi->connector; + const struct dw_hdmi_plat_data *pdata = hdmi->plat_data; enum drm_mode_status mode_status = MODE_OK; /* We don't support double-clocked modes */ if (mode->flags & DRM_MODE_FLAG_DBLCLK) return MODE_BAD; - if (hdmi->plat_data->mode_valid) - mode_status = hdmi->plat_data->mode_valid(connector, mode); + if (pdata->mode_valid) + mode_status = pdata->mode_valid(hdmi, pdata->priv_data, info, + mode); return mode_status; } @@ -2797,28 +2846,52 @@ static void dw_hdmi_bridge_mode_set(struct drm_bridge *bridge, mutex_unlock(&hdmi->mutex); } -static void dw_hdmi_bridge_disable(struct drm_bridge *bridge) +static void dw_hdmi_bridge_atomic_disable(struct drm_bridge *bridge, + struct drm_bridge_state *old_state) { struct dw_hdmi *hdmi = bridge->driver_private; mutex_lock(&hdmi->mutex); hdmi->disabled = true; + hdmi->curr_conn = NULL; dw_hdmi_update_power(hdmi); dw_hdmi_update_phy_mask(hdmi); mutex_unlock(&hdmi->mutex); } -static void dw_hdmi_bridge_enable(struct drm_bridge *bridge) +static void dw_hdmi_bridge_atomic_enable(struct drm_bridge *bridge, + struct drm_bridge_state *old_state) { struct dw_hdmi *hdmi = bridge->driver_private; + struct drm_atomic_state *state = old_state->base.state; + struct drm_connector *connector; + + connector = drm_atomic_get_new_connector_for_encoder(state, + bridge->encoder); mutex_lock(&hdmi->mutex); hdmi->disabled = false; + hdmi->curr_conn = connector; dw_hdmi_update_power(hdmi); dw_hdmi_update_phy_mask(hdmi); mutex_unlock(&hdmi->mutex); } +static enum drm_connector_status dw_hdmi_bridge_detect(struct drm_bridge *bridge) +{ + struct dw_hdmi *hdmi = bridge->driver_private; + + return dw_hdmi_detect(hdmi); +} + +static struct edid *dw_hdmi_bridge_get_edid(struct drm_bridge *bridge, + struct drm_connector *connector) +{ + struct dw_hdmi *hdmi = bridge->driver_private; + + return dw_hdmi_get_edid(hdmi, connector); +} + static const struct drm_bridge_funcs dw_hdmi_bridge_funcs = { .atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state, .atomic_destroy_state = drm_atomic_helper_bridge_destroy_state, @@ -2828,12 +2901,18 @@ static const struct drm_bridge_funcs dw_hdmi_bridge_funcs = { .atomic_check = dw_hdmi_bridge_atomic_check, .atomic_get_output_bus_fmts = dw_hdmi_bridge_atomic_get_output_bus_fmts, .atomic_get_input_bus_fmts = dw_hdmi_bridge_atomic_get_input_bus_fmts, - .enable = dw_hdmi_bridge_enable, - .disable = dw_hdmi_bridge_disable, + .atomic_enable = dw_hdmi_bridge_atomic_enable, + .atomic_disable = dw_hdmi_bridge_atomic_disable, .mode_set = dw_hdmi_bridge_mode_set, .mode_valid = dw_hdmi_bridge_mode_valid, + .detect = dw_hdmi_bridge_detect, + .get_edid = dw_hdmi_bridge_get_edid, }; +/* ----------------------------------------------------------------------------- + * IRQ Handling + */ + static irqreturn_t dw_hdmi_i2c_irq(struct dw_hdmi *hdmi) { struct dw_hdmi_i2c *i2c = hdmi->i2c; @@ -2943,10 +3022,18 @@ static irqreturn_t dw_hdmi_irq(int irq, void *dev_id) } if (intr_stat & HDMI_IH_PHY_STAT0_HPD) { + enum drm_connector_status status = phy_int_pol & HDMI_PHY_HPD + ? connector_status_connected + : connector_status_disconnected; + dev_dbg(hdmi->dev, "EVENT=%s\n", - phy_int_pol & HDMI_PHY_HPD ? "plugin" : "plugout"); - if (hdmi->bridge.dev) + status == connector_status_connected ? + "plugin" : "plugout"); + + if (hdmi->bridge.dev) { drm_helper_hpd_irq_event(hdmi->bridge.dev); + drm_bridge_hpd_notify(&hdmi->bridge, status); + } } hdmi_writeb(hdmi, intr_stat, HDMI_IH_PHY_STAT0); @@ -3292,16 +3379,12 @@ __dw_hdmi_probe(struct platform_device *pdev, hdmi->bridge.driver_private = hdmi; hdmi->bridge.funcs = &dw_hdmi_bridge_funcs; + hdmi->bridge.ops = DRM_BRIDGE_OP_DETECT | DRM_BRIDGE_OP_EDID + | DRM_BRIDGE_OP_HPD; #ifdef CONFIG_OF hdmi->bridge.of_node = pdev->dev.of_node; #endif - if (hdmi->version >= 0x200a) - hdmi->connector.ycbcr_420_allowed = - hdmi->plat_data->ycbcr_420_allowed; - else - hdmi->connector.ycbcr_420_allowed = false; - memset(&pdevinfo, 0, sizeof(pdevinfo)); pdevinfo.parent = dev; pdevinfo.id = PLATFORM_DEVID_AUTO; diff --git a/drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c b/drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c index 5ef0f154aa7b..d580b2aa4ce9 100644 --- a/drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c +++ b/drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c @@ -27,7 +27,6 @@ #include <drm/drm_modes.h> #include <drm/drm_of.h> #include <drm/drm_print.h> -#include <drm/drm_probe_helper.h> #define HWVER_131 0x31333100 /* IP version 1.31 */ @@ -924,6 +923,7 @@ static void dw_mipi_dsi_bridge_enable(struct drm_bridge *bridge) static enum drm_mode_status dw_mipi_dsi_bridge_mode_valid(struct drm_bridge *bridge, + const struct drm_display_info *info, const struct drm_display_mode *mode) { struct dw_mipi_dsi *dsi = bridge_to_dsi(bridge); diff --git a/drivers/gpu/drm/bridge/tc358767.c b/drivers/gpu/drm/bridge/tc358767.c index e4c0ea03ae3a..c2777b226c75 100644 --- a/drivers/gpu/drm/bridge/tc358767.c +++ b/drivers/gpu/drm/bridge/tc358767.c @@ -1306,6 +1306,7 @@ static bool tc_bridge_mode_fixup(struct drm_bridge *bridge, } static enum drm_mode_status tc_mode_valid(struct drm_bridge *bridge, + const struct drm_display_info *info, const struct drm_display_mode *mode) { struct tc_data *tc = bridge_to_tc(bridge); diff --git a/drivers/gpu/drm/bridge/tc358768.c b/drivers/gpu/drm/bridge/tc358768.c index 6650fe4cfc20..4a463fadf743 100644 --- a/drivers/gpu/drm/bridge/tc358768.c +++ b/drivers/gpu/drm/bridge/tc358768.c @@ -529,6 +529,7 @@ static int tc358768_bridge_attach(struct drm_bridge *bridge, static enum drm_mode_status tc358768_bridge_mode_valid(struct drm_bridge *bridge, + const struct drm_display_info *info, const struct drm_display_mode *mode) { struct tc358768_priv *priv = bridge_to_tc358768(bridge); diff --git a/drivers/gpu/drm/bridge/thc63lvd1024.c b/drivers/gpu/drm/bridge/thc63lvd1024.c index 97d8129760e9..86b06975bfdd 100644 --- a/drivers/gpu/drm/bridge/thc63lvd1024.c +++ b/drivers/gpu/drm/bridge/thc63lvd1024.c @@ -51,6 +51,7 @@ static int thc63_attach(struct drm_bridge *bridge, } static enum drm_mode_status thc63_mode_valid(struct drm_bridge *bridge, + const struct drm_display_info *info, const struct drm_display_mode *mode) { struct thc63_dev *thc63 = to_thc63(bridge); diff --git a/drivers/gpu/drm/bridge/ti-tfp410.c b/drivers/gpu/drm/bridge/ti-tfp410.c index e3eb6364c0f7..ba3fa2a9b8a4 100644 --- a/drivers/gpu/drm/bridge/ti-tfp410.c +++ b/drivers/gpu/drm/bridge/ti-tfp410.c @@ -51,11 +51,15 @@ static int tfp410_get_modes(struct drm_connector *connector) struct edid *edid; int ret; - edid = drm_bridge_get_edid(dvi->next_bridge, connector); - if (IS_ERR_OR_NULL(edid)) { - if (edid != ERR_PTR(-ENOTSUPP)) + if (dvi->next_bridge->ops & DRM_BRIDGE_OP_EDID) { + edid = drm_bridge_get_edid(dvi->next_bridge, connector); + if (!edid) DRM_INFO("EDID read failed. Fallback to standard modes\n"); + } else { + edid = NULL; + } + if (!edid) { /* * No EDID, fallback on the XGA standard modes and prefer a mode * pretty much anything can handle. @@ -188,6 +192,7 @@ static void tfp410_disable(struct drm_bridge *bridge) } static enum drm_mode_status tfp410_mode_valid(struct drm_bridge *bridge, + const struct drm_display_info *info, const struct drm_display_mode *mode) { if (mode->clock < 25000) @@ -220,7 +225,7 @@ static int tfp410_parse_timings(struct tfp410 *dvi, bool i2c) struct device_node *ep; u32 pclk_sample = 0; u32 bus_width = 24; - s32 deskew = 0; + u32 deskew = 0; /* Start with defaults. */ *timings = tfp410_default_timings; @@ -274,12 +279,12 @@ static int tfp410_parse_timings(struct tfp410 *dvi, bool i2c) } /* Get the setup and hold time from vendor-specific properties. */ - of_property_read_u32(dvi->dev->of_node, "ti,deskew", (u32 *)&deskew); - if (deskew < -4 || deskew > 3) + of_property_read_u32(dvi->dev->of_node, "ti,deskew", &deskew); + if (deskew > 7) return -EINVAL; - timings->setup_time_ps = min(0, 1200 - 350 * deskew); - timings->hold_time_ps = min(0, 1300 + 350 * deskew); + timings->setup_time_ps = 1200 - 350 * ((s32)deskew - 4); + timings->hold_time_ps = max(0, 1300 + 350 * ((s32)deskew - 4)); return 0; } |