mirror of
https://github.com/openwrt/openwrt.git
synced 2024-12-26 17:01:14 +00:00
360 lines
11 KiB
Diff
360 lines
11 KiB
Diff
|
From 5f391cd6c90a53c7095bf22a308081d19a6cb8e2 Mon Sep 17 00:00:00 2001
|
||
|
From: Nick Hollinghurst <nick.hollinghurst@raspberrypi.com>
|
||
|
Date: Sat, 3 Feb 2024 12:04:00 +0000
|
||
|
Subject: [PATCH 0883/1085] drm: rp1: VEC and DPI drivers: Fix bug #5901
|
||
|
|
||
|
Rework probe() to use devm_drm_dev_alloc(), embedding the DRM
|
||
|
device in the DPI or VEC device as now seems to be recommended.
|
||
|
|
||
|
Change order of resource allocation and driver initialization.
|
||
|
This prevents it trying to write to an unmapped register during
|
||
|
clean-up, which previously could crash.
|
||
|
|
||
|
Signed-off-by: Nick Hollinghurst <nick.hollinghurst@raspberrypi.com>
|
||
|
---
|
||
|
drivers/gpu/drm/rp1/rp1-dpi/rp1_dpi.c | 74 +++++++++------------
|
||
|
drivers/gpu/drm/rp1/rp1-dpi/rp1_dpi.h | 4 +-
|
||
|
drivers/gpu/drm/rp1/rp1-dpi/rp1_dpi_hw.c | 4 +-
|
||
|
drivers/gpu/drm/rp1/rp1-vec/rp1_vec.c | 82 +++++++++++-------------
|
||
|
drivers/gpu/drm/rp1/rp1-vec/rp1_vec.h | 4 +-
|
||
|
drivers/gpu/drm/rp1/rp1-vec/rp1_vec_hw.c | 2 +-
|
||
|
6 files changed, 75 insertions(+), 95 deletions(-)
|
||
|
|
||
|
--- a/drivers/gpu/drm/rp1/rp1-dpi/rp1_dpi.c
|
||
|
+++ b/drivers/gpu/drm/rp1/rp1-dpi/rp1_dpi.c
|
||
|
@@ -268,7 +268,6 @@ static const u32 rp1dpi_formats[] = {
|
||
|
static int rp1dpi_platform_probe(struct platform_device *pdev)
|
||
|
{
|
||
|
struct device *dev = &pdev->dev;
|
||
|
- struct drm_device *drm;
|
||
|
struct rp1_dpi *dpi;
|
||
|
struct drm_bridge *bridge = NULL;
|
||
|
struct drm_panel *panel;
|
||
|
@@ -287,24 +286,13 @@ static int rp1dpi_platform_probe(struct
|
||
|
return PTR_ERR(bridge);
|
||
|
}
|
||
|
|
||
|
- drm = drm_dev_alloc(&rp1dpi_driver, dev);
|
||
|
- if (IS_ERR(drm)) {
|
||
|
- dev_info(dev, "%s %d", __func__, (int)__LINE__);
|
||
|
- ret = PTR_ERR(drm);
|
||
|
+ dpi = devm_drm_dev_alloc(dev, &rp1dpi_driver, struct rp1_dpi, drm);
|
||
|
+ if (IS_ERR(dpi)) {
|
||
|
+ ret = PTR_ERR(dpi);
|
||
|
+ dev_err(dev, "%s devm_drm_dev_alloc %d", __func__, ret);
|
||
|
return ret;
|
||
|
}
|
||
|
- dpi = drmm_kzalloc(drm, sizeof(*dpi), GFP_KERNEL);
|
||
|
- if (!dpi) {
|
||
|
- dev_info(dev, "%s %d", __func__, (int)__LINE__);
|
||
|
- drm_dev_put(drm);
|
||
|
- return -ENOMEM;
|
||
|
- }
|
||
|
-
|
||
|
- init_completion(&dpi->finished);
|
||
|
- dpi->drm = drm;
|
||
|
dpi->pdev = pdev;
|
||
|
- drm->dev_private = dpi;
|
||
|
- platform_set_drvdata(pdev, drm);
|
||
|
|
||
|
dpi->bus_fmt = default_bus_fmt;
|
||
|
ret = of_property_read_u32(dev->of_node, "default_bus_fmt", &dpi->bus_fmt);
|
||
|
@@ -314,9 +302,8 @@ static int rp1dpi_platform_probe(struct
|
||
|
devm_ioremap_resource(dev,
|
||
|
platform_get_resource(dpi->pdev, IORESOURCE_MEM, i));
|
||
|
if (IS_ERR(dpi->hw_base[i])) {
|
||
|
- ret = PTR_ERR(dpi->hw_base[i]);
|
||
|
dev_err(dev, "Error memory mapping regs[%d]\n", i);
|
||
|
- goto err_free_drm;
|
||
|
+ return PTR_ERR(dpi->hw_base[i]);
|
||
|
}
|
||
|
}
|
||
|
ret = platform_get_irq(dpi->pdev, 0);
|
||
|
@@ -325,10 +312,8 @@ static int rp1dpi_platform_probe(struct
|
||
|
IRQF_SHARED, "rp1-dpi", dpi);
|
||
|
if (ret) {
|
||
|
dev_err(dev, "Unable to request interrupt\n");
|
||
|
- ret = -EINVAL;
|
||
|
- goto err_free_drm;
|
||
|
+ return -EINVAL;
|
||
|
}
|
||
|
- dma_set_mask_and_coherent(dev, DMA_BIT_MASK(64));
|
||
|
|
||
|
for (i = 0; i < RP1DPI_NUM_CLOCKS; i++) {
|
||
|
static const char * const myclocknames[RP1DPI_NUM_CLOCKS] = {
|
||
|
@@ -336,24 +321,30 @@ static int rp1dpi_platform_probe(struct
|
||
|
};
|
||
|
dpi->clocks[i] = devm_clk_get(dev, myclocknames[i]);
|
||
|
if (IS_ERR(dpi->clocks[i])) {
|
||
|
- ret = PTR_ERR(dpi->clocks[i]);
|
||
|
- goto err_free_drm;
|
||
|
+ dev_err(dev, "Unable to request clock %s\n", myclocknames[i]);
|
||
|
+ return PTR_ERR(dpi->clocks[i]);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
- ret = drmm_mode_config_init(drm);
|
||
|
+ ret = drmm_mode_config_init(&dpi->drm);
|
||
|
if (ret)
|
||
|
- goto err_free_drm;
|
||
|
+ goto done_err;
|
||
|
|
||
|
- drm->mode_config.max_width = 4096;
|
||
|
- drm->mode_config.max_height = 4096;
|
||
|
- drm->mode_config.preferred_depth = 32;
|
||
|
- drm->mode_config.prefer_shadow = 0;
|
||
|
- drm->mode_config.quirk_addfb_prefer_host_byte_order = true;
|
||
|
- drm->mode_config.funcs = &rp1dpi_mode_funcs;
|
||
|
- drm_vblank_init(drm, 1);
|
||
|
+ /* Now we have all our resources, finish driver initialization */
|
||
|
+ dma_set_mask_and_coherent(dev, DMA_BIT_MASK(64));
|
||
|
+ init_completion(&dpi->finished);
|
||
|
+ dpi->drm.dev_private = dpi;
|
||
|
+ platform_set_drvdata(pdev, &dpi->drm);
|
||
|
+
|
||
|
+ dpi->drm.mode_config.max_width = 4096;
|
||
|
+ dpi->drm.mode_config.max_height = 4096;
|
||
|
+ dpi->drm.mode_config.preferred_depth = 32;
|
||
|
+ dpi->drm.mode_config.prefer_shadow = 0;
|
||
|
+ dpi->drm.mode_config.quirk_addfb_prefer_host_byte_order = true;
|
||
|
+ dpi->drm.mode_config.funcs = &rp1dpi_mode_funcs;
|
||
|
+ drm_vblank_init(&dpi->drm, 1);
|
||
|
|
||
|
- ret = drm_simple_display_pipe_init(drm,
|
||
|
+ ret = drm_simple_display_pipe_init(&dpi->drm,
|
||
|
&dpi->pipe,
|
||
|
&rp1dpi_pipe_funcs,
|
||
|
rp1dpi_formats,
|
||
|
@@ -362,22 +353,19 @@ static int rp1dpi_platform_probe(struct
|
||
|
if (!ret)
|
||
|
ret = drm_simple_display_pipe_attach_bridge(&dpi->pipe, bridge);
|
||
|
if (ret)
|
||
|
- goto err_free_drm;
|
||
|
+ goto done_err;
|
||
|
|
||
|
- drm_mode_config_reset(drm);
|
||
|
+ drm_mode_config_reset(&dpi->drm);
|
||
|
|
||
|
- ret = drm_dev_register(drm, 0);
|
||
|
+ ret = drm_dev_register(&dpi->drm, 0);
|
||
|
if (ret)
|
||
|
- goto err_free_drm;
|
||
|
-
|
||
|
- drm_fbdev_generic_setup(drm, 32);
|
||
|
+ return ret;
|
||
|
|
||
|
- dev_info(dev, "%s success\n", __func__);
|
||
|
+ drm_fbdev_generic_setup(&dpi->drm, 32);
|
||
|
return ret;
|
||
|
|
||
|
-err_free_drm:
|
||
|
+done_err:
|
||
|
dev_err(dev, "%s fail %d\n", __func__, ret);
|
||
|
- drm_dev_put(drm);
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
--- a/drivers/gpu/drm/rp1/rp1-dpi/rp1_dpi.h
|
||
|
+++ b/drivers/gpu/drm/rp1/rp1-dpi/rp1_dpi.h
|
||
|
@@ -28,8 +28,8 @@
|
||
|
/* ---------------------------------------------------------------------- */
|
||
|
|
||
|
struct rp1_dpi {
|
||
|
- /* DRM and platform device pointers */
|
||
|
- struct drm_device *drm;
|
||
|
+ /* DRM base and platform device pointer */
|
||
|
+ struct drm_device drm;
|
||
|
struct platform_device *pdev;
|
||
|
|
||
|
/* Framework and helper objects */
|
||
|
--- a/drivers/gpu/drm/rp1/rp1-dpi/rp1_dpi_hw.c
|
||
|
+++ b/drivers/gpu/drm/rp1/rp1-dpi/rp1_dpi_hw.c
|
||
|
@@ -451,7 +451,7 @@ void rp1dpi_hw_stop(struct rp1_dpi *dpi)
|
||
|
ctrl &= ~(DPI_DMA_CONTROL_ARM_MASK | DPI_DMA_CONTROL_AUTO_REPEAT_MASK);
|
||
|
rp1dpi_hw_write(dpi, DPI_DMA_CONTROL, ctrl);
|
||
|
if (!wait_for_completion_timeout(&dpi->finished, HZ / 10))
|
||
|
- drm_err(dpi->drm, "%s: timed out waiting for idle\n", __func__);
|
||
|
+ drm_err(&dpi->drm, "%s: timed out waiting for idle\n", __func__);
|
||
|
rp1dpi_hw_write(dpi, DPI_DMA_IRQ_EN, 0);
|
||
|
}
|
||
|
|
||
|
@@ -473,7 +473,7 @@ irqreturn_t rp1dpi_hw_isr(int irq, void
|
||
|
rp1dpi_hw_write(dpi, DPI_DMA_IRQ_FLAGS, u);
|
||
|
if (dpi) {
|
||
|
if (u & DPI_DMA_IRQ_FLAGS_UNDERFLOW_MASK)
|
||
|
- drm_err_ratelimited(dpi->drm,
|
||
|
+ drm_err_ratelimited(&dpi->drm,
|
||
|
"Underflow! (panics=0x%08x)\n",
|
||
|
rp1dpi_hw_read(dpi, DPI_DMA_PANICS));
|
||
|
if (u & DPI_DMA_IRQ_FLAGS_DMA_READY_MASK)
|
||
|
--- a/drivers/gpu/drm/rp1/rp1-vec/rp1_vec.c
|
||
|
+++ b/drivers/gpu/drm/rp1/rp1-vec/rp1_vec.c
|
||
|
@@ -361,29 +361,17 @@ static struct drm_driver rp1vec_driver =
|
||
|
static int rp1vec_platform_probe(struct platform_device *pdev)
|
||
|
{
|
||
|
struct device *dev = &pdev->dev;
|
||
|
- struct drm_device *drm;
|
||
|
struct rp1_vec *vec;
|
||
|
int i, ret;
|
||
|
|
||
|
dev_info(dev, __func__);
|
||
|
- drm = drm_dev_alloc(&rp1vec_driver, dev);
|
||
|
- if (IS_ERR(drm)) {
|
||
|
- ret = PTR_ERR(drm);
|
||
|
- dev_err(dev, "%s drm_dev_alloc %d", __func__, ret);
|
||
|
+ vec = devm_drm_dev_alloc(dev, &rp1vec_driver, struct rp1_vec, drm);
|
||
|
+ if (IS_ERR(vec)) {
|
||
|
+ ret = PTR_ERR(vec);
|
||
|
+ dev_err(dev, "%s devm_drm_dev_alloc %d", __func__, ret);
|
||
|
return ret;
|
||
|
}
|
||
|
-
|
||
|
- vec = drmm_kzalloc(drm, sizeof(*vec), GFP_KERNEL);
|
||
|
- if (!vec) {
|
||
|
- dev_err(dev, "%s drmm_kzalloc failed", __func__);
|
||
|
- ret = -ENOMEM;
|
||
|
- goto err_free_drm;
|
||
|
- }
|
||
|
- init_completion(&vec->finished);
|
||
|
- vec->drm = drm;
|
||
|
vec->pdev = pdev;
|
||
|
- drm->dev_private = vec;
|
||
|
- platform_set_drvdata(pdev, drm);
|
||
|
|
||
|
for (i = 0; i < RP1VEC_NUM_HW_BLOCKS; i++) {
|
||
|
vec->hw_base[i] =
|
||
|
@@ -392,7 +380,7 @@ static int rp1vec_platform_probe(struct
|
||
|
if (IS_ERR(vec->hw_base[i])) {
|
||
|
ret = PTR_ERR(vec->hw_base[i]);
|
||
|
dev_err(dev, "Error memory mapping regs[%d]\n", i);
|
||
|
- goto err_free_drm;
|
||
|
+ goto done_err;
|
||
|
}
|
||
|
}
|
||
|
ret = platform_get_irq(vec->pdev, 0);
|
||
|
@@ -402,48 +390,53 @@ static int rp1vec_platform_probe(struct
|
||
|
if (ret) {
|
||
|
dev_err(dev, "Unable to request interrupt\n");
|
||
|
ret = -EINVAL;
|
||
|
- goto err_free_drm;
|
||
|
+ goto done_err;
|
||
|
}
|
||
|
- dma_set_mask_and_coherent(dev, DMA_BIT_MASK(64));
|
||
|
|
||
|
vec->vec_clock = devm_clk_get(dev, NULL);
|
||
|
if (IS_ERR(vec->vec_clock)) {
|
||
|
ret = PTR_ERR(vec->vec_clock);
|
||
|
- goto err_free_drm;
|
||
|
+ goto done_err;
|
||
|
}
|
||
|
ret = clk_prepare_enable(vec->vec_clock);
|
||
|
|
||
|
- ret = drmm_mode_config_init(drm);
|
||
|
+ ret = drmm_mode_config_init(&vec->drm);
|
||
|
if (ret)
|
||
|
- goto err_free_drm;
|
||
|
- drm->mode_config.max_width = 800;
|
||
|
- drm->mode_config.max_height = 576;
|
||
|
- drm->mode_config.preferred_depth = 32;
|
||
|
- drm->mode_config.prefer_shadow = 0;
|
||
|
- //drm->mode_config.fbdev_use_iomem = false;
|
||
|
- drm->mode_config.quirk_addfb_prefer_host_byte_order = true;
|
||
|
- drm->mode_config.funcs = &rp1vec_mode_funcs;
|
||
|
- drm_vblank_init(drm, 1);
|
||
|
+ goto done_err;
|
||
|
+
|
||
|
+ /* Now we have all our resources, finish driver initialization */
|
||
|
+ dma_set_mask_and_coherent(dev, DMA_BIT_MASK(64));
|
||
|
+ init_completion(&vec->finished);
|
||
|
+ vec->drm.dev_private = vec;
|
||
|
+ platform_set_drvdata(pdev, &vec->drm);
|
||
|
+
|
||
|
+ vec->drm.mode_config.max_width = 800;
|
||
|
+ vec->drm.mode_config.max_height = 576;
|
||
|
+ vec->drm.mode_config.preferred_depth = 32;
|
||
|
+ vec->drm.mode_config.prefer_shadow = 0;
|
||
|
+ vec->drm.mode_config.quirk_addfb_prefer_host_byte_order = true;
|
||
|
+ vec->drm.mode_config.funcs = &rp1vec_mode_funcs;
|
||
|
+ drm_vblank_init(&vec->drm, 1);
|
||
|
|
||
|
- ret = drm_mode_create_tv_properties(drm, RP1VEC_SUPPORTED_TV_MODES);
|
||
|
+ ret = drm_mode_create_tv_properties(&vec->drm, RP1VEC_SUPPORTED_TV_MODES);
|
||
|
if (ret)
|
||
|
- goto err_free_drm;
|
||
|
+ goto done_err;
|
||
|
|
||
|
- drm_connector_init(drm, &vec->connector, &rp1vec_connector_funcs,
|
||
|
+ drm_connector_init(&vec->drm, &vec->connector, &rp1vec_connector_funcs,
|
||
|
DRM_MODE_CONNECTOR_Composite);
|
||
|
if (ret)
|
||
|
- goto err_free_drm;
|
||
|
+ goto done_err;
|
||
|
|
||
|
vec->connector.interlace_allowed = true;
|
||
|
drm_connector_helper_add(&vec->connector, &rp1vec_connector_helper_funcs);
|
||
|
|
||
|
drm_object_attach_property(&vec->connector.base,
|
||
|
- drm->mode_config.tv_mode_property,
|
||
|
+ vec->drm.mode_config.tv_mode_property,
|
||
|
(vec->connector.cmdline_mode.tv_mode_specified) ?
|
||
|
vec->connector.cmdline_mode.tv_mode :
|
||
|
DRM_MODE_TV_MODE_NTSC);
|
||
|
|
||
|
- ret = drm_simple_display_pipe_init(drm,
|
||
|
+ ret = drm_simple_display_pipe_init(&vec->drm,
|
||
|
&vec->pipe,
|
||
|
&rp1vec_pipe_funcs,
|
||
|
rp1vec_formats,
|
||
|
@@ -451,20 +444,19 @@ static int rp1vec_platform_probe(struct
|
||
|
NULL,
|
||
|
&vec->connector);
|
||
|
if (ret)
|
||
|
- goto err_free_drm;
|
||
|
+ goto done_err;
|
||
|
|
||
|
- drm_mode_config_reset(drm);
|
||
|
+ drm_mode_config_reset(&vec->drm);
|
||
|
|
||
|
- ret = drm_dev_register(drm, 0);
|
||
|
+ ret = drm_dev_register(&vec->drm, 0);
|
||
|
if (ret)
|
||
|
- goto err_free_drm;
|
||
|
+ goto done_err;
|
||
|
|
||
|
- drm_fbdev_generic_setup(drm, 32); /* the "32" is preferred BPP */
|
||
|
+ drm_fbdev_generic_setup(&vec->drm, 32);
|
||
|
return ret;
|
||
|
|
||
|
-err_free_drm:
|
||
|
- dev_info(dev, "%s fail %d", __func__, ret);
|
||
|
- drm_dev_put(drm);
|
||
|
+done_err:
|
||
|
+ dev_err(dev, "%s fail %d", __func__, ret);
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
--- a/drivers/gpu/drm/rp1/rp1-vec/rp1_vec.h
|
||
|
+++ b/drivers/gpu/drm/rp1/rp1-vec/rp1_vec.h
|
||
|
@@ -31,8 +31,8 @@
|
||
|
/* ---------------------------------------------------------------------- */
|
||
|
|
||
|
struct rp1_vec {
|
||
|
- /* DRM and platform device pointers */
|
||
|
- struct drm_device *drm;
|
||
|
+ /* DRM base and platform device pointer */
|
||
|
+ struct drm_device drm;
|
||
|
struct platform_device *pdev;
|
||
|
|
||
|
/* Framework and helper objects */
|
||
|
--- a/drivers/gpu/drm/rp1/rp1-vec/rp1_vec_hw.c
|
||
|
+++ b/drivers/gpu/drm/rp1/rp1-vec/rp1_vec_hw.c
|
||
|
@@ -480,7 +480,7 @@ void rp1vec_hw_stop(struct rp1_vec *vec)
|
||
|
reinit_completion(&vec->finished);
|
||
|
VEC_WRITE(VEC_CONTROL, 0);
|
||
|
if (!wait_for_completion_timeout(&vec->finished, HZ / 10))
|
||
|
- drm_err(vec->drm, "%s: timed out waiting for idle\n", __func__);
|
||
|
+ drm_err(&vec->drm, "%s: timed out waiting for idle\n", __func__);
|
||
|
VEC_WRITE(VEC_IRQ_ENABLES, 0);
|
||
|
}
|
||
|
|