mirror of
https://github.com/torvalds/linux.git
synced 2026-04-21 00:04:01 -04:00
Based on grepping through the source code these drivers appear 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.
All of the drivers in this patch were fairly straightforward to fix
since they already had a call to drm_atomic_helper_shutdown() at
remove/unbind time but were just lacking one at system shutdown. The
only hitch is that some of these drivers use the component model to
register/unregister their DRM devices. The shutdown callback is part
of the original device. The typical solution here, based on how other
DRM drivers do this, is to keep track of whether the device is bound
based on drvdata. In most cases the drvdata is the drm_device, so we
can just make sure it is NULL when the device is not bound. In some
drivers, this required minor code changes. To make things simpler,
drm_atomic_helper_shutdown() has been modified to consider a NULL
drm_device as a noop in the patch ("drm/atomic-helper:
drm_atomic_helper_shutdown(NULL) should be a noop").
Suggested-by: Maxime Ripard <mripard@kernel.org>
Reviewed-by: Tomi Valkeinen <tomi.valkeinen@ideasonboard.com>
Tested-by: Tomi Valkeinen <tomi.valkeinen@ideasonboard.com>
Acked-by: Maxime Ripard <mripard@kernel.org>
Tested-by: Jernej Skrabec <jernej.skrabec@gmail.com>
Reviewed-by: Jernej Skrabec <jernej.skrabec@gmail.com>
Reviewed-by: Sui Jingfeng <suijingfeng@loongson.cn>
Tested-by: Sui Jingfeng <suijingfeng@loongson.cn>
Signed-off-by: Douglas Anderson <dianders@chromium.org>
Link: https://patchwork.freedesktop.org/patch/msgid/20230901163944.RFT.2.I9115e5d094a43e687978b0699cc1fe9f2a3452ea@changeid
166 lines
3.7 KiB
C
166 lines
3.7 KiB
C
// SPDX-License-Identifier: GPL-2.0
|
|
/*
|
|
* (C) COPYRIGHT 2018 ARM Limited. All rights reserved.
|
|
* Author: James.Qian.Wang <james.qian.wang@arm.com>
|
|
*
|
|
*/
|
|
#include <linux/module.h>
|
|
#include <linux/kernel.h>
|
|
#include <linux/of.h>
|
|
#include <linux/platform_device.h>
|
|
#include <linux/pm_runtime.h>
|
|
#include <drm/drm_fbdev_generic.h>
|
|
#include <drm/drm_module.h>
|
|
#include <drm/drm_of.h>
|
|
#include "komeda_dev.h"
|
|
#include "komeda_kms.h"
|
|
|
|
struct komeda_drv {
|
|
struct komeda_dev *mdev;
|
|
struct komeda_kms_dev *kms;
|
|
};
|
|
|
|
struct komeda_dev *dev_to_mdev(struct device *dev)
|
|
{
|
|
struct komeda_drv *mdrv = dev_get_drvdata(dev);
|
|
|
|
return mdrv ? mdrv->mdev : NULL;
|
|
}
|
|
|
|
static void komeda_platform_remove(struct platform_device *pdev)
|
|
{
|
|
struct device *dev = &pdev->dev;
|
|
struct komeda_drv *mdrv = dev_get_drvdata(dev);
|
|
|
|
komeda_kms_detach(mdrv->kms);
|
|
|
|
if (pm_runtime_enabled(dev))
|
|
pm_runtime_disable(dev);
|
|
else
|
|
komeda_dev_suspend(mdrv->mdev);
|
|
|
|
komeda_dev_destroy(mdrv->mdev);
|
|
|
|
dev_set_drvdata(dev, NULL);
|
|
devm_kfree(dev, mdrv);
|
|
}
|
|
|
|
static void komeda_platform_shutdown(struct platform_device *pdev)
|
|
{
|
|
struct device *dev = &pdev->dev;
|
|
struct komeda_drv *mdrv = dev_get_drvdata(dev);
|
|
|
|
komeda_kms_shutdown(mdrv->kms);
|
|
}
|
|
|
|
static int komeda_platform_probe(struct platform_device *pdev)
|
|
{
|
|
struct device *dev = &pdev->dev;
|
|
struct komeda_drv *mdrv;
|
|
int err;
|
|
|
|
mdrv = devm_kzalloc(dev, sizeof(*mdrv), GFP_KERNEL);
|
|
if (!mdrv)
|
|
return -ENOMEM;
|
|
|
|
mdrv->mdev = komeda_dev_create(dev);
|
|
if (IS_ERR(mdrv->mdev)) {
|
|
err = PTR_ERR(mdrv->mdev);
|
|
goto free_mdrv;
|
|
}
|
|
|
|
pm_runtime_enable(dev);
|
|
if (!pm_runtime_enabled(dev))
|
|
komeda_dev_resume(mdrv->mdev);
|
|
|
|
mdrv->kms = komeda_kms_attach(mdrv->mdev);
|
|
if (IS_ERR(mdrv->kms)) {
|
|
err = PTR_ERR(mdrv->kms);
|
|
goto destroy_mdev;
|
|
}
|
|
|
|
dev_set_drvdata(dev, mdrv);
|
|
drm_fbdev_generic_setup(&mdrv->kms->base, 32);
|
|
|
|
return 0;
|
|
|
|
destroy_mdev:
|
|
if (pm_runtime_enabled(dev))
|
|
pm_runtime_disable(dev);
|
|
else
|
|
komeda_dev_suspend(mdrv->mdev);
|
|
|
|
komeda_dev_destroy(mdrv->mdev);
|
|
|
|
free_mdrv:
|
|
devm_kfree(dev, mdrv);
|
|
return err;
|
|
}
|
|
|
|
static const struct of_device_id komeda_of_match[] = {
|
|
{ .compatible = "arm,mali-d71", .data = d71_identify, },
|
|
{ .compatible = "arm,mali-d32", .data = d71_identify, },
|
|
{},
|
|
};
|
|
|
|
MODULE_DEVICE_TABLE(of, komeda_of_match);
|
|
|
|
static int __maybe_unused komeda_rt_pm_suspend(struct device *dev)
|
|
{
|
|
struct komeda_drv *mdrv = dev_get_drvdata(dev);
|
|
|
|
return komeda_dev_suspend(mdrv->mdev);
|
|
}
|
|
|
|
static int __maybe_unused komeda_rt_pm_resume(struct device *dev)
|
|
{
|
|
struct komeda_drv *mdrv = dev_get_drvdata(dev);
|
|
|
|
return komeda_dev_resume(mdrv->mdev);
|
|
}
|
|
|
|
static int __maybe_unused komeda_pm_suspend(struct device *dev)
|
|
{
|
|
struct komeda_drv *mdrv = dev_get_drvdata(dev);
|
|
int res;
|
|
|
|
res = drm_mode_config_helper_suspend(&mdrv->kms->base);
|
|
|
|
if (!pm_runtime_status_suspended(dev))
|
|
komeda_dev_suspend(mdrv->mdev);
|
|
|
|
return res;
|
|
}
|
|
|
|
static int __maybe_unused komeda_pm_resume(struct device *dev)
|
|
{
|
|
struct komeda_drv *mdrv = dev_get_drvdata(dev);
|
|
|
|
if (!pm_runtime_status_suspended(dev))
|
|
komeda_dev_resume(mdrv->mdev);
|
|
|
|
return drm_mode_config_helper_resume(&mdrv->kms->base);
|
|
}
|
|
|
|
static const struct dev_pm_ops komeda_pm_ops = {
|
|
SET_SYSTEM_SLEEP_PM_OPS(komeda_pm_suspend, komeda_pm_resume)
|
|
SET_RUNTIME_PM_OPS(komeda_rt_pm_suspend, komeda_rt_pm_resume, NULL)
|
|
};
|
|
|
|
static struct platform_driver komeda_platform_driver = {
|
|
.probe = komeda_platform_probe,
|
|
.remove_new = komeda_platform_remove,
|
|
.shutdown = komeda_platform_shutdown,
|
|
.driver = {
|
|
.name = "komeda",
|
|
.of_match_table = komeda_of_match,
|
|
.pm = &komeda_pm_ops,
|
|
},
|
|
};
|
|
|
|
drm_module_platform_driver(komeda_platform_driver);
|
|
|
|
MODULE_AUTHOR("James.Qian.Wang <james.qian.wang@arm.com>");
|
|
MODULE_DESCRIPTION("Komeda KMS driver");
|
|
MODULE_LICENSE("GPL v2");
|