mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-08-30 21:39:35 -04:00
drm/panel: of_drm_find_panel() return a counted reference
Callers of of_drm_find_panel() and drm_of_find_panel_or_bridge() receive a pointer with no reference held, creating a window where the panel device can be unregistered and freed between the lookup and first use (e.g., drm_panel_prepare()). Fix the lookup function by acquiring a reference with drm_panel_get() before returning, under panel_lock. Callers are now responsible for calling drm_panel_put() when they no longer need the pointer. For bridge drivers that immediately wrap the panel in a panel_bridge (which acquires its own reference), release the lookup reference right after the bridge creation call. For analogix-anx6345, which stores the panel for direct use, release the reference in the i2c remove path. For platform drivers using analogix_dp_core with a component lifecycle (exynos_dp, rockchip analogix_dp), release the lookup reference in the platform remove() function. The panel_bridge created during bind() holds a separate reference that devm cleanup releases after remove() returns. Also fix devm_drm_of_get_bridge() and drmm_of_get_bridge() in bridge/panel.c itself, update a second batch of drivers calling of_drm_find_panel() or drm_of_find_panel_or_bridge() to release the lookup reference after wrapping the panel in a bridge, and handle the cases where a panel is found but cannot be used, dropping the reference immediately in those paths. Assisted-by: Claude:claude-opus-4-6 Acked-by: Maxime Ripard <mripard@kernel.org> Signed-off-by: Albert Esteve <aesteve@redhat.com> Signed-off-by: Neil Armstrong <neil.armstrong@linaro.org> Link: https://patch.msgid.link/20260717-drm_refcount_wiring-v3-3-023900c32e01@redhat.com
This commit is contained in:
committed by
Neil Armstrong
parent
8f79d34ea8
commit
b71a623598
@@ -663,6 +663,11 @@ static bool anx6345_get_chip_id(struct anx6345 *anx6345)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void anx6345_panel_put_action(void *data)
|
||||||
|
{
|
||||||
|
drm_panel_put(data);
|
||||||
|
}
|
||||||
|
|
||||||
static int anx6345_i2c_probe(struct i2c_client *client)
|
static int anx6345_i2c_probe(struct i2c_client *client)
|
||||||
{
|
{
|
||||||
struct anx6345 *anx6345;
|
struct anx6345 *anx6345;
|
||||||
@@ -691,6 +696,13 @@ static int anx6345_i2c_probe(struct i2c_client *client)
|
|||||||
if (err)
|
if (err)
|
||||||
DRM_DEBUG("No panel found\n");
|
DRM_DEBUG("No panel found\n");
|
||||||
|
|
||||||
|
if (anx6345->panel) {
|
||||||
|
err = devm_add_action_or_reset(dev, anx6345_panel_put_action,
|
||||||
|
anx6345->panel);
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
/* 1.2V digital core power regulator */
|
/* 1.2V digital core power regulator */
|
||||||
anx6345->dvdd12 = devm_regulator_get(dev, "dvdd12");
|
anx6345->dvdd12 = devm_regulator_get(dev, "dvdd12");
|
||||||
if (IS_ERR(anx6345->dvdd12)) {
|
if (IS_ERR(anx6345->dvdd12)) {
|
||||||
|
|||||||
@@ -348,6 +348,7 @@ static int fsl_ldb_probe(struct platform_device *pdev)
|
|||||||
fsl_ldb->use_termination_resistor = true;
|
fsl_ldb->use_termination_resistor = true;
|
||||||
|
|
||||||
fsl_ldb->panel_bridge = devm_drm_panel_bridge_add(dev, panel);
|
fsl_ldb->panel_bridge = devm_drm_panel_bridge_add(dev, panel);
|
||||||
|
drm_panel_put(panel);
|
||||||
if (IS_ERR(fsl_ldb->panel_bridge))
|
if (IS_ERR(fsl_ldb->panel_bridge))
|
||||||
return PTR_ERR(fsl_ldb->panel_bridge);
|
return PTR_ERR(fsl_ldb->panel_bridge);
|
||||||
|
|
||||||
|
|||||||
@@ -660,6 +660,7 @@ static int lt9211_parse_dt(struct lt9211 *ctx)
|
|||||||
return ret;
|
return ret;
|
||||||
if (panel) {
|
if (panel) {
|
||||||
panel_bridge = devm_drm_panel_bridge_add(dev, panel);
|
panel_bridge = devm_drm_panel_bridge_add(dev, panel);
|
||||||
|
drm_panel_put(panel);
|
||||||
if (IS_ERR(panel_bridge))
|
if (IS_ERR(panel_bridge))
|
||||||
return PTR_ERR(panel_bridge);
|
return PTR_ERR(panel_bridge);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -156,6 +156,7 @@ static int lvds_codec_probe(struct platform_device *pdev)
|
|||||||
lvds_codec->panel_bridge =
|
lvds_codec->panel_bridge =
|
||||||
devm_drm_panel_bridge_add_typed(dev, panel,
|
devm_drm_panel_bridge_add_typed(dev, panel,
|
||||||
lvds_codec->connector_type);
|
lvds_codec->connector_type);
|
||||||
|
drm_panel_put(panel);
|
||||||
if (IS_ERR(lvds_codec->panel_bridge))
|
if (IS_ERR(lvds_codec->panel_bridge))
|
||||||
return PTR_ERR(lvds_codec->panel_bridge);
|
return PTR_ERR(lvds_codec->panel_bridge);
|
||||||
|
|
||||||
|
|||||||
@@ -515,8 +515,10 @@ struct drm_bridge *devm_drm_of_get_bridge(struct device *dev,
|
|||||||
if (ret)
|
if (ret)
|
||||||
return ERR_PTR(ret);
|
return ERR_PTR(ret);
|
||||||
|
|
||||||
if (panel)
|
if (panel) {
|
||||||
bridge = devm_drm_panel_bridge_add(dev, panel);
|
bridge = devm_drm_panel_bridge_add(dev, panel);
|
||||||
|
drm_panel_put(panel);
|
||||||
|
}
|
||||||
|
|
||||||
return bridge;
|
return bridge;
|
||||||
}
|
}
|
||||||
@@ -549,8 +551,10 @@ struct drm_bridge *drmm_of_get_bridge(struct drm_device *drm,
|
|||||||
if (ret)
|
if (ret)
|
||||||
return ERR_PTR(ret);
|
return ERR_PTR(ret);
|
||||||
|
|
||||||
if (panel)
|
if (panel) {
|
||||||
bridge = drmm_panel_bridge_add(drm, panel);
|
bridge = drmm_panel_bridge_add(drm, panel);
|
||||||
|
drm_panel_put(panel);
|
||||||
|
}
|
||||||
|
|
||||||
return bridge;
|
return bridge;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1934,6 +1934,7 @@ static int samsung_dsim_host_attach(struct mipi_dsi_host *host,
|
|||||||
panel = of_drm_find_panel(remote);
|
panel = of_drm_find_panel(remote);
|
||||||
if (!IS_ERR(panel)) {
|
if (!IS_ERR(panel)) {
|
||||||
next_bridge = devm_drm_panel_bridge_add(dev, panel);
|
next_bridge = devm_drm_panel_bridge_add(dev, panel);
|
||||||
|
drm_panel_put(panel);
|
||||||
if (IS_ERR(next_bridge)) {
|
if (IS_ERR(next_bridge)) {
|
||||||
ret = PTR_ERR(next_bridge);
|
ret = PTR_ERR(next_bridge);
|
||||||
next_bridge = NULL; // Inhibit the cleanup action on an ERR_PTR
|
next_bridge = NULL; // Inhibit the cleanup action on an ERR_PTR
|
||||||
|
|||||||
@@ -301,6 +301,7 @@ static int ssd2825_dsi_host_attach(struct mipi_dsi_host *host, struct mipi_dsi_d
|
|||||||
|
|
||||||
if (panel) {
|
if (panel) {
|
||||||
bridge = drm_panel_bridge_add_typed(panel, DRM_MODE_CONNECTOR_DSI);
|
bridge = drm_panel_bridge_add_typed(panel, DRM_MODE_CONNECTOR_DSI);
|
||||||
|
drm_panel_put(panel);
|
||||||
if (IS_ERR(bridge))
|
if (IS_ERR(bridge))
|
||||||
return PTR_ERR(bridge);
|
return PTR_ERR(bridge);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2329,6 +2329,7 @@ static int tc_probe_dpi_bridge_endpoint(struct tc_data *tc)
|
|||||||
|
|
||||||
if (panel) {
|
if (panel) {
|
||||||
bridge = devm_drm_panel_bridge_add(dev, panel);
|
bridge = devm_drm_panel_bridge_add(dev, panel);
|
||||||
|
drm_panel_put(panel);
|
||||||
if (IS_ERR(bridge))
|
if (IS_ERR(bridge))
|
||||||
return PTR_ERR(bridge);
|
return PTR_ERR(bridge);
|
||||||
}
|
}
|
||||||
@@ -2359,6 +2360,7 @@ static int tc_probe_edp_bridge_endpoint(struct tc_data *tc)
|
|||||||
struct drm_bridge *panel_bridge;
|
struct drm_bridge *panel_bridge;
|
||||||
|
|
||||||
panel_bridge = devm_drm_panel_bridge_add(dev, panel);
|
panel_bridge = devm_drm_panel_bridge_add(dev, panel);
|
||||||
|
drm_panel_put(panel);
|
||||||
if (IS_ERR(panel_bridge))
|
if (IS_ERR(panel_bridge))
|
||||||
return PTR_ERR(panel_bridge);
|
return PTR_ERR(panel_bridge);
|
||||||
|
|
||||||
|
|||||||
@@ -479,6 +479,7 @@ static int tc358768_dsi_host_attach(struct mipi_dsi_host *host,
|
|||||||
if (panel) {
|
if (panel) {
|
||||||
bridge = drm_panel_bridge_add_typed(panel,
|
bridge = drm_panel_bridge_add_typed(panel,
|
||||||
DRM_MODE_CONNECTOR_DSI);
|
DRM_MODE_CONNECTOR_DSI);
|
||||||
|
drm_panel_put(panel);
|
||||||
if (IS_ERR(bridge))
|
if (IS_ERR(bridge))
|
||||||
return PTR_ERR(bridge);
|
return PTR_ERR(bridge);
|
||||||
|
|
||||||
|
|||||||
@@ -169,6 +169,7 @@ static int ws_bridge_probe(struct i2c_client *i2c)
|
|||||||
return dev_err_probe(dev, ret, "Failed to find remote panel\n");
|
return dev_err_probe(dev, ret, "Failed to find remote panel\n");
|
||||||
|
|
||||||
ws->next_bridge = devm_drm_panel_bridge_add(dev, panel);
|
ws->next_bridge = devm_drm_panel_bridge_add(dev, panel);
|
||||||
|
drm_panel_put(panel);
|
||||||
if (IS_ERR(ws->next_bridge))
|
if (IS_ERR(ws->next_bridge))
|
||||||
return PTR_ERR(ws->next_bridge);
|
return PTR_ERR(ws->next_bridge);
|
||||||
|
|
||||||
|
|||||||
@@ -269,7 +269,8 @@ EXPORT_SYMBOL_GPL(drm_of_get_panel_orientation);
|
|||||||
* @np: device tree node containing encoder output ports
|
* @np: device tree node containing encoder output ports
|
||||||
* @port: port in the device tree node
|
* @port: port in the device tree node
|
||||||
* @endpoint: endpoint in the device tree node
|
* @endpoint: endpoint in the device tree node
|
||||||
* @panel: pointer to hold returned drm_panel, must not be NULL
|
* @panel: pointer to hold returned drm_panel, must not be NULL. On success
|
||||||
|
* the caller must call drm_panel_put() when done with the panel
|
||||||
* @bridge: pointer to hold returned drm_bridge
|
* @bridge: pointer to hold returned drm_bridge
|
||||||
*
|
*
|
||||||
* Given a DT node's port and endpoint number, find the connected node and
|
* Given a DT node's port and endpoint number, find the connected node and
|
||||||
|
|||||||
@@ -459,14 +459,17 @@ EXPORT_SYMBOL(__devm_drm_panel_alloc);
|
|||||||
|
|
||||||
#ifdef CONFIG_OF
|
#ifdef CONFIG_OF
|
||||||
/**
|
/**
|
||||||
* of_drm_find_panel - look up a panel using a device tree node
|
* of_drm_find_panel - look up and reference a panel by device tree node
|
||||||
* @np: device tree node of the panel
|
* @np: device tree node of the panel
|
||||||
*
|
*
|
||||||
* Searches the set of registered panels for one that matches the given device
|
* Searches the set of registered panels for one that matches the given device
|
||||||
* tree node. If a matching panel is found, return a pointer to it.
|
* tree node. If a matching panel is found, the panel's reference count is
|
||||||
|
* incremented before returning a pointer to it. The caller must call
|
||||||
|
* drm_panel_put() when it no longer needs the panel pointer.
|
||||||
*
|
*
|
||||||
* Return: A pointer to the panel registered for the specified device tree
|
* Return: A reference-counted pointer to the panel registered for the specified
|
||||||
* node or an ERR_PTR() if no panel matching the device tree node can be found.
|
* device tree node or an ERR_PTR() if no panel matching the device tree node
|
||||||
|
* can be found.
|
||||||
*
|
*
|
||||||
* Possible error codes returned by this function:
|
* Possible error codes returned by this function:
|
||||||
*
|
*
|
||||||
@@ -485,6 +488,7 @@ struct drm_panel *of_drm_find_panel(const struct device_node *np)
|
|||||||
|
|
||||||
list_for_each_entry(panel, &panel_list, list) {
|
list_for_each_entry(panel, &panel_list, list) {
|
||||||
if (panel->dev->of_node == np) {
|
if (panel->dev->of_node == np) {
|
||||||
|
drm_panel_get(panel);
|
||||||
mutex_unlock(&panel_lock);
|
mutex_unlock(&panel_lock);
|
||||||
return panel;
|
return panel;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -182,8 +182,15 @@ static int exynos_dp_probe(struct platform_device *pdev)
|
|||||||
|
|
||||||
out:
|
out:
|
||||||
dp->adp = analogix_dp_probe(dev, &dp->plat_data);
|
dp->adp = analogix_dp_probe(dev, &dp->plat_data);
|
||||||
if (IS_ERR(dp->adp))
|
if (IS_ERR(dp->adp)) {
|
||||||
|
/*
|
||||||
|
* The driver core does not invoke remove() for failed probes,
|
||||||
|
* so release the probe-time panel reference here.
|
||||||
|
*/
|
||||||
|
if (dp->plat_data.panel)
|
||||||
|
drm_panel_put(dp->plat_data.panel);
|
||||||
return PTR_ERR(dp->adp);
|
return PTR_ERR(dp->adp);
|
||||||
|
}
|
||||||
|
|
||||||
if (dp->plat_data.panel || dp->plat_data.next_bridge)
|
if (dp->plat_data.panel || dp->plat_data.next_bridge)
|
||||||
return component_add(&pdev->dev, &exynos_dp_ops);
|
return component_add(&pdev->dev, &exynos_dp_ops);
|
||||||
@@ -193,6 +200,16 @@ static int exynos_dp_probe(struct platform_device *pdev)
|
|||||||
|
|
||||||
static void exynos_dp_remove(struct platform_device *pdev)
|
static void exynos_dp_remove(struct platform_device *pdev)
|
||||||
{
|
{
|
||||||
|
struct exynos_dp_device *dp = platform_get_drvdata(pdev);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Release the probe-time reference from of_drm_find_panel(). If bind
|
||||||
|
* ran, the panel_bridge holds a second reference that devm cleanup
|
||||||
|
* will release when the bridge is destroyed after remove() returns.
|
||||||
|
*/
|
||||||
|
if (dp->plat_data.panel)
|
||||||
|
drm_panel_put(dp->plat_data.panel);
|
||||||
|
|
||||||
component_del(&pdev->dev, &exynos_dp_ops);
|
component_del(&pdev->dev, &exynos_dp_ops);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -245,5 +245,8 @@ int exynos_dpi_remove(struct drm_encoder *encoder)
|
|||||||
|
|
||||||
exynos_dpi_disable(&ctx->encoder);
|
exynos_dpi_disable(&ctx->encoder);
|
||||||
|
|
||||||
|
if (ctx->panel)
|
||||||
|
drm_panel_put(ctx->panel);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -109,6 +109,13 @@ static int fsl_dcu_attach_panel(struct fsl_dcu_drm_device *fsl_dev,
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void fsl_dcu_panel_put_action(void *data)
|
||||||
|
{
|
||||||
|
struct drm_panel *panel = data;
|
||||||
|
|
||||||
|
drm_panel_put(panel);
|
||||||
|
}
|
||||||
|
|
||||||
int fsl_dcu_create_outputs(struct fsl_dcu_drm_device *fsl_dev)
|
int fsl_dcu_create_outputs(struct fsl_dcu_drm_device *fsl_dev)
|
||||||
{
|
{
|
||||||
struct device_node *panel_node;
|
struct device_node *panel_node;
|
||||||
@@ -124,6 +131,12 @@ int fsl_dcu_create_outputs(struct fsl_dcu_drm_device *fsl_dev)
|
|||||||
if (IS_ERR(fsl_dev->connector.panel))
|
if (IS_ERR(fsl_dev->connector.panel))
|
||||||
return PTR_ERR(fsl_dev->connector.panel);
|
return PTR_ERR(fsl_dev->connector.panel);
|
||||||
|
|
||||||
|
ret = devm_add_action_or_reset(fsl_dev->dev,
|
||||||
|
fsl_dcu_panel_put_action,
|
||||||
|
fsl_dev->connector.panel);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
return fsl_dcu_attach_panel(fsl_dev, fsl_dev->connector.panel);
|
return fsl_dcu_attach_panel(fsl_dev, fsl_dev->connector.panel);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -132,6 +145,11 @@ int fsl_dcu_create_outputs(struct fsl_dcu_drm_device *fsl_dev)
|
|||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
if (panel) {
|
if (panel) {
|
||||||
|
ret = devm_add_action_or_reset(fsl_dev->dev,
|
||||||
|
fsl_dcu_panel_put_action, panel);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
fsl_dev->connector.panel = panel;
|
fsl_dev->connector.panel = panel;
|
||||||
return fsl_dcu_attach_panel(fsl_dev, panel);
|
return fsl_dcu_attach_panel(fsl_dev, panel);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -77,6 +77,9 @@ static int dcss_kms_bridge_connector_init(struct dcss_kms_dev *kms)
|
|||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
|
if (panel)
|
||||||
|
drm_panel_put(panel);
|
||||||
|
|
||||||
if (!bridge) {
|
if (!bridge) {
|
||||||
dev_err(ddev->dev, "No bridge found %d.\n", ret);
|
dev_err(ddev->dev, "No bridge found %d.\n", ret);
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
|
|||||||
@@ -1297,9 +1297,11 @@ static int ingenic_drm_bind(struct device *dev, bool has_components)
|
|||||||
goto err_drvdata;
|
goto err_drvdata;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (panel)
|
if (panel) {
|
||||||
bridge = devm_drm_panel_bridge_add_typed(dev, panel,
|
bridge = devm_drm_panel_bridge_add_typed(dev, panel,
|
||||||
DRM_MODE_CONNECTOR_DPI);
|
DRM_MODE_CONNECTOR_DPI);
|
||||||
|
drm_panel_put(panel);
|
||||||
|
}
|
||||||
|
|
||||||
ib = drmm_encoder_alloc(drm, struct ingenic_drm_bridge, encoder,
|
ib = drmm_encoder_alloc(drm, struct ingenic_drm_bridge, encoder,
|
||||||
NULL, DRM_MODE_ENCODER_DPI, NULL);
|
NULL, DRM_MODE_ENCODER_DPI, NULL);
|
||||||
|
|||||||
@@ -28,6 +28,11 @@
|
|||||||
#define logicvc_interface_from_drm_connector(c) \
|
#define logicvc_interface_from_drm_connector(c) \
|
||||||
container_of(c, struct logicvc_interface, drm_connector)
|
container_of(c, struct logicvc_interface, drm_connector)
|
||||||
|
|
||||||
|
static void logicvc_panel_put_action(void *data)
|
||||||
|
{
|
||||||
|
drm_panel_put(data);
|
||||||
|
}
|
||||||
|
|
||||||
static void logicvc_encoder_enable(struct drm_encoder *drm_encoder)
|
static void logicvc_encoder_enable(struct drm_encoder *drm_encoder)
|
||||||
{
|
{
|
||||||
struct logicvc_drm *logicvc = logicvc_drm(drm_encoder->dev);
|
struct logicvc_drm *logicvc = logicvc_drm(drm_encoder->dev);
|
||||||
@@ -160,6 +165,13 @@ int logicvc_interface_init(struct logicvc_drm *logicvc)
|
|||||||
if (ret == -EPROBE_DEFER)
|
if (ret == -EPROBE_DEFER)
|
||||||
goto error_early;
|
goto error_early;
|
||||||
|
|
||||||
|
if (interface->drm_panel) {
|
||||||
|
ret = devm_add_action_or_reset(dev, logicvc_panel_put_action,
|
||||||
|
interface->drm_panel);
|
||||||
|
if (ret)
|
||||||
|
goto error_early;
|
||||||
|
}
|
||||||
|
|
||||||
ret = drm_encoder_init(drm_dev, &interface->drm_encoder,
|
ret = drm_encoder_init(drm_dev, &interface->drm_encoder,
|
||||||
&logicvc_encoder_funcs, encoder_type, NULL);
|
&logicvc_encoder_funcs, encoder_type, NULL);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
|
|||||||
@@ -153,6 +153,7 @@ static int mcde_modeset_init(struct drm_device *drm)
|
|||||||
if (panel) {
|
if (panel) {
|
||||||
bridge = drm_panel_bridge_add_typed(panel,
|
bridge = drm_panel_bridge_add_typed(panel,
|
||||||
DRM_MODE_CONNECTOR_DPI);
|
DRM_MODE_CONNECTOR_DPI);
|
||||||
|
drm_panel_put(panel);
|
||||||
if (IS_ERR(bridge)) {
|
if (IS_ERR(bridge)) {
|
||||||
dev_err(drm->dev,
|
dev_err(drm->dev,
|
||||||
"Could not connect panel bridge\n");
|
"Could not connect panel bridge\n");
|
||||||
|
|||||||
@@ -1127,6 +1127,7 @@ static int mcde_dsi_bind(struct device *dev, struct device *master,
|
|||||||
if (panel) {
|
if (panel) {
|
||||||
bridge = drm_panel_bridge_add_typed(panel,
|
bridge = drm_panel_bridge_add_typed(panel,
|
||||||
DRM_MODE_CONNECTOR_DSI);
|
DRM_MODE_CONNECTOR_DSI);
|
||||||
|
drm_panel_put(panel);
|
||||||
if (IS_ERR(bridge)) {
|
if (IS_ERR(bridge)) {
|
||||||
dev_err(dev, "error adding panel bridge\n");
|
dev_err(dev, "error adding panel bridge\n");
|
||||||
return PTR_ERR(bridge);
|
return PTR_ERR(bridge);
|
||||||
|
|||||||
@@ -127,6 +127,7 @@ static int mxsfb_attach_bridge(struct mxsfb_drm_private *mxsfb)
|
|||||||
if (panel) {
|
if (panel) {
|
||||||
bridge = devm_drm_panel_bridge_add_typed(drm->dev, panel,
|
bridge = devm_drm_panel_bridge_add_typed(drm->dev, panel,
|
||||||
DRM_MODE_CONNECTOR_DPI);
|
DRM_MODE_CONNECTOR_DPI);
|
||||||
|
drm_panel_put(panel);
|
||||||
if (IS_ERR(bridge))
|
if (IS_ERR(bridge))
|
||||||
return PTR_ERR(bridge);
|
return PTR_ERR(bridge);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -43,6 +43,7 @@ int omapdss_device_init_output(struct omap_dss_device *out,
|
|||||||
struct drm_bridge *bridge;
|
struct drm_bridge *bridge;
|
||||||
|
|
||||||
bridge = drm_panel_bridge_add(out->panel);
|
bridge = drm_panel_bridge_add(out->panel);
|
||||||
|
drm_panel_put(out->panel);
|
||||||
if (IS_ERR(bridge)) {
|
if (IS_ERR(bridge)) {
|
||||||
dev_err(out->dev,
|
dev_err(out->dev,
|
||||||
"unable to create panel bridge (%ld)\n",
|
"unable to create panel bridge (%ld)\n",
|
||||||
|
|||||||
@@ -145,6 +145,7 @@ static int pl111_modeset_init(struct drm_device *dev)
|
|||||||
if (panel) {
|
if (panel) {
|
||||||
bridge = drm_panel_bridge_add_typed(panel,
|
bridge = drm_panel_bridge_add_typed(panel,
|
||||||
DRM_MODE_CONNECTOR_Unknown);
|
DRM_MODE_CONNECTOR_Unknown);
|
||||||
|
drm_panel_put(panel);
|
||||||
if (IS_ERR(bridge)) {
|
if (IS_ERR(bridge)) {
|
||||||
ret = PTR_ERR(bridge);
|
ret = PTR_ERR(bridge);
|
||||||
goto finish;
|
goto finish;
|
||||||
|
|||||||
@@ -69,6 +69,7 @@ int rcar_du_encoder_init(struct rcar_du_device *rcdu,
|
|||||||
|
|
||||||
bridge = devm_drm_panel_bridge_add_typed(rcdu->dev, panel,
|
bridge = devm_drm_panel_bridge_add_typed(rcdu->dev, panel,
|
||||||
DRM_MODE_CONNECTOR_DPI);
|
DRM_MODE_CONNECTOR_DPI);
|
||||||
|
drm_panel_put(panel);
|
||||||
if (IS_ERR(bridge))
|
if (IS_ERR(bridge))
|
||||||
return PTR_ERR(no_free_ptr(bridge));
|
return PTR_ERR(no_free_ptr(bridge));
|
||||||
|
|
||||||
|
|||||||
@@ -791,6 +791,7 @@ static int rcar_lvds_parse_dt(struct rcar_lvds *lvds)
|
|||||||
if (lvds->panel) {
|
if (lvds->panel) {
|
||||||
lvds->next_bridge = devm_drm_panel_bridge_add(lvds->dev,
|
lvds->next_bridge = devm_drm_panel_bridge_add(lvds->dev,
|
||||||
lvds->panel);
|
lvds->panel);
|
||||||
|
drm_panel_put(lvds->panel);
|
||||||
if (IS_ERR_OR_NULL(lvds->next_bridge)) {
|
if (IS_ERR_OR_NULL(lvds->next_bridge)) {
|
||||||
ret = -EINVAL;
|
ret = -EINVAL;
|
||||||
goto done;
|
goto done;
|
||||||
|
|||||||
@@ -90,6 +90,7 @@ int rzg2l_du_encoder_init(struct rzg2l_du_device *rcdu,
|
|||||||
|
|
||||||
bridge = devm_drm_panel_bridge_add_typed(rcdu->dev, panel,
|
bridge = devm_drm_panel_bridge_add_typed(rcdu->dev, panel,
|
||||||
DRM_MODE_CONNECTOR_DPI);
|
DRM_MODE_CONNECTOR_DPI);
|
||||||
|
drm_panel_put(panel);
|
||||||
if (IS_ERR(bridge))
|
if (IS_ERR(bridge))
|
||||||
return PTR_ERR(no_free_ptr(bridge));
|
return PTR_ERR(no_free_ptr(bridge));
|
||||||
|
|
||||||
|
|||||||
@@ -28,6 +28,7 @@
|
|||||||
#include <drm/drm_bridge_connector.h>
|
#include <drm/drm_bridge_connector.h>
|
||||||
#include <drm/bridge/analogix_dp.h>
|
#include <drm/bridge/analogix_dp.h>
|
||||||
#include <drm/drm_of.h>
|
#include <drm/drm_of.h>
|
||||||
|
#include <drm/drm_panel.h>
|
||||||
#include <drm/drm_print.h>
|
#include <drm/drm_print.h>
|
||||||
#include <drm/drm_probe_helper.h>
|
#include <drm/drm_probe_helper.h>
|
||||||
|
|
||||||
@@ -485,6 +486,16 @@ static int rockchip_dp_probe(struct platform_device *pdev)
|
|||||||
|
|
||||||
static void rockchip_dp_remove(struct platform_device *pdev)
|
static void rockchip_dp_remove(struct platform_device *pdev)
|
||||||
{
|
{
|
||||||
|
struct rockchip_dp_device *dp = platform_get_drvdata(pdev);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Release the probe-time reference from of_drm_find_panel(). If bind
|
||||||
|
* ran, the panel_bridge holds a second reference that devm cleanup
|
||||||
|
* will release when the bridge is destroyed after remove() returns.
|
||||||
|
*/
|
||||||
|
if (dp->plat_data.panel)
|
||||||
|
drm_panel_put(dp->plat_data.panel);
|
||||||
|
|
||||||
component_del(&pdev->dev, &rockchip_dp_component_ops);
|
component_del(&pdev->dev, &rockchip_dp_component_ops);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -610,6 +610,8 @@ static int rockchip_lvds_bind(struct device *dev, struct device *master,
|
|||||||
|
|
||||||
if (lvds->panel) {
|
if (lvds->panel) {
|
||||||
lvds->bridge = drm_panel_bridge_add_typed(lvds->panel, DRM_MODE_CONNECTOR_LVDS);
|
lvds->bridge = drm_panel_bridge_add_typed(lvds->panel, DRM_MODE_CONNECTOR_LVDS);
|
||||||
|
drm_panel_put(lvds->panel);
|
||||||
|
lvds->panel = NULL;
|
||||||
if (IS_ERR(lvds->bridge)) {
|
if (IS_ERR(lvds->bridge)) {
|
||||||
ret = PTR_ERR(lvds->bridge);
|
ret = PTR_ERR(lvds->bridge);
|
||||||
goto err_free_encoder;
|
goto err_free_encoder;
|
||||||
@@ -646,6 +648,8 @@ static int rockchip_lvds_bind(struct device *dev, struct device *master,
|
|||||||
err_free_encoder:
|
err_free_encoder:
|
||||||
drm_encoder_cleanup(encoder);
|
drm_encoder_cleanup(encoder);
|
||||||
err_put_remote:
|
err_put_remote:
|
||||||
|
if (lvds->panel)
|
||||||
|
drm_panel_put(lvds->panel);
|
||||||
of_node_put(remote);
|
of_node_put(remote);
|
||||||
err_put_port:
|
err_put_port:
|
||||||
of_node_put(port);
|
of_node_put(port);
|
||||||
|
|||||||
@@ -135,6 +135,8 @@ struct rockchip_rgb *rockchip_rgb_init(struct device *dev,
|
|||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
DRM_DEV_ERROR(drm_dev->dev,
|
DRM_DEV_ERROR(drm_dev->dev,
|
||||||
"failed to initialize encoder: %d\n", ret);
|
"failed to initialize encoder: %d\n", ret);
|
||||||
|
if (panel)
|
||||||
|
drm_panel_put(panel);
|
||||||
return ERR_PTR(ret);
|
return ERR_PTR(ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -143,6 +145,7 @@ struct rockchip_rgb *rockchip_rgb_init(struct device *dev,
|
|||||||
if (panel) {
|
if (panel) {
|
||||||
bridge = drm_panel_bridge_add_typed(panel,
|
bridge = drm_panel_bridge_add_typed(panel,
|
||||||
DRM_MODE_CONNECTOR_LVDS);
|
DRM_MODE_CONNECTOR_LVDS);
|
||||||
|
drm_panel_put(panel);
|
||||||
if (IS_ERR(bridge))
|
if (IS_ERR(bridge))
|
||||||
return ERR_CAST(bridge);
|
return ERR_CAST(bridge);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -498,6 +498,9 @@ static void sti_dvo_unbind(struct device *dev,
|
|||||||
{
|
{
|
||||||
struct sti_dvo *dvo = dev_get_drvdata(dev);
|
struct sti_dvo *dvo = dev_get_drvdata(dev);
|
||||||
|
|
||||||
|
if (dvo->panel)
|
||||||
|
drm_panel_put(dvo->panel);
|
||||||
|
|
||||||
drm_bridge_remove(&dvo->bridge);
|
drm_bridge_remove(&dvo->bridge);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1982,6 +1982,7 @@ int ltdc_load(struct drm_device *ddev)
|
|||||||
|
|
||||||
if (panel) {
|
if (panel) {
|
||||||
bridge = drmm_panel_bridge_add(ddev, panel);
|
bridge = drmm_panel_bridge_add(ddev, panel);
|
||||||
|
drm_panel_put(panel);
|
||||||
if (IS_ERR(bridge)) {
|
if (IS_ERR(bridge)) {
|
||||||
drm_err(ddev, "panel-bridge endpoint %d\n", i);
|
drm_err(ddev, "panel-bridge endpoint %d\n", i);
|
||||||
ret = PTR_ERR(bridge);
|
ret = PTR_ERR(bridge);
|
||||||
|
|||||||
@@ -1068,20 +1068,20 @@ static int lvds_probe(struct platform_device *pdev)
|
|||||||
if (IS_ERR(lvds->base)) {
|
if (IS_ERR(lvds->base)) {
|
||||||
ret = PTR_ERR(lvds->base);
|
ret = PTR_ERR(lvds->base);
|
||||||
dev_err(dev, "Unable to get regs %d\n", ret);
|
dev_err(dev, "Unable to get regs %d\n", ret);
|
||||||
return ret;
|
goto err_put_panel;
|
||||||
}
|
}
|
||||||
|
|
||||||
lvds->pclk = devm_clk_get(dev, "pclk");
|
lvds->pclk = devm_clk_get(dev, "pclk");
|
||||||
if (IS_ERR(lvds->pclk)) {
|
if (IS_ERR(lvds->pclk)) {
|
||||||
ret = PTR_ERR(lvds->pclk);
|
ret = PTR_ERR(lvds->pclk);
|
||||||
dev_err(dev, "Unable to get peripheral clock: %d\n", ret);
|
dev_err(dev, "Unable to get peripheral clock: %d\n", ret);
|
||||||
return ret;
|
goto err_put_panel;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = clk_prepare_enable(lvds->pclk);
|
ret = clk_prepare_enable(lvds->pclk);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
dev_err(dev, "%s: Failed to enable peripheral clk\n", __func__);
|
dev_err(dev, "%s: Failed to enable peripheral clk\n", __func__);
|
||||||
return ret;
|
goto err_put_panel;
|
||||||
}
|
}
|
||||||
|
|
||||||
rstc = devm_reset_control_get_exclusive(dev, NULL);
|
rstc = devm_reset_control_get_exclusive(dev, NULL);
|
||||||
@@ -1181,6 +1181,9 @@ static int lvds_probe(struct platform_device *pdev)
|
|||||||
|
|
||||||
err_lvds_probe:
|
err_lvds_probe:
|
||||||
clk_disable_unprepare(lvds->pclk);
|
clk_disable_unprepare(lvds->pclk);
|
||||||
|
err_put_panel:
|
||||||
|
if (lvds->panel)
|
||||||
|
drm_panel_put(lvds->panel);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
@@ -1189,6 +1192,9 @@ static void lvds_remove(struct platform_device *pdev)
|
|||||||
{
|
{
|
||||||
struct stm_lvds *lvds = platform_get_drvdata(pdev);
|
struct stm_lvds *lvds = platform_get_drvdata(pdev);
|
||||||
|
|
||||||
|
if (lvds->panel)
|
||||||
|
drm_panel_put(lvds->panel);
|
||||||
|
|
||||||
lvds_pixel_clk_unregister(lvds);
|
lvds_pixel_clk_unregister(lvds);
|
||||||
|
|
||||||
drm_bridge_remove(&lvds->lvds_bridge);
|
drm_bridge_remove(&lvds->lvds_bridge);
|
||||||
|
|||||||
@@ -18,6 +18,11 @@
|
|||||||
#include "sun4i_tcon.h"
|
#include "sun4i_tcon.h"
|
||||||
#include "sun4i_lvds.h"
|
#include "sun4i_lvds.h"
|
||||||
|
|
||||||
|
static void sun4i_panel_put_action(void *data)
|
||||||
|
{
|
||||||
|
drm_panel_put(data);
|
||||||
|
}
|
||||||
|
|
||||||
struct sun4i_lvds {
|
struct sun4i_lvds {
|
||||||
struct drm_connector connector;
|
struct drm_connector connector;
|
||||||
struct drm_encoder encoder;
|
struct drm_encoder encoder;
|
||||||
@@ -117,6 +122,14 @@ int sun4i_lvds_init(struct drm_device *drm, struct sun4i_tcon *tcon)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (lvds->panel) {
|
||||||
|
ret = devm_add_action_or_reset(tcon->dev,
|
||||||
|
sun4i_panel_put_action,
|
||||||
|
lvds->panel);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
drm_encoder_helper_add(&lvds->encoder,
|
drm_encoder_helper_add(&lvds->encoder,
|
||||||
&sun4i_lvds_enc_helper_funcs);
|
&sun4i_lvds_enc_helper_funcs);
|
||||||
ret = drm_encoder_init(drm, &lvds->encoder, &sun4i_lvds_enc_funcs,
|
ret = drm_encoder_init(drm, &lvds->encoder, &sun4i_lvds_enc_funcs,
|
||||||
|
|||||||
@@ -43,6 +43,11 @@ drm_encoder_to_sun4i_rgb(struct drm_encoder *encoder)
|
|||||||
encoder);
|
encoder);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void sun4i_panel_put_action(void *data)
|
||||||
|
{
|
||||||
|
drm_panel_put(data);
|
||||||
|
}
|
||||||
|
|
||||||
static int sun4i_rgb_get_modes(struct drm_connector *connector)
|
static int sun4i_rgb_get_modes(struct drm_connector *connector)
|
||||||
{
|
{
|
||||||
struct sun4i_rgb *rgb =
|
struct sun4i_rgb *rgb =
|
||||||
@@ -209,6 +214,14 @@ int sun4i_rgb_init(struct drm_device *drm, struct sun4i_tcon *tcon)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (rgb->panel) {
|
||||||
|
ret = devm_add_action_or_reset(tcon->dev,
|
||||||
|
sun4i_panel_put_action,
|
||||||
|
rgb->panel);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
drm_encoder_helper_add(&rgb->encoder,
|
drm_encoder_helper_add(&rgb->encoder,
|
||||||
&sun4i_rgb_enc_helper_funcs);
|
&sun4i_rgb_enc_helper_funcs);
|
||||||
ret = drm_encoder_init(drm, &rgb->encoder, &sun4i_rgb_enc_funcs,
|
ret = drm_encoder_init(drm, &rgb->encoder, &sun4i_rgb_enc_funcs,
|
||||||
|
|||||||
@@ -1326,6 +1326,8 @@ static int sun4i_tcon_probe(struct platform_device *pdev)
|
|||||||
ret = drm_of_find_panel_or_bridge(node, 1, 0, &panel, &bridge);
|
ret = drm_of_find_panel_or_bridge(node, 1, 0, &panel, &bridge);
|
||||||
if (ret == -EPROBE_DEFER)
|
if (ret == -EPROBE_DEFER)
|
||||||
return ret;
|
return ret;
|
||||||
|
if (panel)
|
||||||
|
drm_panel_put(panel);
|
||||||
}
|
}
|
||||||
|
|
||||||
return component_add(&pdev->dev, &sun4i_tcon_ops);
|
return component_add(&pdev->dev, &sun4i_tcon_ops);
|
||||||
|
|||||||
@@ -971,8 +971,10 @@ static int sun6i_dsi_attach(struct mipi_dsi_host *host,
|
|||||||
|
|
||||||
if (IS_ERR(panel))
|
if (IS_ERR(panel))
|
||||||
return PTR_ERR(panel);
|
return PTR_ERR(panel);
|
||||||
if (!dsi->drm || !dsi->drm->registered)
|
if (!dsi->drm || !dsi->drm->registered) {
|
||||||
|
drm_panel_put(panel);
|
||||||
return -EPROBE_DEFER;
|
return -EPROBE_DEFER;
|
||||||
|
}
|
||||||
|
|
||||||
dsi->panel = panel;
|
dsi->panel = panel;
|
||||||
dsi->device = device;
|
dsi->device = device;
|
||||||
@@ -989,6 +991,8 @@ static int sun6i_dsi_detach(struct mipi_dsi_host *host,
|
|||||||
{
|
{
|
||||||
struct sun6i_dsi *dsi = host_to_sun6i_dsi(host);
|
struct sun6i_dsi *dsi = host_to_sun6i_dsi(host);
|
||||||
|
|
||||||
|
if (dsi->panel)
|
||||||
|
drm_panel_put(dsi->panel);
|
||||||
dsi->panel = NULL;
|
dsi->panel = NULL;
|
||||||
dsi->device = NULL;
|
dsi->device = NULL;
|
||||||
|
|
||||||
|
|||||||
@@ -1527,6 +1527,10 @@ static int tegra_dsi_host_attach(struct mipi_dsi_host *host,
|
|||||||
if (!dsi->master) {
|
if (!dsi->master) {
|
||||||
struct tegra_output *output = &dsi->output;
|
struct tegra_output *output = &dsi->output;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* tegra_output_probe() never populates a panel for DSI
|
||||||
|
* outputs, so output->panel is always NULL here.
|
||||||
|
*/
|
||||||
output->panel = of_drm_find_panel(device->dev.of_node);
|
output->panel = of_drm_find_panel(device->dev.of_node);
|
||||||
if (IS_ERR(output->panel))
|
if (IS_ERR(output->panel))
|
||||||
output->panel = NULL;
|
output->panel = NULL;
|
||||||
@@ -1545,6 +1549,7 @@ static int tegra_dsi_host_detach(struct mipi_dsi_host *host,
|
|||||||
struct tegra_output *output = &dsi->output;
|
struct tegra_output *output = &dsi->output;
|
||||||
|
|
||||||
if (output->panel && &device->dev == output->panel->dev) {
|
if (output->panel && &device->dev == output->panel->dev) {
|
||||||
|
drm_panel_put(output->panel);
|
||||||
output->panel = NULL;
|
output->panel = NULL;
|
||||||
|
|
||||||
if (output->connector.dev)
|
if (output->connector.dev)
|
||||||
|
|||||||
@@ -117,11 +117,19 @@ int tegra_output_probe(struct tegra_output *output)
|
|||||||
*/
|
*/
|
||||||
WARN_ON(output->panel || output->bridge);
|
WARN_ON(output->panel || output->bridge);
|
||||||
|
|
||||||
|
if (output->panel) {
|
||||||
|
drm_panel_put(output->panel);
|
||||||
|
output->panel = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
output->panel = of_drm_find_panel(panel);
|
output->panel = of_drm_find_panel(panel);
|
||||||
of_node_put(panel);
|
of_node_put(panel);
|
||||||
|
|
||||||
if (IS_ERR(output->panel))
|
if (IS_ERR(output->panel)) {
|
||||||
return PTR_ERR(output->panel);
|
err = PTR_ERR(output->panel);
|
||||||
|
output->panel = NULL;
|
||||||
|
return err;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ddc = of_parse_phandle(output->of_node, "nvidia,ddc-i2c-bus", 0);
|
ddc = of_parse_phandle(output->of_node, "nvidia,ddc-i2c-bus", 0);
|
||||||
@@ -131,7 +139,7 @@ int tegra_output_probe(struct tegra_output *output)
|
|||||||
|
|
||||||
if (!output->ddc) {
|
if (!output->ddc) {
|
||||||
err = -EPROBE_DEFER;
|
err = -EPROBE_DEFER;
|
||||||
return err;
|
goto put_i2c;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -185,6 +193,11 @@ int tegra_output_probe(struct tegra_output *output)
|
|||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
put_i2c:
|
put_i2c:
|
||||||
|
if (output->panel) {
|
||||||
|
drm_panel_put(output->panel);
|
||||||
|
output->panel = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
if (output->ddc)
|
if (output->ddc)
|
||||||
i2c_put_adapter(output->ddc);
|
i2c_put_adapter(output->ddc);
|
||||||
|
|
||||||
@@ -195,6 +208,11 @@ int tegra_output_probe(struct tegra_output *output)
|
|||||||
|
|
||||||
void tegra_output_remove(struct tegra_output *output)
|
void tegra_output_remove(struct tegra_output *output)
|
||||||
{
|
{
|
||||||
|
if (output->panel) {
|
||||||
|
drm_panel_put(output->panel);
|
||||||
|
output->panel = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
if (output->hpd_gpio)
|
if (output->hpd_gpio)
|
||||||
free_irq(output->hpd_irq, output);
|
free_irq(output->hpd_irq, output);
|
||||||
|
|
||||||
|
|||||||
@@ -162,6 +162,7 @@ static int tidss_dispc_modeset_init(struct tidss_device *tidss)
|
|||||||
|
|
||||||
if (panel) {
|
if (panel) {
|
||||||
u32 conn_type;
|
u32 conn_type;
|
||||||
|
int ret;
|
||||||
|
|
||||||
dev_dbg(dev, "Setting up panel for port %d\n", i);
|
dev_dbg(dev, "Setting up panel for port %d\n", i);
|
||||||
|
|
||||||
@@ -176,7 +177,8 @@ static int tidss_dispc_modeset_init(struct tidss_device *tidss)
|
|||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
WARN_ON(1);
|
WARN_ON(1);
|
||||||
return -EINVAL;
|
ret = -EINVAL;
|
||||||
|
goto put_panel;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (panel->connector_type != conn_type) {
|
if (panel->connector_type != conn_type) {
|
||||||
@@ -184,16 +186,20 @@ static int tidss_dispc_modeset_init(struct tidss_device *tidss)
|
|||||||
"%s: Panel %s has incompatible connector type for vp%d (%d != %d)\n",
|
"%s: Panel %s has incompatible connector type for vp%d (%d != %d)\n",
|
||||||
__func__, dev_name(panel->dev), i,
|
__func__, dev_name(panel->dev), i,
|
||||||
panel->connector_type, conn_type);
|
panel->connector_type, conn_type);
|
||||||
return -EINVAL;
|
ret = -EINVAL;
|
||||||
|
goto put_panel;
|
||||||
}
|
}
|
||||||
|
|
||||||
bridge = devm_drm_panel_bridge_add(dev, panel);
|
bridge = devm_drm_panel_bridge_add(dev, panel);
|
||||||
if (IS_ERR(bridge)) {
|
ret = PTR_ERR_OR_ZERO(bridge);
|
||||||
|
if (ret)
|
||||||
dev_err(dev,
|
dev_err(dev,
|
||||||
"failed to set up panel bridge for port %d\n",
|
"failed to set up panel bridge for port %d\n",
|
||||||
i);
|
i);
|
||||||
return PTR_ERR(bridge);
|
put_panel:
|
||||||
}
|
drm_panel_put(panel);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
pipes[num_pipes].hw_videoport = i;
|
pipes[num_pipes].hw_videoport = i;
|
||||||
|
|||||||
@@ -84,6 +84,7 @@ static int tve200_modeset_init(struct drm_device *dev)
|
|||||||
if (panel) {
|
if (panel) {
|
||||||
bridge = drm_panel_bridge_add_typed(panel,
|
bridge = drm_panel_bridge_add_typed(panel,
|
||||||
DRM_MODE_CONNECTOR_Unknown);
|
DRM_MODE_CONNECTOR_Unknown);
|
||||||
|
drm_panel_put(panel);
|
||||||
if (IS_ERR(bridge)) {
|
if (IS_ERR(bridge)) {
|
||||||
ret = PTR_ERR(bridge);
|
ret = PTR_ERR(bridge);
|
||||||
goto out_bridge;
|
goto out_bridge;
|
||||||
|
|||||||
Reference in New Issue
Block a user