mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-09-14 06:35:12 +00:00
drm: xlnx: zynqmp_dpsub: Manage DP and DISP allocations manually
The zynqmp_disp and zynqmp_dp structures are allocated with drmm_kzalloc(). While this simplifies management of memory, it requires a DRM device, which will not be available at probe time when the DP bridge will be used standalone, with a DRM device in the PL. To prepare for this, switch to manual allocation for zynqmp_disp and zynqmp_dp. The cleanup still uses the DRM managed infrastructure, but one level up, at the top level. This will be addressed separately. Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
This commit is contained in:
parent
5889ee5903
commit
6ca91bb43a
5 changed files with 57 additions and 30 deletions
|
@ -12,7 +12,6 @@
|
||||||
#include <drm/drm_fb_dma_helper.h>
|
#include <drm/drm_fb_dma_helper.h>
|
||||||
#include <drm/drm_fourcc.h>
|
#include <drm/drm_fourcc.h>
|
||||||
#include <drm/drm_framebuffer.h>
|
#include <drm/drm_framebuffer.h>
|
||||||
#include <drm/drm_managed.h>
|
|
||||||
#include <drm/drm_plane.h>
|
#include <drm/drm_plane.h>
|
||||||
|
|
||||||
#include <linux/clk.h>
|
#include <linux/clk.h>
|
||||||
|
@ -22,6 +21,7 @@
|
||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
#include <linux/of.h>
|
#include <linux/of.h>
|
||||||
#include <linux/platform_device.h>
|
#include <linux/platform_device.h>
|
||||||
|
#include <linux/slab.h>
|
||||||
|
|
||||||
#include "zynqmp_disp.h"
|
#include "zynqmp_disp.h"
|
||||||
#include "zynqmp_disp_regs.h"
|
#include "zynqmp_disp_regs.h"
|
||||||
|
@ -1225,7 +1225,7 @@ int zynqmp_disp_setup_clock(struct zynqmp_disp *disp,
|
||||||
* Initialization & Cleanup
|
* Initialization & Cleanup
|
||||||
*/
|
*/
|
||||||
|
|
||||||
int zynqmp_disp_probe(struct zynqmp_dpsub *dpsub, struct drm_device *drm)
|
int zynqmp_disp_probe(struct zynqmp_dpsub *dpsub)
|
||||||
{
|
{
|
||||||
struct platform_device *pdev = to_platform_device(dpsub->dev);
|
struct platform_device *pdev = to_platform_device(dpsub->dev);
|
||||||
struct zynqmp_disp *disp;
|
struct zynqmp_disp *disp;
|
||||||
|
@ -1233,38 +1233,48 @@ int zynqmp_disp_probe(struct zynqmp_dpsub *dpsub, struct drm_device *drm)
|
||||||
struct resource *res;
|
struct resource *res;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
disp = drmm_kzalloc(drm, sizeof(*disp), GFP_KERNEL);
|
disp = kzalloc(sizeof(*disp), GFP_KERNEL);
|
||||||
if (!disp)
|
if (!disp)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
disp->dev = &pdev->dev;
|
disp->dev = &pdev->dev;
|
||||||
disp->dpsub = dpsub;
|
disp->dpsub = dpsub;
|
||||||
|
|
||||||
dpsub->disp = disp;
|
|
||||||
|
|
||||||
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "blend");
|
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "blend");
|
||||||
disp->blend.base = devm_ioremap_resource(disp->dev, res);
|
disp->blend.base = devm_ioremap_resource(disp->dev, res);
|
||||||
if (IS_ERR(disp->blend.base))
|
if (IS_ERR(disp->blend.base)) {
|
||||||
return PTR_ERR(disp->blend.base);
|
ret = PTR_ERR(disp->blend.base);
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "av_buf");
|
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "av_buf");
|
||||||
disp->avbuf.base = devm_ioremap_resource(disp->dev, res);
|
disp->avbuf.base = devm_ioremap_resource(disp->dev, res);
|
||||||
if (IS_ERR(disp->avbuf.base))
|
if (IS_ERR(disp->avbuf.base)) {
|
||||||
return PTR_ERR(disp->avbuf.base);
|
ret = PTR_ERR(disp->avbuf.base);
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "aud");
|
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "aud");
|
||||||
disp->audio.base = devm_ioremap_resource(disp->dev, res);
|
disp->audio.base = devm_ioremap_resource(disp->dev, res);
|
||||||
if (IS_ERR(disp->audio.base))
|
if (IS_ERR(disp->audio.base)) {
|
||||||
return PTR_ERR(disp->audio.base);
|
ret = PTR_ERR(disp->audio.base);
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
ret = zynqmp_disp_create_layers(disp);
|
ret = zynqmp_disp_create_layers(disp);
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
goto error;
|
||||||
|
|
||||||
layer = &disp->layers[ZYNQMP_DPSUB_LAYER_VID];
|
layer = &disp->layers[ZYNQMP_DPSUB_LAYER_VID];
|
||||||
dpsub->dma_align = 1 << layer->dmas[0].chan->device->copy_align;
|
dpsub->dma_align = 1 << layer->dmas[0].chan->device->copy_align;
|
||||||
|
|
||||||
|
dpsub->disp = disp;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
error:
|
||||||
|
kfree(disp);
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
void zynqmp_disp_remove(struct zynqmp_dpsub *dpsub)
|
void zynqmp_disp_remove(struct zynqmp_dpsub *dpsub)
|
||||||
|
|
|
@ -25,7 +25,6 @@
|
||||||
#define ZYNQMP_DISP_MAX_DMA_BIT 44
|
#define ZYNQMP_DISP_MAX_DMA_BIT 44
|
||||||
|
|
||||||
struct device;
|
struct device;
|
||||||
struct drm_device;
|
|
||||||
struct drm_format_info;
|
struct drm_format_info;
|
||||||
struct drm_plane_state;
|
struct drm_plane_state;
|
||||||
struct platform_device;
|
struct platform_device;
|
||||||
|
@ -60,7 +59,7 @@ void zynqmp_disp_layer_set_format(struct zynqmp_disp_layer *layer,
|
||||||
int zynqmp_disp_layer_update(struct zynqmp_disp_layer *layer,
|
int zynqmp_disp_layer_update(struct zynqmp_disp_layer *layer,
|
||||||
struct drm_plane_state *state);
|
struct drm_plane_state *state);
|
||||||
|
|
||||||
int zynqmp_disp_probe(struct zynqmp_dpsub *dpsub, struct drm_device *drm);
|
int zynqmp_disp_probe(struct zynqmp_dpsub *dpsub);
|
||||||
void zynqmp_disp_remove(struct zynqmp_dpsub *dpsub);
|
void zynqmp_disp_remove(struct zynqmp_dpsub *dpsub);
|
||||||
|
|
||||||
#endif /* _ZYNQMP_DISP_H_ */
|
#endif /* _ZYNQMP_DISP_H_ */
|
||||||
|
|
|
@ -14,7 +14,6 @@
|
||||||
#include <drm/drm_crtc.h>
|
#include <drm/drm_crtc.h>
|
||||||
#include <drm/drm_device.h>
|
#include <drm/drm_device.h>
|
||||||
#include <drm/drm_edid.h>
|
#include <drm/drm_edid.h>
|
||||||
#include <drm/drm_managed.h>
|
|
||||||
#include <drm/drm_modes.h>
|
#include <drm/drm_modes.h>
|
||||||
#include <drm/drm_of.h>
|
#include <drm/drm_of.h>
|
||||||
|
|
||||||
|
@ -27,6 +26,7 @@
|
||||||
#include <linux/pm_runtime.h>
|
#include <linux/pm_runtime.h>
|
||||||
#include <linux/phy/phy.h>
|
#include <linux/phy/phy.h>
|
||||||
#include <linux/reset.h>
|
#include <linux/reset.h>
|
||||||
|
#include <linux/slab.h>
|
||||||
|
|
||||||
#include "zynqmp_disp.h"
|
#include "zynqmp_disp.h"
|
||||||
#include "zynqmp_dp.h"
|
#include "zynqmp_dp.h"
|
||||||
|
@ -1610,7 +1610,7 @@ static irqreturn_t zynqmp_dp_irq_handler(int irq, void *data)
|
||||||
* Initialization & Cleanup
|
* Initialization & Cleanup
|
||||||
*/
|
*/
|
||||||
|
|
||||||
int zynqmp_dp_probe(struct zynqmp_dpsub *dpsub, struct drm_device *drm)
|
int zynqmp_dp_probe(struct zynqmp_dpsub *dpsub)
|
||||||
{
|
{
|
||||||
struct platform_device *pdev = to_platform_device(dpsub->dev);
|
struct platform_device *pdev = to_platform_device(dpsub->dev);
|
||||||
struct drm_bridge *bridge;
|
struct drm_bridge *bridge;
|
||||||
|
@ -1618,7 +1618,7 @@ int zynqmp_dp_probe(struct zynqmp_dpsub *dpsub, struct drm_device *drm)
|
||||||
struct resource *res;
|
struct resource *res;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
dp = drmm_kzalloc(drm, sizeof(*dp), GFP_KERNEL);
|
dp = kzalloc(sizeof(*dp), GFP_KERNEL);
|
||||||
if (!dp)
|
if (!dp)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
|
@ -1628,29 +1628,32 @@ int zynqmp_dp_probe(struct zynqmp_dpsub *dpsub, struct drm_device *drm)
|
||||||
|
|
||||||
INIT_DELAYED_WORK(&dp->hpd_work, zynqmp_dp_hpd_work_func);
|
INIT_DELAYED_WORK(&dp->hpd_work, zynqmp_dp_hpd_work_func);
|
||||||
|
|
||||||
dpsub->dp = dp;
|
|
||||||
|
|
||||||
/* Acquire all resources (IOMEM, IRQ and PHYs). */
|
/* Acquire all resources (IOMEM, IRQ and PHYs). */
|
||||||
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dp");
|
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dp");
|
||||||
dp->iomem = devm_ioremap_resource(dp->dev, res);
|
dp->iomem = devm_ioremap_resource(dp->dev, res);
|
||||||
if (IS_ERR(dp->iomem))
|
if (IS_ERR(dp->iomem)) {
|
||||||
return PTR_ERR(dp->iomem);
|
ret = PTR_ERR(dp->iomem);
|
||||||
|
goto err_free;
|
||||||
|
}
|
||||||
|
|
||||||
dp->irq = platform_get_irq(pdev, 0);
|
dp->irq = platform_get_irq(pdev, 0);
|
||||||
if (dp->irq < 0)
|
if (dp->irq < 0) {
|
||||||
return dp->irq;
|
ret = dp->irq;
|
||||||
|
goto err_free;
|
||||||
|
}
|
||||||
|
|
||||||
dp->reset = devm_reset_control_get(dp->dev, NULL);
|
dp->reset = devm_reset_control_get(dp->dev, NULL);
|
||||||
if (IS_ERR(dp->reset)) {
|
if (IS_ERR(dp->reset)) {
|
||||||
if (PTR_ERR(dp->reset) != -EPROBE_DEFER)
|
if (PTR_ERR(dp->reset) != -EPROBE_DEFER)
|
||||||
dev_err(dp->dev, "failed to get reset: %ld\n",
|
dev_err(dp->dev, "failed to get reset: %ld\n",
|
||||||
PTR_ERR(dp->reset));
|
PTR_ERR(dp->reset));
|
||||||
return PTR_ERR(dp->reset);
|
ret = PTR_ERR(dp->reset);
|
||||||
|
goto err_free;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = zynqmp_dp_reset(dp, false);
|
ret = zynqmp_dp_reset(dp, false);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
return ret;
|
goto err_free;
|
||||||
|
|
||||||
ret = zynqmp_dp_phy_probe(dp);
|
ret = zynqmp_dp_phy_probe(dp);
|
||||||
if (ret)
|
if (ret)
|
||||||
|
@ -1700,6 +1703,8 @@ int zynqmp_dp_probe(struct zynqmp_dpsub *dpsub, struct drm_device *drm)
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
goto err_phy_exit;
|
goto err_phy_exit;
|
||||||
|
|
||||||
|
dpsub->dp = dp;
|
||||||
|
|
||||||
dev_dbg(dp->dev, "ZynqMP DisplayPort Tx probed with %u lanes\n",
|
dev_dbg(dp->dev, "ZynqMP DisplayPort Tx probed with %u lanes\n",
|
||||||
dp->num_lanes);
|
dp->num_lanes);
|
||||||
|
|
||||||
|
@ -1709,7 +1714,8 @@ int zynqmp_dp_probe(struct zynqmp_dpsub *dpsub, struct drm_device *drm)
|
||||||
zynqmp_dp_phy_exit(dp);
|
zynqmp_dp_phy_exit(dp);
|
||||||
err_reset:
|
err_reset:
|
||||||
zynqmp_dp_reset(dp, true);
|
zynqmp_dp_reset(dp, true);
|
||||||
|
err_free:
|
||||||
|
kfree(dp);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -12,7 +12,6 @@
|
||||||
#ifndef _ZYNQMP_DP_H_
|
#ifndef _ZYNQMP_DP_H_
|
||||||
#define _ZYNQMP_DP_H_
|
#define _ZYNQMP_DP_H_
|
||||||
|
|
||||||
struct drm_device;
|
|
||||||
struct platform_device;
|
struct platform_device;
|
||||||
struct zynqmp_dp;
|
struct zynqmp_dp;
|
||||||
struct zynqmp_dpsub;
|
struct zynqmp_dpsub;
|
||||||
|
@ -20,7 +19,7 @@ struct zynqmp_dpsub;
|
||||||
void zynqmp_dp_enable_vblank(struct zynqmp_dp *dp);
|
void zynqmp_dp_enable_vblank(struct zynqmp_dp *dp);
|
||||||
void zynqmp_dp_disable_vblank(struct zynqmp_dp *dp);
|
void zynqmp_dp_disable_vblank(struct zynqmp_dp *dp);
|
||||||
|
|
||||||
int zynqmp_dp_probe(struct zynqmp_dpsub *dpsub, struct drm_device *drm);
|
int zynqmp_dp_probe(struct zynqmp_dpsub *dpsub);
|
||||||
void zynqmp_dp_remove(struct zynqmp_dpsub *dpsub);
|
void zynqmp_dp_remove(struct zynqmp_dpsub *dpsub);
|
||||||
|
|
||||||
#endif /* _ZYNQMP_DP_H_ */
|
#endif /* _ZYNQMP_DP_H_ */
|
||||||
|
|
|
@ -15,6 +15,7 @@
|
||||||
#include <linux/of_reserved_mem.h>
|
#include <linux/of_reserved_mem.h>
|
||||||
#include <linux/platform_device.h>
|
#include <linux/platform_device.h>
|
||||||
#include <linux/pm_runtime.h>
|
#include <linux/pm_runtime.h>
|
||||||
|
#include <linux/slab.h>
|
||||||
|
|
||||||
#include <drm/drm_atomic_helper.h>
|
#include <drm/drm_atomic_helper.h>
|
||||||
#include <drm/drm_bridge_connector.h>
|
#include <drm/drm_bridge_connector.h>
|
||||||
|
@ -247,6 +248,14 @@ static int zynqmp_dpsub_init_clocks(struct zynqmp_dpsub *dpsub)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void zynqmp_dpsub_release(struct drm_device *drm, void *res)
|
||||||
|
{
|
||||||
|
struct zynqmp_dpsub *dpsub = res;
|
||||||
|
|
||||||
|
kfree(dpsub->disp);
|
||||||
|
kfree(dpsub->dp);
|
||||||
|
}
|
||||||
|
|
||||||
static int zynqmp_dpsub_probe(struct platform_device *pdev)
|
static int zynqmp_dpsub_probe(struct platform_device *pdev)
|
||||||
{
|
{
|
||||||
struct zynqmp_dpsub *dpsub;
|
struct zynqmp_dpsub *dpsub;
|
||||||
|
@ -258,6 +267,10 @@ static int zynqmp_dpsub_probe(struct platform_device *pdev)
|
||||||
if (IS_ERR(dpsub))
|
if (IS_ERR(dpsub))
|
||||||
return PTR_ERR(dpsub);
|
return PTR_ERR(dpsub);
|
||||||
|
|
||||||
|
ret = drmm_add_action(&dpsub->drm, zynqmp_dpsub_release, dpsub);
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
|
||||||
dpsub->dev = &pdev->dev;
|
dpsub->dev = &pdev->dev;
|
||||||
platform_set_drvdata(pdev, dpsub);
|
platform_set_drvdata(pdev, dpsub);
|
||||||
|
|
||||||
|
@ -276,11 +289,11 @@ static int zynqmp_dpsub_probe(struct platform_device *pdev)
|
||||||
* DP should be probed first so that the zynqmp_disp can set the output
|
* DP should be probed first so that the zynqmp_disp can set the output
|
||||||
* format accordingly.
|
* format accordingly.
|
||||||
*/
|
*/
|
||||||
ret = zynqmp_dp_probe(dpsub, &dpsub->drm);
|
ret = zynqmp_dp_probe(dpsub);
|
||||||
if (ret)
|
if (ret)
|
||||||
goto err_pm;
|
goto err_pm;
|
||||||
|
|
||||||
ret = zynqmp_disp_probe(dpsub, &dpsub->drm);
|
ret = zynqmp_disp_probe(dpsub);
|
||||||
if (ret)
|
if (ret)
|
||||||
goto err_dp;
|
goto err_dp;
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue