diff options
Diffstat (limited to 'drivers/gpu/drm/bridge')
| -rw-r--r-- | drivers/gpu/drm/bridge/aux-hpd-bridge.c | 3 | ||||
| -rw-r--r-- | drivers/gpu/drm/bridge/panel.c | 5 | ||||
| -rw-r--r-- | drivers/gpu/drm/bridge/samsung-dsim.c | 4 | ||||
| -rw-r--r-- | drivers/gpu/drm/bridge/ti-sn65dsi86.c | 69 | 
4 files changed, 65 insertions, 16 deletions
diff --git a/drivers/gpu/drm/bridge/aux-hpd-bridge.c b/drivers/gpu/drm/bridge/aux-hpd-bridge.c index b3f588b71a7d..af6f79793407 100644 --- a/drivers/gpu/drm/bridge/aux-hpd-bridge.c +++ b/drivers/gpu/drm/bridge/aux-hpd-bridge.c @@ -64,10 +64,11 @@ struct auxiliary_device *devm_drm_dp_hpd_bridge_alloc(struct device *parent, str  	adev->id = ret;  	adev->name = "dp_hpd_bridge";  	adev->dev.parent = parent; -	adev->dev.of_node = of_node_get(parent->of_node);  	adev->dev.release = drm_aux_hpd_bridge_release;  	adev->dev.platform_data = of_node_get(np); +	device_set_of_node_from_dev(&adev->dev, parent); +  	ret = auxiliary_device_init(adev);  	if (ret) {  		of_node_put(adev->dev.platform_data); diff --git a/drivers/gpu/drm/bridge/panel.c b/drivers/gpu/drm/bridge/panel.c index 79b009ab9396..29b0358a7b6d 100644 --- a/drivers/gpu/drm/bridge/panel.c +++ b/drivers/gpu/drm/bridge/panel.c @@ -299,6 +299,7 @@ struct drm_bridge *drm_panel_bridge_add_typed(struct drm_panel *panel,  	panel_bridge->bridge.of_node = panel->dev->of_node;  	panel_bridge->bridge.ops = DRM_BRIDGE_OP_MODES;  	panel_bridge->bridge.type = connector_type; +	panel_bridge->bridge.pre_enable_prev_first = panel->prepare_prev_first;  	drm_bridge_add(&panel_bridge->bridge); @@ -413,8 +414,6 @@ struct drm_bridge *devm_drm_panel_bridge_add_typed(struct device *dev,  		return bridge;  	} -	bridge->pre_enable_prev_first = panel->prepare_prev_first; -  	*ptr = bridge;  	devres_add(dev, ptr); @@ -456,8 +455,6 @@ struct drm_bridge *drmm_panel_bridge_add(struct drm_device *drm,  	if (ret)  		return ERR_PTR(ret); -	bridge->pre_enable_prev_first = panel->prepare_prev_first; -  	return bridge;  }  EXPORT_SYMBOL(drmm_panel_bridge_add); diff --git a/drivers/gpu/drm/bridge/samsung-dsim.c b/drivers/gpu/drm/bridge/samsung-dsim.c index 0014c497e3fe..bccc88d25948 100644 --- a/drivers/gpu/drm/bridge/samsung-dsim.c +++ b/drivers/gpu/drm/bridge/samsung-dsim.c @@ -1095,7 +1095,7 @@ static void samsung_dsim_send_to_fifo(struct samsung_dsim *dsi,  	bool first = !xfer->tx_done;  	u32 reg; -	dev_dbg(dev, "< xfer %pK: tx len %u, done %u, rx len %u, done %u\n", +	dev_dbg(dev, "< xfer %p: tx len %u, done %u, rx len %u, done %u\n",  		xfer, length, xfer->tx_done, xfer->rx_len, xfer->rx_done);  	if (length > DSI_TX_FIFO_SIZE) @@ -1293,7 +1293,7 @@ static bool samsung_dsim_transfer_finish(struct samsung_dsim *dsi)  	spin_unlock_irqrestore(&dsi->transfer_lock, flags);  	dev_dbg(dsi->dev, -		"> xfer %pK, tx_len %zu, tx_done %u, rx_len %u, rx_done %u\n", +		"> xfer %p, tx_len %zu, tx_done %u, rx_len %u, rx_done %u\n",  		xfer, xfer->packet.payload_length, xfer->tx_done, xfer->rx_len,  		xfer->rx_done); diff --git a/drivers/gpu/drm/bridge/ti-sn65dsi86.c b/drivers/gpu/drm/bridge/ti-sn65dsi86.c index 60224f476e1d..834b42a4d31f 100644 --- a/drivers/gpu/drm/bridge/ti-sn65dsi86.c +++ b/drivers/gpu/drm/bridge/ti-sn65dsi86.c @@ -348,12 +348,18 @@ static void ti_sn65dsi86_enable_comms(struct ti_sn65dsi86 *pdata,  	 * 200 ms.  We'll assume that the panel driver will have the hardcoded  	 * delay in its prepare and always disable HPD.  	 * -	 * If HPD somehow makes sense on some future panel we'll have to -	 * change this to be conditional on someone specifying that HPD should -	 * be used. +	 * For DisplayPort bridge type, we need HPD. So we use the bridge type +	 * to conditionally disable HPD. +	 * NOTE: The bridge type is set in ti_sn_bridge_probe() but enable_comms() +	 * can be called before. So for DisplayPort, HPD will be enabled once +	 * bridge type is set. We are using bridge type instead of "no-hpd" +	 * property because it is not used properly in devicetree description +	 * and hence is unreliable.  	 */ -	regmap_update_bits(pdata->regmap, SN_HPD_DISABLE_REG, HPD_DISABLE, -			   HPD_DISABLE); + +	if (pdata->bridge.type != DRM_MODE_CONNECTOR_DisplayPort) +		regmap_update_bits(pdata->regmap, SN_HPD_DISABLE_REG, HPD_DISABLE, +				   HPD_DISABLE);  	pdata->comms_enabled = true; @@ -1195,9 +1201,14 @@ static enum drm_connector_status ti_sn_bridge_detect(struct drm_bridge *bridge)  	struct ti_sn65dsi86 *pdata = bridge_to_ti_sn65dsi86(bridge);  	int val = 0; -	pm_runtime_get_sync(pdata->dev); +	/* +	 * Runtime reference is grabbed in ti_sn_bridge_hpd_enable() +	 * as the chip won't report HPD just after being powered on. +	 * HPD_DEBOUNCED_STATE reflects correct state only after the +	 * debounce time (~100-400 ms). +	 */ +  	regmap_read(pdata->regmap, SN_HPD_DISABLE_REG, &val); -	pm_runtime_put_autosuspend(pdata->dev);  	return val & HPD_DEBOUNCED_STATE ? connector_status_connected  					 : connector_status_disconnected; @@ -1220,6 +1231,26 @@ static void ti_sn65dsi86_debugfs_init(struct drm_bridge *bridge, struct dentry *  	debugfs_create_file("status", 0600, debugfs, pdata, &status_fops);  } +static void ti_sn_bridge_hpd_enable(struct drm_bridge *bridge) +{ +	struct ti_sn65dsi86 *pdata = bridge_to_ti_sn65dsi86(bridge); + +	/* +	 * Device needs to be powered on before reading the HPD state +	 * for reliable hpd detection in ti_sn_bridge_detect() due to +	 * the high debounce time. +	 */ + +	pm_runtime_get_sync(pdata->dev); +} + +static void ti_sn_bridge_hpd_disable(struct drm_bridge *bridge) +{ +	struct ti_sn65dsi86 *pdata = bridge_to_ti_sn65dsi86(bridge); + +	pm_runtime_put_autosuspend(pdata->dev); +} +  static const struct drm_bridge_funcs ti_sn_bridge_funcs = {  	.attach = ti_sn_bridge_attach,  	.detach = ti_sn_bridge_detach, @@ -1234,6 +1265,8 @@ static const struct drm_bridge_funcs ti_sn_bridge_funcs = {  	.atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state,  	.atomic_destroy_state = drm_atomic_helper_bridge_destroy_state,  	.debugfs_init = ti_sn65dsi86_debugfs_init, +	.hpd_enable = ti_sn_bridge_hpd_enable, +	.hpd_disable = ti_sn_bridge_hpd_disable,  };  static void ti_sn_bridge_parse_lanes(struct ti_sn65dsi86 *pdata, @@ -1321,8 +1354,26 @@ static int ti_sn_bridge_probe(struct auxiliary_device *adev,  	pdata->bridge.type = pdata->next_bridge->type == DRM_MODE_CONNECTOR_DisplayPort  			   ? DRM_MODE_CONNECTOR_DisplayPort : DRM_MODE_CONNECTOR_eDP; -	if (pdata->bridge.type == DRM_MODE_CONNECTOR_DisplayPort) -		pdata->bridge.ops = DRM_BRIDGE_OP_EDID | DRM_BRIDGE_OP_DETECT; +	if (pdata->bridge.type == DRM_MODE_CONNECTOR_DisplayPort) { +		pdata->bridge.ops = DRM_BRIDGE_OP_EDID | DRM_BRIDGE_OP_DETECT | +				    DRM_BRIDGE_OP_HPD; +		/* +		 * If comms were already enabled they would have been enabled +		 * with the wrong value of HPD_DISABLE. Update it now. Comms +		 * could be enabled if anyone is holding a pm_runtime reference +		 * (like if a GPIO is in use). Note that in most cases nobody +		 * is doing AUX channel xfers before the bridge is added so +		 * HPD doesn't _really_ matter then. The only exception is in +		 * the eDP case where the panel wants to read the EDID before +		 * the bridge is added. We always consistently have HPD disabled +		 * for eDP. +		 */ +		mutex_lock(&pdata->comms_mutex); +		if (pdata->comms_enabled) +			regmap_update_bits(pdata->regmap, SN_HPD_DISABLE_REG, +					   HPD_DISABLE, 0); +		mutex_unlock(&pdata->comms_mutex); +	}  	drm_bridge_add(&pdata->bridge);  | 
