Commit c3ca9839 authored by Douglas Anderson's avatar Douglas Anderson

drm/ingenic: Call drm_atomic_helper_shutdown() at shutdown time

Based on grepping through the source code this driver appears to be
missing a call to drm_atomic_helper_shutdown() at system shutdown
time. Among other things, this means that if a panel is in use that it
won't be cleanly powered off at system shutdown time.

The fact that we should call drm_atomic_helper_shutdown() in the case
of OS shutdown/restart comes straight out of the kernel doc "driver
instance overview" in drm_drv.c.

Since this driver uses the component model and shutdown happens at the
base driver, we communicate whether we have to call
drm_atomic_helper_shutdown() by seeing if drvdata is non-NULL.
Suggested-by: default avatarMaxime Ripard <mripard@kernel.org>
Acked-by: default avatarPaul Cercueil <paul@crapouillou.net>
Reviewed-by: default avatarMaxime Ripard <mripard@kernel.org>
Signed-off-by: default avatarDouglas Anderson <dianders@chromium.org>
Link: https://patchwork.freedesktop.org/patch/msgid/20230901164111.RFT.3.Iea742f06d8bec41598aa40378fc625fbd7e8a3d6@changeid
parent 02680d71
...@@ -1130,7 +1130,7 @@ static int ingenic_drm_bind(struct device *dev, bool has_components) ...@@ -1130,7 +1130,7 @@ static int ingenic_drm_bind(struct device *dev, bool has_components)
ret = drmm_mode_config_init(drm); ret = drmm_mode_config_init(drm);
if (ret) if (ret)
return ret; goto err_drvdata;
drm->mode_config.min_width = 0; drm->mode_config.min_width = 0;
drm->mode_config.min_height = 0; drm->mode_config.min_height = 0;
...@@ -1142,7 +1142,8 @@ static int ingenic_drm_bind(struct device *dev, bool has_components) ...@@ -1142,7 +1142,8 @@ static int ingenic_drm_bind(struct device *dev, bool has_components)
base = devm_platform_get_and_ioremap_resource(pdev, 0, &res); base = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
if (IS_ERR(base)) { if (IS_ERR(base)) {
dev_err(dev, "Failed to get memory resource\n"); dev_err(dev, "Failed to get memory resource\n");
return PTR_ERR(base); ret = PTR_ERR(base);
goto err_drvdata;
} }
regmap_config = ingenic_drm_regmap_config; regmap_config = ingenic_drm_regmap_config;
...@@ -1151,33 +1152,40 @@ static int ingenic_drm_bind(struct device *dev, bool has_components) ...@@ -1151,33 +1152,40 @@ static int ingenic_drm_bind(struct device *dev, bool has_components)
&regmap_config); &regmap_config);
if (IS_ERR(priv->map)) { if (IS_ERR(priv->map)) {
dev_err(dev, "Failed to create regmap\n"); dev_err(dev, "Failed to create regmap\n");
return PTR_ERR(priv->map); ret = PTR_ERR(priv->map);
goto err_drvdata;
} }
irq = platform_get_irq(pdev, 0); irq = platform_get_irq(pdev, 0);
if (irq < 0) if (irq < 0) {
return irq; ret = irq;
goto err_drvdata;
}
if (soc_info->needs_dev_clk) { if (soc_info->needs_dev_clk) {
priv->lcd_clk = devm_clk_get(dev, "lcd"); priv->lcd_clk = devm_clk_get(dev, "lcd");
if (IS_ERR(priv->lcd_clk)) { if (IS_ERR(priv->lcd_clk)) {
dev_err(dev, "Failed to get lcd clock\n"); dev_err(dev, "Failed to get lcd clock\n");
return PTR_ERR(priv->lcd_clk); ret = PTR_ERR(priv->lcd_clk);
goto err_drvdata;
} }
} }
priv->pix_clk = devm_clk_get(dev, "lcd_pclk"); priv->pix_clk = devm_clk_get(dev, "lcd_pclk");
if (IS_ERR(priv->pix_clk)) { if (IS_ERR(priv->pix_clk)) {
dev_err(dev, "Failed to get pixel clock\n"); dev_err(dev, "Failed to get pixel clock\n");
return PTR_ERR(priv->pix_clk); ret = PTR_ERR(priv->pix_clk);
goto err_drvdata;
} }
priv->dma_hwdescs = dmam_alloc_coherent(dev, priv->dma_hwdescs = dmam_alloc_coherent(dev,
sizeof(*priv->dma_hwdescs), sizeof(*priv->dma_hwdescs),
&priv->dma_hwdescs_phys, &priv->dma_hwdescs_phys,
GFP_KERNEL); GFP_KERNEL);
if (!priv->dma_hwdescs) if (!priv->dma_hwdescs) {
return -ENOMEM; ret = -ENOMEM;
goto err_drvdata;
}
/* Configure DMA hwdesc for foreground0 plane */ /* Configure DMA hwdesc for foreground0 plane */
ingenic_drm_configure_hwdesc_plane(priv, 0); ingenic_drm_configure_hwdesc_plane(priv, 0);
...@@ -1199,7 +1207,7 @@ static int ingenic_drm_bind(struct device *dev, bool has_components) ...@@ -1199,7 +1207,7 @@ static int ingenic_drm_bind(struct device *dev, bool has_components)
NULL, DRM_PLANE_TYPE_PRIMARY, NULL); NULL, DRM_PLANE_TYPE_PRIMARY, NULL);
if (ret) { if (ret) {
dev_err(dev, "Failed to register plane: %i\n", ret); dev_err(dev, "Failed to register plane: %i\n", ret);
return ret; goto err_drvdata;
} }
if (soc_info->map_noncoherent) if (soc_info->map_noncoherent)
...@@ -1211,7 +1219,7 @@ static int ingenic_drm_bind(struct device *dev, bool has_components) ...@@ -1211,7 +1219,7 @@ static int ingenic_drm_bind(struct device *dev, bool has_components)
NULL, &ingenic_drm_crtc_funcs, NULL); NULL, &ingenic_drm_crtc_funcs, NULL);
if (ret) { if (ret) {
dev_err(dev, "Failed to init CRTC: %i\n", ret); dev_err(dev, "Failed to init CRTC: %i\n", ret);
return ret; goto err_drvdata;
} }
drm_crtc_enable_color_mgmt(&priv->crtc, 0, false, drm_crtc_enable_color_mgmt(&priv->crtc, 0, false,
...@@ -1230,7 +1238,7 @@ static int ingenic_drm_bind(struct device *dev, bool has_components) ...@@ -1230,7 +1238,7 @@ static int ingenic_drm_bind(struct device *dev, bool has_components)
if (ret) { if (ret) {
dev_err(dev, "Failed to register overlay plane: %i\n", dev_err(dev, "Failed to register overlay plane: %i\n",
ret); ret);
return ret; goto err_drvdata;
} }
if (soc_info->map_noncoherent) if (soc_info->map_noncoherent)
...@@ -1241,17 +1249,18 @@ static int ingenic_drm_bind(struct device *dev, bool has_components) ...@@ -1241,17 +1249,18 @@ static int ingenic_drm_bind(struct device *dev, bool has_components)
if (ret) { if (ret) {
if (ret != -EPROBE_DEFER) if (ret != -EPROBE_DEFER)
dev_err(dev, "Failed to bind components: %i\n", ret); dev_err(dev, "Failed to bind components: %i\n", ret);
return ret; goto err_drvdata;
} }
ret = devm_add_action_or_reset(dev, ingenic_drm_unbind_all, priv); ret = devm_add_action_or_reset(dev, ingenic_drm_unbind_all, priv);
if (ret) if (ret)
return ret; goto err_drvdata;
priv->ipu_plane = drm_plane_from_index(drm, 2); priv->ipu_plane = drm_plane_from_index(drm, 2);
if (!priv->ipu_plane) { if (!priv->ipu_plane) {
dev_err(dev, "Failed to retrieve IPU plane\n"); dev_err(dev, "Failed to retrieve IPU plane\n");
return -EINVAL; ret = -EINVAL;
goto err_drvdata;
} }
} }
} }
...@@ -1263,7 +1272,7 @@ static int ingenic_drm_bind(struct device *dev, bool has_components) ...@@ -1263,7 +1272,7 @@ static int ingenic_drm_bind(struct device *dev, bool has_components)
break; /* we're done */ break; /* we're done */
if (ret != -EPROBE_DEFER) if (ret != -EPROBE_DEFER)
dev_err(dev, "Failed to get bridge handle\n"); dev_err(dev, "Failed to get bridge handle\n");
return ret; goto err_drvdata;
} }
if (panel) if (panel)
...@@ -1275,7 +1284,7 @@ static int ingenic_drm_bind(struct device *dev, bool has_components) ...@@ -1275,7 +1284,7 @@ static int ingenic_drm_bind(struct device *dev, bool has_components)
if (IS_ERR(ib)) { if (IS_ERR(ib)) {
ret = PTR_ERR(ib); ret = PTR_ERR(ib);
dev_err(dev, "Failed to init encoder: %d\n", ret); dev_err(dev, "Failed to init encoder: %d\n", ret);
return ret; goto err_drvdata;
} }
encoder = &ib->encoder; encoder = &ib->encoder;
...@@ -1290,13 +1299,14 @@ static int ingenic_drm_bind(struct device *dev, bool has_components) ...@@ -1290,13 +1299,14 @@ static int ingenic_drm_bind(struct device *dev, bool has_components)
DRM_BRIDGE_ATTACH_NO_CONNECTOR); DRM_BRIDGE_ATTACH_NO_CONNECTOR);
if (ret) { if (ret) {
dev_err(dev, "Unable to attach bridge\n"); dev_err(dev, "Unable to attach bridge\n");
return ret; goto err_drvdata;
} }
connector = drm_bridge_connector_init(drm, encoder); connector = drm_bridge_connector_init(drm, encoder);
if (IS_ERR(connector)) { if (IS_ERR(connector)) {
dev_err(dev, "Unable to init connector\n"); dev_err(dev, "Unable to init connector\n");
return PTR_ERR(connector); ret = PTR_ERR(connector);
goto err_drvdata;
} }
drm_connector_attach_encoder(connector, encoder); drm_connector_attach_encoder(connector, encoder);
...@@ -1313,13 +1323,13 @@ static int ingenic_drm_bind(struct device *dev, bool has_components) ...@@ -1313,13 +1323,13 @@ static int ingenic_drm_bind(struct device *dev, bool has_components)
ret = devm_request_irq(dev, irq, ingenic_drm_irq_handler, 0, drm->driver->name, drm); ret = devm_request_irq(dev, irq, ingenic_drm_irq_handler, 0, drm->driver->name, drm);
if (ret) { if (ret) {
dev_err(dev, "Unable to install IRQ handler\n"); dev_err(dev, "Unable to install IRQ handler\n");
return ret; goto err_drvdata;
} }
ret = drm_vblank_init(drm, 1); ret = drm_vblank_init(drm, 1);
if (ret) { if (ret) {
dev_err(dev, "Failed calling drm_vblank_init()\n"); dev_err(dev, "Failed calling drm_vblank_init()\n");
return ret; goto err_drvdata;
} }
drm_mode_config_reset(drm); drm_mode_config_reset(drm);
...@@ -1327,7 +1337,7 @@ static int ingenic_drm_bind(struct device *dev, bool has_components) ...@@ -1327,7 +1337,7 @@ static int ingenic_drm_bind(struct device *dev, bool has_components)
ret = clk_prepare_enable(priv->pix_clk); ret = clk_prepare_enable(priv->pix_clk);
if (ret) { if (ret) {
dev_err(dev, "Unable to start pixel clock\n"); dev_err(dev, "Unable to start pixel clock\n");
return ret; goto err_drvdata;
} }
if (priv->lcd_clk) { if (priv->lcd_clk) {
...@@ -1402,6 +1412,8 @@ static int ingenic_drm_bind(struct device *dev, bool has_components) ...@@ -1402,6 +1412,8 @@ static int ingenic_drm_bind(struct device *dev, bool has_components)
clk_disable_unprepare(priv->lcd_clk); clk_disable_unprepare(priv->lcd_clk);
err_pixclk_disable: err_pixclk_disable:
clk_disable_unprepare(priv->pix_clk); clk_disable_unprepare(priv->pix_clk);
err_drvdata:
platform_set_drvdata(pdev, NULL);
return ret; return ret;
} }
...@@ -1422,6 +1434,7 @@ static void ingenic_drm_unbind(struct device *dev) ...@@ -1422,6 +1434,7 @@ static void ingenic_drm_unbind(struct device *dev)
drm_dev_unregister(&priv->drm); drm_dev_unregister(&priv->drm);
drm_atomic_helper_shutdown(&priv->drm); drm_atomic_helper_shutdown(&priv->drm);
dev_set_drvdata(dev, NULL);
} }
static const struct component_master_ops ingenic_master_ops = { static const struct component_master_ops ingenic_master_ops = {
...@@ -1459,6 +1472,14 @@ static void ingenic_drm_remove(struct platform_device *pdev) ...@@ -1459,6 +1472,14 @@ static void ingenic_drm_remove(struct platform_device *pdev)
component_master_del(dev, &ingenic_master_ops); component_master_del(dev, &ingenic_master_ops);
} }
static void ingenic_drm_shutdown(struct platform_device *pdev)
{
struct ingenic_drm *priv = platform_get_drvdata(pdev);
if (priv)
drm_atomic_helper_shutdown(&priv->drm);
}
static int ingenic_drm_suspend(struct device *dev) static int ingenic_drm_suspend(struct device *dev)
{ {
struct ingenic_drm *priv = dev_get_drvdata(dev); struct ingenic_drm *priv = dev_get_drvdata(dev);
...@@ -1610,6 +1631,7 @@ static struct platform_driver ingenic_drm_driver = { ...@@ -1610,6 +1631,7 @@ static struct platform_driver ingenic_drm_driver = {
}, },
.probe = ingenic_drm_probe, .probe = ingenic_drm_probe,
.remove_new = ingenic_drm_remove, .remove_new = ingenic_drm_remove,
.shutdown = ingenic_drm_shutdown,
}; };
static int ingenic_drm_init(void) static int ingenic_drm_init(void)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment