Merge remote-tracking branch 'sm8250/lineage-20' into lineage-23.2
* sm8250/lineage-20: msm: kgsl: Use kthread instead of workqueue for event work msm: kgsl: Fix possible NULL pointer dereference fixup! BACKPORT: kbuild: check the minimum assembler version in Kconfig techpack: drm/msm/sde: add sysfs node for trigger wake up early Change-Id: I10989481293366e0d0fc83795dfdfbf68a679743
This commit is contained in:
12 files changed
+207
-33
No files matched your search
+38
-6
@@ -609,11 +609,11 @@ int kgsl_context_init(struct kgsl_device_private *dev_priv,
|
|||||||
if (id == -ENOSPC) {
|
if (id == -ENOSPC) {
|
||||||
/*
|
/*
|
||||||
* Before declaring that there are no contexts left try
|
* Before declaring that there are no contexts left try
|
||||||
* flushing the event workqueue just in case there are
|
* flushing the event worker just in case there are
|
||||||
* detached contexts waiting to finish
|
* detached contexts waiting to finish
|
||||||
*/
|
*/
|
||||||
|
|
||||||
flush_workqueue(device->events_wq);
|
kthread_flush_worker(device->events_worker);
|
||||||
id = _kgsl_get_context_id(device);
|
id = _kgsl_get_context_id(device);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -5334,6 +5334,16 @@ int kgsl_device_platform_probe(struct kgsl_device *device)
|
|||||||
if (status)
|
if (status)
|
||||||
goto error;
|
goto error;
|
||||||
|
|
||||||
|
device->events_worker = kthread_create_worker(0, "kgsl-events");
|
||||||
|
|
||||||
|
if (IS_ERR(device->events_worker)) {
|
||||||
|
status = PTR_ERR(device->events_worker);
|
||||||
|
dev_err(device->dev, "Failed to create events worker ret=%d\n", status);
|
||||||
|
goto error_pwrctrl_close;
|
||||||
|
}
|
||||||
|
|
||||||
|
sched_set_fifo(device->events_worker->task);
|
||||||
|
|
||||||
if (!devm_request_mem_region(device->dev, device->reg_phys,
|
if (!devm_request_mem_region(device->dev, device->reg_phys,
|
||||||
device->reg_len, device->name)) {
|
device->reg_len, device->name)) {
|
||||||
dev_err(device->dev, "request_mem_region failed\n");
|
dev_err(device->dev, "request_mem_region failed\n");
|
||||||
@@ -5422,9 +5432,6 @@ int kgsl_device_platform_probe(struct kgsl_device *device)
|
|||||||
PM_QOS_DEFAULT_VALUE);
|
PM_QOS_DEFAULT_VALUE);
|
||||||
}
|
}
|
||||||
|
|
||||||
device->events_wq = alloc_workqueue("kgsl-events",
|
|
||||||
WQ_UNBOUND | WQ_MEM_RECLAIM | WQ_SYSFS | WQ_HIGHPRI, 0);
|
|
||||||
|
|
||||||
/* Initialize the snapshot engine */
|
/* Initialize the snapshot engine */
|
||||||
kgsl_device_snapshot_init(device);
|
kgsl_device_snapshot_init(device);
|
||||||
|
|
||||||
@@ -5436,6 +5443,9 @@ int kgsl_device_platform_probe(struct kgsl_device *device)
|
|||||||
error_close_mmu:
|
error_close_mmu:
|
||||||
kgsl_mmu_close(device);
|
kgsl_mmu_close(device);
|
||||||
error_pwrctrl_close:
|
error_pwrctrl_close:
|
||||||
|
if (!IS_ERR(device->events_worker))
|
||||||
|
kthread_destroy_worker(device->events_worker);
|
||||||
|
|
||||||
kgsl_pwrctrl_close(device);
|
kgsl_pwrctrl_close(device);
|
||||||
error:
|
error:
|
||||||
kgsl_device_debugfs_close(device);
|
kgsl_device_debugfs_close(device);
|
||||||
@@ -5446,7 +5456,7 @@ EXPORT_SYMBOL(kgsl_device_platform_probe);
|
|||||||
|
|
||||||
void kgsl_device_platform_remove(struct kgsl_device *device)
|
void kgsl_device_platform_remove(struct kgsl_device *device)
|
||||||
{
|
{
|
||||||
destroy_workqueue(device->events_wq);
|
kthread_destroy_worker(device->events_worker);
|
||||||
|
|
||||||
kfree(device->dev->dma_parms);
|
kfree(device->dev->dma_parms);
|
||||||
device->dev->dma_parms = NULL;
|
device->dev->dma_parms = NULL;
|
||||||
@@ -5481,6 +5491,16 @@ _flush_mem_workqueue(struct work_struct *work)
|
|||||||
|
|
||||||
static void kgsl_core_exit(void)
|
static void kgsl_core_exit(void)
|
||||||
{
|
{
|
||||||
|
if (kgsl_driver.workqueue) {
|
||||||
|
destroy_workqueue(kgsl_driver.workqueue);
|
||||||
|
kgsl_driver.workqueue = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (kgsl_driver.mem_workqueue) {
|
||||||
|
destroy_workqueue(kgsl_driver.mem_workqueue);
|
||||||
|
kgsl_driver.mem_workqueue = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
kgsl_events_exit();
|
kgsl_events_exit();
|
||||||
kgsl_core_debugfs_close();
|
kgsl_core_debugfs_close();
|
||||||
|
|
||||||
@@ -5579,9 +5599,21 @@ static int __init kgsl_core_init(void)
|
|||||||
kgsl_driver.workqueue = alloc_workqueue("kgsl-workqueue",
|
kgsl_driver.workqueue = alloc_workqueue("kgsl-workqueue",
|
||||||
WQ_UNBOUND | WQ_MEM_RECLAIM | WQ_SYSFS, 0);
|
WQ_UNBOUND | WQ_MEM_RECLAIM | WQ_SYSFS, 0);
|
||||||
|
|
||||||
|
if (!kgsl_driver.workqueue) {
|
||||||
|
pr_err("kgsl: Failed to allocate kgsl workqueue\n");
|
||||||
|
result = -ENOMEM;
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
|
||||||
kgsl_driver.mem_workqueue = alloc_workqueue("kgsl-mementry",
|
kgsl_driver.mem_workqueue = alloc_workqueue("kgsl-mementry",
|
||||||
WQ_UNBOUND | WQ_MEM_RECLAIM, 0);
|
WQ_UNBOUND | WQ_MEM_RECLAIM, 0);
|
||||||
|
|
||||||
|
if (!kgsl_driver.mem_workqueue) {
|
||||||
|
pr_err("kgsl: Failed to allocate mem workqueue\n");
|
||||||
|
result = -ENOMEM;
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
|
||||||
INIT_WORK(&kgsl_driver.mem_work, _flush_mem_workqueue);
|
INIT_WORK(&kgsl_driver.mem_work, _flush_mem_workqueue);
|
||||||
|
|
||||||
kthread_init_worker(&kgsl_driver.worker);
|
kthread_init_worker(&kgsl_driver.worker);
|
||||||
|
|||||||
@@ -316,7 +316,7 @@ typedef void (*kgsl_event_func)(struct kgsl_device *, struct kgsl_event_group *,
|
|||||||
* @priv: Private data passed to the callback function
|
* @priv: Private data passed to the callback function
|
||||||
* @node: List node for the kgsl_event_group list
|
* @node: List node for the kgsl_event_group list
|
||||||
* @created: Jiffies when the event was created
|
* @created: Jiffies when the event was created
|
||||||
* @work: Work struct for dispatching the callback
|
* @work: kthread_work struct for dispatching the callback
|
||||||
* @result: KGSL event result type to pass to the callback
|
* @result: KGSL event result type to pass to the callback
|
||||||
* group: The event group this event belongs to
|
* group: The event group this event belongs to
|
||||||
*/
|
*/
|
||||||
@@ -328,7 +328,7 @@ struct kgsl_event {
|
|||||||
void *priv;
|
void *priv;
|
||||||
struct list_head node;
|
struct list_head node;
|
||||||
unsigned int created;
|
unsigned int created;
|
||||||
struct work_struct work;
|
struct kthread_work work;
|
||||||
int result;
|
int result;
|
||||||
struct kgsl_event_group *group;
|
struct kgsl_event_group *group;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2002,2007-2021, The Linux Foundation. All rights reserved.
|
* Copyright (c) 2002,2007-2021, The Linux Foundation. All rights reserved.
|
||||||
* Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
|
* Copyright (c) 2022-2024, Qualcomm Innovation Center, Inc. All rights reserved.
|
||||||
*/
|
*/
|
||||||
#ifndef __KGSL_DEVICE_H
|
#ifndef __KGSL_DEVICE_H
|
||||||
#define __KGSL_DEVICE_H
|
#define __KGSL_DEVICE_H
|
||||||
@@ -311,7 +311,7 @@ struct kgsl_device {
|
|||||||
struct kgsl_pwrscale pwrscale;
|
struct kgsl_pwrscale pwrscale;
|
||||||
|
|
||||||
int reset_counter; /* Track how many GPU core resets have occurred */
|
int reset_counter; /* Track how many GPU core resets have occurred */
|
||||||
struct workqueue_struct *events_wq;
|
struct kthread_worker *events_worker;
|
||||||
|
|
||||||
struct device *busmondev; /* pseudo dev for GPU BW voting governor */
|
struct device *busmondev; /* pseudo dev for GPU BW voting governor */
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
// SPDX-License-Identifier: GPL-2.0-only
|
// SPDX-License-Identifier: GPL-2.0-only
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2011-2019, The Linux Foundation. All rights reserved.
|
* Copyright (c) 2011-2019, The Linux Foundation. All rights reserved.
|
||||||
|
* Copyright (c) 2022, 2024 Qualcomm Innovation Center, Inc. All rights reserved.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <linux/debugfs.h>
|
#include <linux/debugfs.h>
|
||||||
@@ -21,17 +22,17 @@ static inline void signal_event(struct kgsl_device *device,
|
|||||||
{
|
{
|
||||||
list_del(&event->node);
|
list_del(&event->node);
|
||||||
event->result = result;
|
event->result = result;
|
||||||
queue_work(device->events_wq, &event->work);
|
kthread_queue_work(device->events_worker, &event->work);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* _kgsl_event_worker() - Work handler for processing GPU event callbacks
|
* _kgsl_event_worker() - Work handler for processing GPU event callbacks
|
||||||
* @work: Pointer to the work_struct for the event
|
* @work: Pointer to the kthread_work for the event
|
||||||
*
|
*
|
||||||
* Each event callback has its own work struct and is run on a event specific
|
* Each event callback has its own kthread_work struct and is run on a event specific
|
||||||
* workqeuue. This is the worker that queues up the event callback function.
|
* worker thread. This is the worker that queues up the event callback function.
|
||||||
*/
|
*/
|
||||||
static void _kgsl_event_worker(struct work_struct *work)
|
static void _kgsl_event_worker(struct kthread_work *work)
|
||||||
{
|
{
|
||||||
struct kgsl_event *event = container_of(work, struct kgsl_event, work);
|
struct kgsl_event *event = container_of(work, struct kgsl_event, work);
|
||||||
int id = KGSL_CONTEXT_ID(event->context);
|
int id = KGSL_CONTEXT_ID(event->context);
|
||||||
@@ -273,7 +274,7 @@ int kgsl_add_event(struct kgsl_device *device, struct kgsl_event_group *group,
|
|||||||
event->created = jiffies;
|
event->created = jiffies;
|
||||||
event->group = group;
|
event->group = group;
|
||||||
|
|
||||||
INIT_WORK(&event->work, _kgsl_event_worker);
|
kthread_init_work(&event->work, _kgsl_event_worker);
|
||||||
|
|
||||||
trace_kgsl_register_event(KGSL_CONTEXT_ID(context), timestamp, func);
|
trace_kgsl_register_event(KGSL_CONTEXT_ID(context), timestamp, func);
|
||||||
|
|
||||||
@@ -288,7 +289,7 @@ int kgsl_add_event(struct kgsl_device *device, struct kgsl_event_group *group,
|
|||||||
|
|
||||||
if (timestamp_cmp(retired, timestamp) >= 0) {
|
if (timestamp_cmp(retired, timestamp) >= 0) {
|
||||||
event->result = KGSL_EVENT_RETIRED;
|
event->result = KGSL_EVENT_RETIRED;
|
||||||
queue_work(device->events_wq, &event->work);
|
kthread_queue_work(device->events_worker, &event->work);
|
||||||
spin_unlock(&group->lock);
|
spin_unlock(&group->lock);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1028,6 +1028,13 @@ int kgsl_pwrscale_init(struct device *dev, const char *governor)
|
|||||||
} else
|
} else
|
||||||
data->bus.num = 0;
|
data->bus.num = 0;
|
||||||
|
|
||||||
|
pwrscale->devfreq_wq = create_freezable_workqueue("kgsl_devfreq_wq");
|
||||||
|
if (!pwrscale->devfreq_wq) {
|
||||||
|
dev_err(device->dev, "Failed to allocate kgsl devfreq workqueue\n");
|
||||||
|
device->pwrscale.enabled = false;
|
||||||
|
return -ENOMEM;
|
||||||
|
}
|
||||||
|
|
||||||
devfreq = devfreq_add_device(dev, &pwrscale->gpu_profile.profile,
|
devfreq = devfreq_add_device(dev, &pwrscale->gpu_profile.profile,
|
||||||
governor, pwrscale->gpu_profile.private_data);
|
governor, pwrscale->gpu_profile.private_data);
|
||||||
if (IS_ERR(devfreq)) {
|
if (IS_ERR(devfreq)) {
|
||||||
@@ -1074,7 +1081,6 @@ int kgsl_pwrscale_init(struct device *dev, const char *governor)
|
|||||||
ret = sysfs_create_link(&device->dev->kobj,
|
ret = sysfs_create_link(&device->dev->kobj,
|
||||||
&devfreq->dev.kobj, "devfreq");
|
&devfreq->dev.kobj, "devfreq");
|
||||||
|
|
||||||
pwrscale->devfreq_wq = create_freezable_workqueue("kgsl_devfreq_wq");
|
|
||||||
INIT_WORK(&pwrscale->devfreq_suspend_ws, do_devfreq_suspend);
|
INIT_WORK(&pwrscale->devfreq_suspend_ws, do_devfreq_suspend);
|
||||||
INIT_WORK(&pwrscale->devfreq_resume_ws, do_devfreq_resume);
|
INIT_WORK(&pwrscale->devfreq_resume_ws, do_devfreq_resume);
|
||||||
INIT_WORK(&pwrscale->devfreq_notify_ws, do_devfreq_notify);
|
INIT_WORK(&pwrscale->devfreq_notify_ws, do_devfreq_notify);
|
||||||
@@ -1125,8 +1131,13 @@ void kgsl_pwrscale_close(struct kgsl_device *device)
|
|||||||
devfreq_cooling_unregister(pwrscale->cooling_dev);
|
devfreq_cooling_unregister(pwrscale->cooling_dev);
|
||||||
|
|
||||||
kgsl_pwrscale_midframe_timer_cancel(device);
|
kgsl_pwrscale_midframe_timer_cancel(device);
|
||||||
flush_workqueue(pwrscale->devfreq_wq);
|
|
||||||
destroy_workqueue(pwrscale->devfreq_wq);
|
if (pwrscale->devfreq_wq) {
|
||||||
|
flush_workqueue(pwrscale->devfreq_wq);
|
||||||
|
destroy_workqueue(pwrscale->devfreq_wq);
|
||||||
|
pwrscale->devfreq_wq = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
devfreq_remove_device(device->pwrscale.devfreqptr);
|
devfreq_remove_device(device->pwrscale.devfreqptr);
|
||||||
kfree(kgsl_midframe);
|
kfree(kgsl_midframe);
|
||||||
kgsl_midframe = NULL;
|
kgsl_midframe = NULL;
|
||||||
|
|||||||
@@ -51,12 +51,9 @@ set -- $(LC_ALL=C "$@" -Wa,--version -c -x assembler /dev/null -o /dev/null 2>/d
|
|||||||
IFS=' '
|
IFS=' '
|
||||||
set -- $1
|
set -- $1
|
||||||
|
|
||||||
min_tool_version=$(dirname $0)/min-tool-version.sh
|
|
||||||
|
|
||||||
if [ "$1" = GNU -a "$2" = assembler ]; then
|
if [ "$1" = GNU -a "$2" = assembler ]; then
|
||||||
shift $(($# - 1))
|
shift $(($# - 1))
|
||||||
version=$1
|
version=$1
|
||||||
min_version=$($min_tool_version binutils)
|
|
||||||
name=GNU
|
name=GNU
|
||||||
else
|
else
|
||||||
echo "$orig_args: unknown assembler invoked" >&2
|
echo "$orig_args: unknown assembler invoked" >&2
|
||||||
@@ -68,15 +65,5 @@ fi
|
|||||||
version=${version%-*}
|
version=${version%-*}
|
||||||
|
|
||||||
cversion=$(get_canonical_version $version)
|
cversion=$(get_canonical_version $version)
|
||||||
min_cversion=$(get_canonical_version $min_version)
|
|
||||||
|
|
||||||
if [ "$cversion" -lt "$min_cversion" ]; then
|
|
||||||
echo >&2 "***"
|
|
||||||
echo >&2 "*** Assembler is too old."
|
|
||||||
echo >&2 "*** Your $name assembler version: $version"
|
|
||||||
echo >&2 "*** Minimum $name assembler version: $min_version"
|
|
||||||
echo >&2 "***"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo $name $cversion
|
echo $name $cversion
|
||||||
@@ -216,6 +216,47 @@ static int _sde_debugfs_fps_status(struct inode *inode, struct file *file)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
static ssize_t early_wakeup_store(struct device *device,
|
||||||
|
struct device_attribute *attr, const char *buf, size_t count)
|
||||||
|
{
|
||||||
|
struct drm_crtc *crtc;
|
||||||
|
struct sde_crtc *sde_crtc;
|
||||||
|
struct msm_drm_private *priv;
|
||||||
|
u32 crtc_id;
|
||||||
|
bool trigger;
|
||||||
|
|
||||||
|
if (!device || !buf || !count) {
|
||||||
|
SDE_ERROR("invalid input param(s)\n");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (kstrtobool(buf, &trigger) < 0)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
if (!trigger)
|
||||||
|
return count;
|
||||||
|
|
||||||
|
crtc = dev_get_drvdata(device);
|
||||||
|
if (!crtc || !crtc->dev || !crtc->dev->dev_private) {
|
||||||
|
SDE_ERROR("invalid crtc\n");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
sde_crtc = to_sde_crtc(crtc);
|
||||||
|
priv = crtc->dev->dev_private;
|
||||||
|
|
||||||
|
crtc_id = drm_crtc_index(crtc);
|
||||||
|
if (crtc_id >= ARRAY_SIZE(priv->disp_thread)) {
|
||||||
|
SDE_ERROR("invalid crtc index[%d]\n", crtc_id);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
kthread_queue_work(&priv->disp_thread[crtc_id].worker,
|
||||||
|
&sde_crtc->early_wakeup_work);
|
||||||
|
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
static ssize_t fps_periodicity_ms_store(struct device *device,
|
static ssize_t fps_periodicity_ms_store(struct device *device,
|
||||||
struct device_attribute *attr, const char *buf, size_t count)
|
struct device_attribute *attr, const char *buf, size_t count)
|
||||||
{
|
{
|
||||||
@@ -403,12 +444,14 @@ static DEVICE_ATTR_RO(vsync_event);
|
|||||||
static DEVICE_ATTR_RO(measured_fps);
|
static DEVICE_ATTR_RO(measured_fps);
|
||||||
static DEVICE_ATTR_RW(fps_periodicity_ms);
|
static DEVICE_ATTR_RW(fps_periodicity_ms);
|
||||||
static DEVICE_ATTR_RO(retire_frame_event);
|
static DEVICE_ATTR_RO(retire_frame_event);
|
||||||
|
static DEVICE_ATTR_WO(early_wakeup);
|
||||||
|
|
||||||
static struct attribute *sde_crtc_dev_attrs[] = {
|
static struct attribute *sde_crtc_dev_attrs[] = {
|
||||||
&dev_attr_vsync_event.attr,
|
&dev_attr_vsync_event.attr,
|
||||||
&dev_attr_measured_fps.attr,
|
&dev_attr_measured_fps.attr,
|
||||||
&dev_attr_fps_periodicity_ms.attr,
|
&dev_attr_fps_periodicity_ms.attr,
|
||||||
&dev_attr_retire_frame_event.attr,
|
&dev_attr_retire_frame_event.attr,
|
||||||
|
&dev_attr_early_wakeup.attr,
|
||||||
NULL
|
NULL
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -6266,6 +6309,40 @@ static void __sde_crtc_idle_notify_work(struct kthread_work *work)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* __sde_crtc_early_wakeup_work - trigger early wakeup from user space
|
||||||
|
*/
|
||||||
|
static void __sde_crtc_early_wakeup_work(struct kthread_work *work)
|
||||||
|
{
|
||||||
|
struct sde_crtc *sde_crtc = container_of(work, struct sde_crtc,
|
||||||
|
early_wakeup_work);
|
||||||
|
struct drm_crtc *crtc;
|
||||||
|
struct drm_device *dev;
|
||||||
|
struct msm_drm_private *priv;
|
||||||
|
struct sde_kms *sde_kms;
|
||||||
|
|
||||||
|
if (!sde_crtc) {
|
||||||
|
SDE_ERROR("invalid sde crtc\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!sde_crtc->enabled) {
|
||||||
|
SDE_INFO("sde crtc is not enabled\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
crtc = &sde_crtc->base;
|
||||||
|
dev = crtc->dev;
|
||||||
|
if (!dev) {
|
||||||
|
SDE_ERROR("invalid drm device\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
priv = dev->dev_private;
|
||||||
|
sde_kms = to_sde_kms(priv->kms);
|
||||||
|
sde_kms_trigger_early_wakeup(sde_kms, crtc);
|
||||||
|
}
|
||||||
|
|
||||||
/* initialize crtc */
|
/* initialize crtc */
|
||||||
struct drm_crtc *sde_crtc_init(struct drm_device *dev, struct drm_plane *plane)
|
struct drm_crtc *sde_crtc_init(struct drm_device *dev, struct drm_plane *plane)
|
||||||
{
|
{
|
||||||
@@ -6357,6 +6434,8 @@ struct drm_crtc *sde_crtc_init(struct drm_device *dev, struct drm_plane *plane)
|
|||||||
|
|
||||||
kthread_init_delayed_work(&sde_crtc->idle_notify_work,
|
kthread_init_delayed_work(&sde_crtc->idle_notify_work,
|
||||||
__sde_crtc_idle_notify_work);
|
__sde_crtc_idle_notify_work);
|
||||||
|
kthread_init_work(&sde_crtc->early_wakeup_work,
|
||||||
|
__sde_crtc_early_wakeup_work);
|
||||||
|
|
||||||
SDE_DEBUG("crtc=%d new_llcc=%d, old_llcc=%d\n",
|
SDE_DEBUG("crtc=%d new_llcc=%d, old_llcc=%d\n",
|
||||||
crtc->base.id,
|
crtc->base.id,
|
||||||
|
|||||||
@@ -272,6 +272,7 @@ struct sde_crtc_misr_info {
|
|||||||
* @misr_frame_count : misr frame count provided by client
|
* @misr_frame_count : misr frame count provided by client
|
||||||
* @misr_data : store misr data before turning off the clocks.
|
* @misr_data : store misr data before turning off the clocks.
|
||||||
* @idle_notify_work: delayed worker to notify idle timeout to user space
|
* @idle_notify_work: delayed worker to notify idle timeout to user space
|
||||||
|
* @early_wakeup_work: work to trigger early wakeup
|
||||||
* @power_event : registered power event handle
|
* @power_event : registered power event handle
|
||||||
* @cur_perf : current performance committed to clock/bandwidth driver
|
* @cur_perf : current performance committed to clock/bandwidth driver
|
||||||
* @plane_mask_old: keeps track of the planes used in the previous commit
|
* @plane_mask_old: keeps track of the planes used in the previous commit
|
||||||
@@ -349,6 +350,7 @@ struct sde_crtc {
|
|||||||
bool misr_enable_debugfs;
|
bool misr_enable_debugfs;
|
||||||
u32 misr_frame_count;
|
u32 misr_frame_count;
|
||||||
struct kthread_delayed_work idle_notify_work;
|
struct kthread_delayed_work idle_notify_work;
|
||||||
|
struct kthread_work early_wakeup_work;
|
||||||
|
|
||||||
struct sde_power_event *power_event;
|
struct sde_power_event *power_event;
|
||||||
|
|
||||||
|
|||||||
@@ -6320,3 +6320,27 @@ void sde_encoder_recovery_events_handler(struct drm_encoder *encoder,
|
|||||||
sde_enc = to_sde_encoder_virt(encoder);
|
sde_enc = to_sde_encoder_virt(encoder);
|
||||||
sde_enc->recovery_events_enabled = enabled;
|
sde_enc->recovery_events_enabled = enabled;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void sde_encoder_trigger_early_wakeup(struct drm_encoder *drm_enc)
|
||||||
|
{
|
||||||
|
struct sde_encoder_virt *sde_enc = NULL;
|
||||||
|
struct msm_drm_private *priv = NULL;
|
||||||
|
|
||||||
|
priv = drm_enc->dev->dev_private;
|
||||||
|
sde_enc = to_sde_encoder_virt(drm_enc);
|
||||||
|
if (!sde_enc->crtc || (sde_enc->crtc->index
|
||||||
|
>= ARRAY_SIZE(priv->disp_thread))) {
|
||||||
|
SDE_DEBUG_ENC(sde_enc,
|
||||||
|
"invalid cached CRTC: %d or crtc index: %d\n",
|
||||||
|
sde_enc->crtc == NULL,
|
||||||
|
sde_enc->crtc ? sde_enc->crtc->index : -EINVAL);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sde_enc->rc_state == SDE_ENC_RC_STATE_IDLE) {
|
||||||
|
SDE_ATRACE_BEGIN("sde_encoder_resource_control");
|
||||||
|
sde_encoder_resource_control(drm_enc,
|
||||||
|
SDE_ENC_RC_EVENT_EARLY_WAKEUP);
|
||||||
|
SDE_ATRACE_END("sde_encoder_resource_control");
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -399,4 +399,10 @@ static inline struct sde_kms *sde_encoder_get_kms(struct drm_encoder *drm_enc)
|
|||||||
return to_sde_kms(priv->kms);
|
return to_sde_kms(priv->kms);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* sde_encoder_trigger_early_wakeup - trigger early wake up
|
||||||
|
* @drm_enc: Pointer to drm encoder structure
|
||||||
|
*/
|
||||||
|
void sde_encoder_trigger_early_wakeup(struct drm_encoder *drm_enc);
|
||||||
|
|
||||||
#endif /* __SDE_ENCODER_H__ */
|
#endif /* __SDE_ENCODER_H__ */
|
||||||
@@ -3945,3 +3945,26 @@ int sde_kms_handle_recovery(struct drm_encoder *encoder)
|
|||||||
SDE_EVT32(DRMID(encoder), MSM_ENC_ACTIVE_REGION);
|
SDE_EVT32(DRMID(encoder), MSM_ENC_ACTIVE_REGION);
|
||||||
return sde_encoder_wait_for_event(encoder, MSM_ENC_ACTIVE_REGION);
|
return sde_encoder_wait_for_event(encoder, MSM_ENC_ACTIVE_REGION);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void sde_kms_trigger_early_wakeup(struct sde_kms *sde_kms,
|
||||||
|
struct drm_crtc *crtc)
|
||||||
|
{
|
||||||
|
struct msm_drm_private *priv;
|
||||||
|
struct drm_encoder *drm_enc;
|
||||||
|
|
||||||
|
if (!sde_kms || !crtc) {
|
||||||
|
SDE_ERROR("invalid argument sde_kms %pK crtc %pK\n",
|
||||||
|
sde_kms, crtc);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
priv = sde_kms->dev->dev_private;
|
||||||
|
|
||||||
|
SDE_ATRACE_BEGIN("sde_kms_trigger_early_wakeup");
|
||||||
|
drm_for_each_encoder_mask(drm_enc, crtc->dev, crtc->state->encoder_mask)
|
||||||
|
sde_encoder_trigger_early_wakeup(drm_enc);
|
||||||
|
|
||||||
|
if (sde_kms->first_kickoff)
|
||||||
|
sde_power_scale_reg_bus(&priv->phandle, VOTE_INDEX_HIGH, false);
|
||||||
|
SDE_ATRACE_END("sde_kms_trigger_early_wakeup");
|
||||||
|
}
|
||||||
@@ -671,4 +671,13 @@ int sde_kms_handle_recovery(struct drm_encoder *encoder);
|
|||||||
*/
|
*/
|
||||||
void sde_kms_update_pm_qos_irq_request(struct sde_kms *sde_kms,
|
void sde_kms_update_pm_qos_irq_request(struct sde_kms *sde_kms,
|
||||||
bool enable, bool skip_lock);
|
bool enable, bool skip_lock);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* sde_kms_trigger_early_wakeup - trigger early wake up
|
||||||
|
* @sde_kms: pointer to sde_kms structure
|
||||||
|
* @crtc: pointer to drm_crtc structure
|
||||||
|
*/
|
||||||
|
void sde_kms_trigger_early_wakeup(struct sde_kms *sde_kms,
|
||||||
|
struct drm_crtc *crtc);
|
||||||
|
|
||||||
#endif /* __sde_kms_H__ */
|
#endif /* __sde_kms_H__ */
|
||||||
Reference in new issue
Block a user