mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2025-01-18 02:46:06 +00:00
b47914741a
The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is (mostly) ignored and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new() which already returns void. Trivially convert the armada drm drivers from always returning zero in the remove callback to the void returning variant. Reviewed-by: Thomas Zimmermann <tzimmermann@suse.de> Reviewed-by: Jyri Sarha <jyri.sarha@iki.fi> Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de> Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de> Link: https://patchwork.freedesktop.org/patch/msgid/20231102165640.3307820-21-u.kleine-koenig@pengutronix.de
287 lines
6.8 KiB
C
287 lines
6.8 KiB
C
// SPDX-License-Identifier: GPL-2.0-only
|
|
/*
|
|
* Copyright (C) 2012 Russell King
|
|
*/
|
|
|
|
#include <linux/clk.h>
|
|
#include <linux/component.h>
|
|
#include <linux/module.h>
|
|
#include <linux/of.h>
|
|
#include <linux/of_graph.h>
|
|
#include <linux/platform_device.h>
|
|
|
|
#include <drm/drm_aperture.h>
|
|
#include <drm/drm_atomic_helper.h>
|
|
#include <drm/drm_drv.h>
|
|
#include <drm/drm_ioctl.h>
|
|
#include <drm/drm_managed.h>
|
|
#include <drm/drm_prime.h>
|
|
#include <drm/drm_probe_helper.h>
|
|
#include <drm/drm_of.h>
|
|
#include <drm/drm_vblank.h>
|
|
|
|
#include "armada_crtc.h"
|
|
#include "armada_drm.h"
|
|
#include "armada_gem.h"
|
|
#include "armada_fb.h"
|
|
#include "armada_hw.h"
|
|
#include <drm/armada_drm.h>
|
|
#include "armada_ioctlP.h"
|
|
|
|
static const struct drm_ioctl_desc armada_ioctls[] = {
|
|
DRM_IOCTL_DEF_DRV(ARMADA_GEM_CREATE, armada_gem_create_ioctl,0),
|
|
DRM_IOCTL_DEF_DRV(ARMADA_GEM_MMAP, armada_gem_mmap_ioctl, 0),
|
|
DRM_IOCTL_DEF_DRV(ARMADA_GEM_PWRITE, armada_gem_pwrite_ioctl, 0),
|
|
};
|
|
|
|
DEFINE_DRM_GEM_FOPS(armada_drm_fops);
|
|
|
|
static const struct drm_driver armada_drm_driver = {
|
|
.gem_prime_import = armada_gem_prime_import,
|
|
.dumb_create = armada_gem_dumb_create,
|
|
.major = 1,
|
|
.minor = 0,
|
|
.name = "armada-drm",
|
|
.desc = "Armada SoC DRM",
|
|
.date = "20120730",
|
|
.driver_features = DRIVER_GEM | DRIVER_MODESET | DRIVER_ATOMIC,
|
|
.ioctls = armada_ioctls,
|
|
.num_ioctls = ARRAY_SIZE(armada_ioctls),
|
|
.fops = &armada_drm_fops,
|
|
};
|
|
|
|
static const struct drm_mode_config_funcs armada_drm_mode_config_funcs = {
|
|
.fb_create = armada_fb_create,
|
|
.atomic_check = drm_atomic_helper_check,
|
|
.atomic_commit = drm_atomic_helper_commit,
|
|
};
|
|
|
|
static int armada_drm_bind(struct device *dev)
|
|
{
|
|
struct armada_private *priv;
|
|
struct resource *mem = NULL;
|
|
int ret, n;
|
|
|
|
for (n = 0; ; n++) {
|
|
struct resource *r = platform_get_resource(to_platform_device(dev),
|
|
IORESOURCE_MEM, n);
|
|
if (!r)
|
|
break;
|
|
|
|
/* Resources above 64K are graphics memory */
|
|
if (resource_size(r) > SZ_64K)
|
|
mem = r;
|
|
else
|
|
return -EINVAL;
|
|
}
|
|
|
|
if (!mem)
|
|
return -ENXIO;
|
|
|
|
if (!devm_request_mem_region(dev, mem->start, resource_size(mem),
|
|
"armada-drm"))
|
|
return -EBUSY;
|
|
|
|
priv = devm_drm_dev_alloc(dev, &armada_drm_driver,
|
|
struct armada_private, drm);
|
|
if (IS_ERR(priv)) {
|
|
dev_err(dev, "[" DRM_NAME ":%s] devm_drm_dev_alloc failed: %li\n",
|
|
__func__, PTR_ERR(priv));
|
|
return PTR_ERR(priv);
|
|
}
|
|
|
|
/* Remove early framebuffers */
|
|
ret = drm_aperture_remove_framebuffers(&armada_drm_driver);
|
|
if (ret) {
|
|
dev_err(dev, "[" DRM_NAME ":%s] can't kick out simple-fb: %d\n",
|
|
__func__, ret);
|
|
return ret;
|
|
}
|
|
|
|
dev_set_drvdata(dev, &priv->drm);
|
|
|
|
/* Mode setting support */
|
|
drm_mode_config_init(&priv->drm);
|
|
priv->drm.mode_config.min_width = 320;
|
|
priv->drm.mode_config.min_height = 200;
|
|
|
|
/*
|
|
* With vscale enabled, the maximum width is 1920 due to the
|
|
* 1920 by 3 lines RAM
|
|
*/
|
|
priv->drm.mode_config.max_width = 1920;
|
|
priv->drm.mode_config.max_height = 2048;
|
|
|
|
priv->drm.mode_config.preferred_depth = 24;
|
|
priv->drm.mode_config.funcs = &armada_drm_mode_config_funcs;
|
|
drm_mm_init(&priv->linear, mem->start, resource_size(mem));
|
|
mutex_init(&priv->linear_lock);
|
|
|
|
ret = component_bind_all(dev, &priv->drm);
|
|
if (ret)
|
|
goto err_kms;
|
|
|
|
ret = drm_vblank_init(&priv->drm, priv->drm.mode_config.num_crtc);
|
|
if (ret)
|
|
goto err_comp;
|
|
|
|
drm_mode_config_reset(&priv->drm);
|
|
|
|
drm_kms_helper_poll_init(&priv->drm);
|
|
|
|
ret = drm_dev_register(&priv->drm, 0);
|
|
if (ret)
|
|
goto err_poll;
|
|
|
|
#ifdef CONFIG_DEBUG_FS
|
|
armada_drm_debugfs_init(priv->drm.primary);
|
|
#endif
|
|
|
|
armada_fbdev_setup(&priv->drm);
|
|
|
|
return 0;
|
|
|
|
err_poll:
|
|
drm_kms_helper_poll_fini(&priv->drm);
|
|
err_comp:
|
|
component_unbind_all(dev, &priv->drm);
|
|
err_kms:
|
|
drm_mode_config_cleanup(&priv->drm);
|
|
drm_mm_takedown(&priv->linear);
|
|
dev_set_drvdata(dev, NULL);
|
|
return ret;
|
|
}
|
|
|
|
static void armada_drm_unbind(struct device *dev)
|
|
{
|
|
struct drm_device *drm = dev_get_drvdata(dev);
|
|
struct armada_private *priv = drm_to_armada_dev(drm);
|
|
|
|
drm_kms_helper_poll_fini(&priv->drm);
|
|
|
|
drm_dev_unregister(&priv->drm);
|
|
|
|
drm_atomic_helper_shutdown(&priv->drm);
|
|
|
|
component_unbind_all(dev, &priv->drm);
|
|
|
|
drm_mode_config_cleanup(&priv->drm);
|
|
drm_mm_takedown(&priv->linear);
|
|
dev_set_drvdata(dev, NULL);
|
|
}
|
|
|
|
static void armada_add_endpoints(struct device *dev,
|
|
struct component_match **match, struct device_node *dev_node)
|
|
{
|
|
struct device_node *ep, *remote;
|
|
|
|
for_each_endpoint_of_node(dev_node, ep) {
|
|
remote = of_graph_get_remote_port_parent(ep);
|
|
if (remote && of_device_is_available(remote))
|
|
drm_of_component_match_add(dev, match, component_compare_of,
|
|
remote);
|
|
of_node_put(remote);
|
|
}
|
|
}
|
|
|
|
static const struct component_master_ops armada_master_ops = {
|
|
.bind = armada_drm_bind,
|
|
.unbind = armada_drm_unbind,
|
|
};
|
|
|
|
static int armada_drm_probe(struct platform_device *pdev)
|
|
{
|
|
struct component_match *match = NULL;
|
|
struct device *dev = &pdev->dev;
|
|
int ret;
|
|
|
|
ret = drm_of_component_probe(dev, component_compare_dev_name, &armada_master_ops);
|
|
if (ret != -EINVAL)
|
|
return ret;
|
|
|
|
if (dev->platform_data) {
|
|
char **devices = dev->platform_data;
|
|
struct device *d;
|
|
int i;
|
|
|
|
for (i = 0; devices[i]; i++)
|
|
component_match_add(dev, &match, component_compare_dev_name,
|
|
devices[i]);
|
|
|
|
if (i == 0) {
|
|
dev_err(dev, "missing 'ports' property\n");
|
|
return -ENODEV;
|
|
}
|
|
|
|
for (i = 0; devices[i]; i++) {
|
|
d = bus_find_device_by_name(&platform_bus_type, NULL,
|
|
devices[i]);
|
|
if (d && d->of_node)
|
|
armada_add_endpoints(dev, &match, d->of_node);
|
|
put_device(d);
|
|
}
|
|
}
|
|
|
|
return component_master_add_with_match(&pdev->dev, &armada_master_ops,
|
|
match);
|
|
}
|
|
|
|
static void armada_drm_remove(struct platform_device *pdev)
|
|
{
|
|
component_master_del(&pdev->dev, &armada_master_ops);
|
|
}
|
|
|
|
static void armada_drm_shutdown(struct platform_device *pdev)
|
|
{
|
|
drm_atomic_helper_shutdown(platform_get_drvdata(pdev));
|
|
}
|
|
|
|
static const struct platform_device_id armada_drm_platform_ids[] = {
|
|
{
|
|
.name = "armada-drm",
|
|
}, {
|
|
.name = "armada-510-drm",
|
|
},
|
|
{ },
|
|
};
|
|
MODULE_DEVICE_TABLE(platform, armada_drm_platform_ids);
|
|
|
|
static struct platform_driver armada_drm_platform_driver = {
|
|
.probe = armada_drm_probe,
|
|
.remove_new = armada_drm_remove,
|
|
.shutdown = armada_drm_shutdown,
|
|
.driver = {
|
|
.name = "armada-drm",
|
|
},
|
|
.id_table = armada_drm_platform_ids,
|
|
};
|
|
|
|
static int __init armada_drm_init(void)
|
|
{
|
|
int ret;
|
|
|
|
if (drm_firmware_drivers_only())
|
|
return -ENODEV;
|
|
|
|
ret = platform_driver_register(&armada_lcd_platform_driver);
|
|
if (ret)
|
|
return ret;
|
|
ret = platform_driver_register(&armada_drm_platform_driver);
|
|
if (ret)
|
|
platform_driver_unregister(&armada_lcd_platform_driver);
|
|
return ret;
|
|
}
|
|
module_init(armada_drm_init);
|
|
|
|
static void __exit armada_drm_exit(void)
|
|
{
|
|
platform_driver_unregister(&armada_drm_platform_driver);
|
|
platform_driver_unregister(&armada_lcd_platform_driver);
|
|
}
|
|
module_exit(armada_drm_exit);
|
|
|
|
MODULE_AUTHOR("Russell King <rmk+kernel@armlinux.org.uk>");
|
|
MODULE_DESCRIPTION("Armada DRM Driver");
|
|
MODULE_LICENSE("GPL");
|
|
MODULE_ALIAS("platform:armada-drm");
|