mirror of
https://github.com/Fishwaldo/build.git
synced 2025-07-23 21:39:02 +00:00
2194 lines
78 KiB
Diff
2194 lines
78 KiB
Diff
From b162fb6ee80dd2a986dc4d0d4eaefd29f9152f9c Mon Sep 17 00:00:00 2001
|
|
From: Tomeu Vizoso <tomeu.vizoso@collabora.com>
|
|
Date: Thu, 11 Jun 2020 10:58:43 +0200
|
|
Subject: [PATCH] drm/panfrost: Make sure GPU is powered on when reading
|
|
GPU_LATEST_FLUSH_ID
|
|
|
|
Bifrost devices do support the flush reduction feature, so on first job
|
|
submit we were trying to read the register while still powered off.
|
|
|
|
If the GPU is powered off, the feature doesn't bring any benefit, so
|
|
don't try to read.
|
|
|
|
Tested-by: Heiko Stuebner <heiko@sntech.de>
|
|
Reviewed-by: Steven Price <steven.price@arm.com>
|
|
Signed-off-by: Tomeu Vizoso <tomeu.vizoso@collabora.com>
|
|
Signed-off-by: Rob Herring <robh@kernel.org>
|
|
Link: https://patchwork.freedesktop.org/patch/msgid/20200611085900.49740-1-tomeu.vizoso@collabora.com
|
|
(cherry picked from commit 3a74265c54f883c847ed8554129baefb3e04f135)
|
|
---
|
|
drivers/gpu/drm/panfrost/panfrost_gpu.c | 14 ++++++++++++--
|
|
1 file changed, 12 insertions(+), 2 deletions(-)
|
|
|
|
diff --git a/drivers/gpu/drm/panfrost/panfrost_gpu.c b/drivers/gpu/drm/panfrost/panfrost_gpu.c
|
|
index f2c1ddc41a9b..e0f190e43813 100644
|
|
--- a/drivers/gpu/drm/panfrost/panfrost_gpu.c
|
|
+++ b/drivers/gpu/drm/panfrost/panfrost_gpu.c
|
|
@@ -10,6 +10,7 @@
|
|
#include <linux/io.h>
|
|
#include <linux/iopoll.h>
|
|
#include <linux/platform_device.h>
|
|
+#include <linux/pm_runtime.h>
|
|
|
|
#include "panfrost_device.h"
|
|
#include "panfrost_features.h"
|
|
@@ -368,7 +369,16 @@ void panfrost_gpu_fini(struct panfrost_device *pfdev)
|
|
|
|
u32 panfrost_gpu_get_latest_flush_id(struct panfrost_device *pfdev)
|
|
{
|
|
- if (panfrost_has_hw_feature(pfdev, HW_FEATURE_FLUSH_REDUCTION))
|
|
- return gpu_read(pfdev, GPU_LATEST_FLUSH_ID);
|
|
+ u32 flush_id;
|
|
+
|
|
+ if (panfrost_has_hw_feature(pfdev, HW_FEATURE_FLUSH_REDUCTION)) {
|
|
+ /* Flush reduction only makes sense when the GPU is kept powered on between jobs */
|
|
+ if (pm_runtime_get_if_in_use(pfdev->dev)) {
|
|
+ flush_id = gpu_read(pfdev, GPU_LATEST_FLUSH_ID);
|
|
+ pm_runtime_put(pfdev->dev);
|
|
+ return flush_id;
|
|
+ }
|
|
+ }
|
|
+
|
|
return 0;
|
|
}
|
|
|
|
From 2aacfa5ced256a281c36ea2577fc5fb7a4974e9b Mon Sep 17 00:00:00 2001
|
|
From: Tomeu Vizoso <tomeu.vizoso@collabora.com>
|
|
Date: Thu, 11 Jun 2020 10:58:44 +0200
|
|
Subject: [PATCH] drm/panfrost: Add compatible string for bifrost
|
|
|
|
Mesa now supports some Bifrost devices, so enable it.
|
|
|
|
Tested-by: Heiko Stuebner <heiko@sntech.de>
|
|
Reviewed-by: Steven Price <steven.price@arm.com>
|
|
Reviewed-by: Heiko Stuebner <heiko@sntech.de>
|
|
Signed-off-by: Tomeu Vizoso <tomeu.vizoso@collabora.com>
|
|
Signed-off-by: Rob Herring <robh@kernel.org>
|
|
Link: https://patchwork.freedesktop.org/patch/msgid/20200611085900.49740-2-tomeu.vizoso@collabora.com
|
|
(cherry picked from commit 72ef7fe96fd20d3d0e538e165b393819f99870ad)
|
|
---
|
|
drivers/gpu/drm/panfrost/panfrost_drv.c | 1 +
|
|
1 file changed, 1 insertion(+)
|
|
|
|
diff --git a/drivers/gpu/drm/panfrost/panfrost_drv.c b/drivers/gpu/drm/panfrost/panfrost_drv.c
|
|
index ada51df9a7a3..f79f98534ab6 100644
|
|
--- a/drivers/gpu/drm/panfrost/panfrost_drv.c
|
|
+++ b/drivers/gpu/drm/panfrost/panfrost_drv.c
|
|
@@ -677,6 +677,7 @@ static const struct of_device_id dt_match[] = {
|
|
{ .compatible = "arm,mali-t830", .data = &default_data, },
|
|
{ .compatible = "arm,mali-t860", .data = &default_data, },
|
|
{ .compatible = "arm,mali-t880", .data = &default_data, },
|
|
+ { .compatible = "arm,mali-bifrost", .data = &default_data, },
|
|
{}
|
|
};
|
|
MODULE_DEVICE_TABLE(of, dt_match);
|
|
|
|
From ef833747ee892a26711ee7765ff81166cd5f1d52 Mon Sep 17 00:00:00 2001
|
|
From: =?UTF-8?q?Cl=C3=A9ment=20P=C3=A9ron?= <peron.clem@gmail.com>
|
|
Date: Fri, 10 Jul 2020 11:53:56 +0200
|
|
Subject: [PATCH] drm/panfrost: avoid static declaration
|
|
MIME-Version: 1.0
|
|
Content-Type: text/plain; charset=UTF-8
|
|
Content-Transfer-Encoding: 8bit
|
|
|
|
This declaration can be avoided so change it.
|
|
|
|
Reviewed-by: Steven Price <steven.price@arm.com>
|
|
Reviewed-by: Alyssa Rosenzweig <alyssa.rosenzweig@collabora.com>
|
|
Signed-off-by: Clément Péron <peron.clem@gmail.com>
|
|
Signed-off-by: Rob Herring <robh@kernel.org>
|
|
Link: https://patchwork.freedesktop.org/patch/msgid/20200710095409.407087-2-peron.clem@gmail.com
|
|
(cherry picked from commit 862cc626210e34501b4d7a7795c41a67785987e5)
|
|
---
|
|
drivers/gpu/drm/panfrost/panfrost_devfreq.c | 38 ++++++++++++++---------------
|
|
1 file changed, 18 insertions(+), 20 deletions(-)
|
|
|
|
diff --git a/drivers/gpu/drm/panfrost/panfrost_devfreq.c b/drivers/gpu/drm/panfrost/panfrost_devfreq.c
|
|
index 413987038fbf..1b560b903ea6 100644
|
|
--- a/drivers/gpu/drm/panfrost/panfrost_devfreq.c
|
|
+++ b/drivers/gpu/drm/panfrost/panfrost_devfreq.c
|
|
@@ -14,7 +14,24 @@
|
|
#include "panfrost_gpu.h"
|
|
#include "panfrost_regs.h"
|
|
|
|
-static void panfrost_devfreq_update_utilization(struct panfrost_device *pfdev);
|
|
+static void panfrost_devfreq_update_utilization(struct panfrost_device *pfdev)
|
|
+{
|
|
+ ktime_t now;
|
|
+ ktime_t last;
|
|
+
|
|
+ if (!pfdev->devfreq.devfreq)
|
|
+ return;
|
|
+
|
|
+ now = ktime_get();
|
|
+ last = pfdev->devfreq.time_last_update;
|
|
+
|
|
+ if (atomic_read(&pfdev->devfreq.busy_count) > 0)
|
|
+ pfdev->devfreq.busy_time += ktime_sub(now, last);
|
|
+ else
|
|
+ pfdev->devfreq.idle_time += ktime_sub(now, last);
|
|
+
|
|
+ pfdev->devfreq.time_last_update = now;
|
|
+}
|
|
|
|
static int panfrost_devfreq_target(struct device *dev, unsigned long *freq,
|
|
u32 flags)
|
|
@@ -139,25 +156,6 @@ void panfrost_devfreq_suspend(struct panfrost_device *pfdev)
|
|
devfreq_suspend_device(pfdev->devfreq.devfreq);
|
|
}
|
|
|
|
-static void panfrost_devfreq_update_utilization(struct panfrost_device *pfdev)
|
|
-{
|
|
- ktime_t now;
|
|
- ktime_t last;
|
|
-
|
|
- if (!pfdev->devfreq.devfreq)
|
|
- return;
|
|
-
|
|
- now = ktime_get();
|
|
- last = pfdev->devfreq.time_last_update;
|
|
-
|
|
- if (atomic_read(&pfdev->devfreq.busy_count) > 0)
|
|
- pfdev->devfreq.busy_time += ktime_sub(now, last);
|
|
- else
|
|
- pfdev->devfreq.idle_time += ktime_sub(now, last);
|
|
-
|
|
- pfdev->devfreq.time_last_update = now;
|
|
-}
|
|
-
|
|
void panfrost_devfreq_record_busy(struct panfrost_device *pfdev)
|
|
{
|
|
panfrost_devfreq_update_utilization(pfdev);
|
|
|
|
From e79051392b32df8ba3dcb9cd160f1dfe5631ca1a Mon Sep 17 00:00:00 2001
|
|
From: =?UTF-8?q?Cl=C3=A9ment=20P=C3=A9ron?= <peron.clem@gmail.com>
|
|
Date: Fri, 10 Jul 2020 11:53:57 +0200
|
|
Subject: [PATCH] drm/panfrost: clean headers in devfreq
|
|
MIME-Version: 1.0
|
|
Content-Type: text/plain; charset=UTF-8
|
|
Content-Transfer-Encoding: 8bit
|
|
|
|
Don't include not required headers and sort them.
|
|
|
|
Reviewed-by: Steven Price <steven.price@arm.com>
|
|
Reviewed-by: Alyssa Rosenzweig <alyssa.rosenzweig@collabora.com>
|
|
Signed-off-by: Clément Péron <peron.clem@gmail.com>
|
|
Signed-off-by: Rob Herring <robh@kernel.org>
|
|
Link: https://patchwork.freedesktop.org/patch/msgid/20200710095409.407087-3-peron.clem@gmail.com
|
|
(cherry picked from commit 9713e942a539c55b5e0bc64ba83b736bda1087fe)
|
|
---
|
|
drivers/gpu/drm/panfrost/panfrost_devfreq.c | 8 ++------
|
|
1 file changed, 2 insertions(+), 6 deletions(-)
|
|
|
|
diff --git a/drivers/gpu/drm/panfrost/panfrost_devfreq.c b/drivers/gpu/drm/panfrost/panfrost_devfreq.c
|
|
index 1b560b903ea6..df7b71da9a84 100644
|
|
--- a/drivers/gpu/drm/panfrost/panfrost_devfreq.c
|
|
+++ b/drivers/gpu/drm/panfrost/panfrost_devfreq.c
|
|
@@ -1,18 +1,14 @@
|
|
// SPDX-License-Identifier: GPL-2.0
|
|
/* Copyright 2019 Collabora ltd. */
|
|
+
|
|
+#include <linux/clk.h>
|
|
#include <linux/devfreq.h>
|
|
#include <linux/devfreq_cooling.h>
|
|
#include <linux/platform_device.h>
|
|
#include <linux/pm_opp.h>
|
|
-#include <linux/clk.h>
|
|
-#include <linux/regulator/consumer.h>
|
|
|
|
#include "panfrost_device.h"
|
|
#include "panfrost_devfreq.h"
|
|
-#include "panfrost_features.h"
|
|
-#include "panfrost_issues.h"
|
|
-#include "panfrost_gpu.h"
|
|
-#include "panfrost_regs.h"
|
|
|
|
static void panfrost_devfreq_update_utilization(struct panfrost_device *pfdev)
|
|
{
|
|
|
|
From b644d4b83e0c6b86565dc6e7eda0e368e855c56d Mon Sep 17 00:00:00 2001
|
|
From: =?UTF-8?q?Cl=C3=A9ment=20P=C3=A9ron?= <peron.clem@gmail.com>
|
|
Date: Fri, 10 Jul 2020 11:53:58 +0200
|
|
Subject: [PATCH] drm/panfrost: don't use pfdevfreq.busy_count to know if hw is
|
|
idle
|
|
MIME-Version: 1.0
|
|
Content-Type: text/plain; charset=UTF-8
|
|
Content-Transfer-Encoding: 8bit
|
|
|
|
This use devfreq variable that will be lock with spinlock in future
|
|
patches. We should either introduce a function to access this one
|
|
but as devfreq is optional let's just remove it.
|
|
|
|
Reviewed-by: Steven Price <steven.price@arm.com>
|
|
Reviewed-by: Alyssa Rosenzweig <alyssa.rosenzweig@collabora.com>
|
|
Signed-off-by: Clément Péron <peron.clem@gmail.com>
|
|
Signed-off-by: Rob Herring <robh@kernel.org>
|
|
Link: https://patchwork.freedesktop.org/patch/msgid/20200710095409.407087-4-peron.clem@gmail.com
|
|
(cherry picked from commit eb9dd67249b55fd1fa3d7359be387ea2079247a6)
|
|
---
|
|
drivers/gpu/drm/panfrost/panfrost_job.c | 4 ----
|
|
1 file changed, 4 deletions(-)
|
|
|
|
diff --git a/drivers/gpu/drm/panfrost/panfrost_job.c b/drivers/gpu/drm/panfrost/panfrost_job.c
|
|
index 360146f6f3d9..4c13dbae68fb 100644
|
|
--- a/drivers/gpu/drm/panfrost/panfrost_job.c
|
|
+++ b/drivers/gpu/drm/panfrost/panfrost_job.c
|
|
@@ -581,10 +581,6 @@ int panfrost_job_is_idle(struct panfrost_device *pfdev)
|
|
struct panfrost_job_slot *js = pfdev->js;
|
|
int i;
|
|
|
|
- /* Check whether the hardware is idle */
|
|
- if (atomic_read(&pfdev->devfreq.busy_count))
|
|
- return false;
|
|
-
|
|
for (i = 0; i < NUM_JOB_SLOTS; i++) {
|
|
/* If there are any jobs in the HW queue, we're not idle */
|
|
if (atomic_read(&js->queue[i].sched.hw_rq_count))
|
|
|
|
From 1a29b20297e3cfb87ccd6c2a05b385b1a3adf099 Mon Sep 17 00:00:00 2001
|
|
From: =?UTF-8?q?Cl=C3=A9ment=20P=C3=A9ron?= <peron.clem@gmail.com>
|
|
Date: Fri, 10 Jul 2020 11:53:59 +0200
|
|
Subject: [PATCH] drm/panfrost: introduce panfrost_devfreq struct
|
|
MIME-Version: 1.0
|
|
Content-Type: text/plain; charset=UTF-8
|
|
Content-Transfer-Encoding: 8bit
|
|
|
|
Introduce a proper panfrost_devfreq to deal with devfreq variables.
|
|
|
|
Reviewed-by: Steven Price <steven.price@arm.com>
|
|
Reviewed-by: Alyssa Rosenzweig <alyssa.rosenzweig@collabora.com>
|
|
Signed-off-by: Clément Péron <peron.clem@gmail.com>
|
|
Signed-off-by: Rob Herring <robh@kernel.org>
|
|
Link: https://patchwork.freedesktop.org/patch/msgid/20200710095409.407087-5-peron.clem@gmail.com
|
|
(cherry picked from commit 9bfacfc82f903b066b0b63460d5b7943705048a4)
|
|
---
|
|
drivers/gpu/drm/panfrost/panfrost_devfreq.c | 76 ++++++++++++++++-------------
|
|
drivers/gpu/drm/panfrost/panfrost_devfreq.h | 20 +++++++-
|
|
drivers/gpu/drm/panfrost/panfrost_device.h | 11 ++---
|
|
drivers/gpu/drm/panfrost/panfrost_job.c | 6 +--
|
|
4 files changed, 66 insertions(+), 47 deletions(-)
|
|
|
|
diff --git a/drivers/gpu/drm/panfrost/panfrost_devfreq.c b/drivers/gpu/drm/panfrost/panfrost_devfreq.c
|
|
index df7b71da9a84..962550363391 100644
|
|
--- a/drivers/gpu/drm/panfrost/panfrost_devfreq.c
|
|
+++ b/drivers/gpu/drm/panfrost/panfrost_devfreq.c
|
|
@@ -10,23 +10,23 @@
|
|
#include "panfrost_device.h"
|
|
#include "panfrost_devfreq.h"
|
|
|
|
-static void panfrost_devfreq_update_utilization(struct panfrost_device *pfdev)
|
|
+static void panfrost_devfreq_update_utilization(struct panfrost_devfreq *pfdevfreq)
|
|
{
|
|
ktime_t now;
|
|
ktime_t last;
|
|
|
|
- if (!pfdev->devfreq.devfreq)
|
|
+ if (!pfdevfreq->devfreq)
|
|
return;
|
|
|
|
now = ktime_get();
|
|
- last = pfdev->devfreq.time_last_update;
|
|
+ last = pfdevfreq->time_last_update;
|
|
|
|
- if (atomic_read(&pfdev->devfreq.busy_count) > 0)
|
|
- pfdev->devfreq.busy_time += ktime_sub(now, last);
|
|
+ if (atomic_read(&pfdevfreq->busy_count) > 0)
|
|
+ pfdevfreq->busy_time += ktime_sub(now, last);
|
|
else
|
|
- pfdev->devfreq.idle_time += ktime_sub(now, last);
|
|
+ pfdevfreq->idle_time += ktime_sub(now, last);
|
|
|
|
- pfdev->devfreq.time_last_update = now;
|
|
+ pfdevfreq->time_last_update = now;
|
|
}
|
|
|
|
static int panfrost_devfreq_target(struct device *dev, unsigned long *freq,
|
|
@@ -47,30 +47,31 @@ static int panfrost_devfreq_target(struct device *dev, unsigned long *freq,
|
|
return 0;
|
|
}
|
|
|
|
-static void panfrost_devfreq_reset(struct panfrost_device *pfdev)
|
|
+static void panfrost_devfreq_reset(struct panfrost_devfreq *pfdevfreq)
|
|
{
|
|
- pfdev->devfreq.busy_time = 0;
|
|
- pfdev->devfreq.idle_time = 0;
|
|
- pfdev->devfreq.time_last_update = ktime_get();
|
|
+ pfdevfreq->busy_time = 0;
|
|
+ pfdevfreq->idle_time = 0;
|
|
+ pfdevfreq->time_last_update = ktime_get();
|
|
}
|
|
|
|
static int panfrost_devfreq_get_dev_status(struct device *dev,
|
|
struct devfreq_dev_status *status)
|
|
{
|
|
struct panfrost_device *pfdev = dev_get_drvdata(dev);
|
|
+ struct panfrost_devfreq *pfdevfreq = &pfdev->pfdevfreq;
|
|
|
|
- panfrost_devfreq_update_utilization(pfdev);
|
|
+ panfrost_devfreq_update_utilization(pfdevfreq);
|
|
|
|
status->current_frequency = clk_get_rate(pfdev->clock);
|
|
- status->total_time = ktime_to_ns(ktime_add(pfdev->devfreq.busy_time,
|
|
- pfdev->devfreq.idle_time));
|
|
+ status->total_time = ktime_to_ns(ktime_add(pfdevfreq->busy_time,
|
|
+ pfdevfreq->idle_time));
|
|
|
|
- status->busy_time = ktime_to_ns(pfdev->devfreq.busy_time);
|
|
+ status->busy_time = ktime_to_ns(pfdevfreq->busy_time);
|
|
|
|
- panfrost_devfreq_reset(pfdev);
|
|
+ panfrost_devfreq_reset(pfdevfreq);
|
|
|
|
- dev_dbg(pfdev->dev, "busy %lu total %lu %lu %% freq %lu MHz\n", status->busy_time,
|
|
- status->total_time,
|
|
+ dev_dbg(pfdev->dev, "busy %lu total %lu %lu %% freq %lu MHz\n",
|
|
+ status->busy_time, status->total_time,
|
|
status->busy_time / (status->total_time / 100),
|
|
status->current_frequency / 1000 / 1000);
|
|
|
|
@@ -91,6 +92,7 @@ int panfrost_devfreq_init(struct panfrost_device *pfdev)
|
|
struct device *dev = &pfdev->pdev->dev;
|
|
struct devfreq *devfreq;
|
|
struct thermal_cooling_device *cooling;
|
|
+ struct panfrost_devfreq *pfdevfreq = &pfdev->pfdevfreq;
|
|
|
|
ret = dev_pm_opp_of_add_table(dev);
|
|
if (ret == -ENODEV) /* Optional, continue without devfreq */
|
|
@@ -98,7 +100,7 @@ int panfrost_devfreq_init(struct panfrost_device *pfdev)
|
|
else if (ret)
|
|
return ret;
|
|
|
|
- panfrost_devfreq_reset(pfdev);
|
|
+ panfrost_devfreq_reset(pfdevfreq);
|
|
|
|
cur_freq = clk_get_rate(pfdev->clock);
|
|
|
|
@@ -116,53 +118,59 @@ int panfrost_devfreq_init(struct panfrost_device *pfdev)
|
|
dev_pm_opp_of_remove_table(dev);
|
|
return PTR_ERR(devfreq);
|
|
}
|
|
- pfdev->devfreq.devfreq = devfreq;
|
|
+ pfdevfreq->devfreq = devfreq;
|
|
|
|
cooling = of_devfreq_cooling_register(dev->of_node, devfreq);
|
|
if (IS_ERR(cooling))
|
|
DRM_DEV_INFO(dev, "Failed to register cooling device\n");
|
|
else
|
|
- pfdev->devfreq.cooling = cooling;
|
|
+ pfdevfreq->cooling = cooling;
|
|
|
|
return 0;
|
|
}
|
|
|
|
void panfrost_devfreq_fini(struct panfrost_device *pfdev)
|
|
{
|
|
- if (pfdev->devfreq.cooling)
|
|
- devfreq_cooling_unregister(pfdev->devfreq.cooling);
|
|
+ struct panfrost_devfreq *pfdevfreq = &pfdev->pfdevfreq;
|
|
+
|
|
+ if (pfdevfreq->cooling)
|
|
+ devfreq_cooling_unregister(pfdevfreq->cooling);
|
|
dev_pm_opp_of_remove_table(&pfdev->pdev->dev);
|
|
}
|
|
|
|
void panfrost_devfreq_resume(struct panfrost_device *pfdev)
|
|
{
|
|
- if (!pfdev->devfreq.devfreq)
|
|
+ struct panfrost_devfreq *pfdevfreq = &pfdev->pfdevfreq;
|
|
+
|
|
+ if (!pfdevfreq->devfreq)
|
|
return;
|
|
|
|
- panfrost_devfreq_reset(pfdev);
|
|
+ panfrost_devfreq_reset(pfdevfreq);
|
|
|
|
- devfreq_resume_device(pfdev->devfreq.devfreq);
|
|
+ devfreq_resume_device(pfdevfreq->devfreq);
|
|
}
|
|
|
|
void panfrost_devfreq_suspend(struct panfrost_device *pfdev)
|
|
{
|
|
- if (!pfdev->devfreq.devfreq)
|
|
+ struct panfrost_devfreq *pfdevfreq = &pfdev->pfdevfreq;
|
|
+
|
|
+ if (!pfdevfreq->devfreq)
|
|
return;
|
|
|
|
- devfreq_suspend_device(pfdev->devfreq.devfreq);
|
|
+ devfreq_suspend_device(pfdevfreq->devfreq);
|
|
}
|
|
|
|
-void panfrost_devfreq_record_busy(struct panfrost_device *pfdev)
|
|
+void panfrost_devfreq_record_busy(struct panfrost_devfreq *pfdevfreq)
|
|
{
|
|
- panfrost_devfreq_update_utilization(pfdev);
|
|
- atomic_inc(&pfdev->devfreq.busy_count);
|
|
+ panfrost_devfreq_update_utilization(pfdevfreq);
|
|
+ atomic_inc(&pfdevfreq->busy_count);
|
|
}
|
|
|
|
-void panfrost_devfreq_record_idle(struct panfrost_device *pfdev)
|
|
+void panfrost_devfreq_record_idle(struct panfrost_devfreq *pfdevfreq)
|
|
{
|
|
int count;
|
|
|
|
- panfrost_devfreq_update_utilization(pfdev);
|
|
- count = atomic_dec_if_positive(&pfdev->devfreq.busy_count);
|
|
+ panfrost_devfreq_update_utilization(pfdevfreq);
|
|
+ count = atomic_dec_if_positive(&pfdevfreq->busy_count);
|
|
WARN_ON(count < 0);
|
|
}
|
|
diff --git a/drivers/gpu/drm/panfrost/panfrost_devfreq.h b/drivers/gpu/drm/panfrost/panfrost_devfreq.h
|
|
index 0611beffc8d0..0697f8d5aa34 100644
|
|
--- a/drivers/gpu/drm/panfrost/panfrost_devfreq.h
|
|
+++ b/drivers/gpu/drm/panfrost/panfrost_devfreq.h
|
|
@@ -4,13 +4,29 @@
|
|
#ifndef __PANFROST_DEVFREQ_H__
|
|
#define __PANFROST_DEVFREQ_H__
|
|
|
|
+#include <linux/ktime.h>
|
|
+
|
|
+struct devfreq;
|
|
+struct thermal_cooling_device;
|
|
+
|
|
+struct panfrost_device;
|
|
+
|
|
+struct panfrost_devfreq {
|
|
+ struct devfreq *devfreq;
|
|
+ struct thermal_cooling_device *cooling;
|
|
+ ktime_t busy_time;
|
|
+ ktime_t idle_time;
|
|
+ ktime_t time_last_update;
|
|
+ atomic_t busy_count;
|
|
+};
|
|
+
|
|
int panfrost_devfreq_init(struct panfrost_device *pfdev);
|
|
void panfrost_devfreq_fini(struct panfrost_device *pfdev);
|
|
|
|
void panfrost_devfreq_resume(struct panfrost_device *pfdev);
|
|
void panfrost_devfreq_suspend(struct panfrost_device *pfdev);
|
|
|
|
-void panfrost_devfreq_record_busy(struct panfrost_device *pfdev);
|
|
-void panfrost_devfreq_record_idle(struct panfrost_device *pfdev);
|
|
+void panfrost_devfreq_record_busy(struct panfrost_devfreq *devfreq);
|
|
+void panfrost_devfreq_record_idle(struct panfrost_devfreq *devfreq);
|
|
|
|
#endif /* __PANFROST_DEVFREQ_H__ */
|
|
diff --git a/drivers/gpu/drm/panfrost/panfrost_device.h b/drivers/gpu/drm/panfrost/panfrost_device.h
|
|
index c30c719a8059..2efa59c9d1c5 100644
|
|
--- a/drivers/gpu/drm/panfrost/panfrost_device.h
|
|
+++ b/drivers/gpu/drm/panfrost/panfrost_device.h
|
|
@@ -13,6 +13,8 @@
|
|
#include <drm/drm_mm.h>
|
|
#include <drm/gpu_scheduler.h>
|
|
|
|
+#include "panfrost_devfreq.h"
|
|
+
|
|
struct panfrost_device;
|
|
struct panfrost_mmu;
|
|
struct panfrost_job_slot;
|
|
@@ -107,14 +109,7 @@ struct panfrost_device {
|
|
struct list_head shrinker_list;
|
|
struct shrinker shrinker;
|
|
|
|
- struct {
|
|
- struct devfreq *devfreq;
|
|
- struct thermal_cooling_device *cooling;
|
|
- ktime_t busy_time;
|
|
- ktime_t idle_time;
|
|
- ktime_t time_last_update;
|
|
- atomic_t busy_count;
|
|
- } devfreq;
|
|
+ struct panfrost_devfreq pfdevfreq;
|
|
};
|
|
|
|
struct panfrost_mmu {
|
|
diff --git a/drivers/gpu/drm/panfrost/panfrost_job.c b/drivers/gpu/drm/panfrost/panfrost_job.c
|
|
index 4c13dbae68fb..30e7b7196dab 100644
|
|
--- a/drivers/gpu/drm/panfrost/panfrost_job.c
|
|
+++ b/drivers/gpu/drm/panfrost/panfrost_job.c
|
|
@@ -145,7 +145,7 @@ static void panfrost_job_hw_submit(struct panfrost_job *job, int js)
|
|
u64 jc_head = job->jc;
|
|
int ret;
|
|
|
|
- panfrost_devfreq_record_busy(pfdev);
|
|
+ panfrost_devfreq_record_busy(&pfdev->pfdevfreq);
|
|
|
|
ret = pm_runtime_get_sync(pfdev->dev);
|
|
if (ret < 0)
|
|
@@ -410,7 +410,7 @@ static void panfrost_job_timedout(struct drm_sched_job *sched_job)
|
|
for (i = 0; i < NUM_JOB_SLOTS; i++) {
|
|
if (pfdev->jobs[i]) {
|
|
pm_runtime_put_noidle(pfdev->dev);
|
|
- panfrost_devfreq_record_idle(pfdev);
|
|
+ panfrost_devfreq_record_idle(&pfdev->pfdevfreq);
|
|
pfdev->jobs[i] = NULL;
|
|
}
|
|
}
|
|
@@ -478,7 +478,7 @@ static irqreturn_t panfrost_job_irq_handler(int irq, void *data)
|
|
pfdev->jobs[j] = NULL;
|
|
|
|
panfrost_mmu_as_put(pfdev, &job->file_priv->mmu);
|
|
- panfrost_devfreq_record_idle(pfdev);
|
|
+ panfrost_devfreq_record_idle(&pfdev->pfdevfreq);
|
|
|
|
dma_fence_signal_locked(job->done_fence);
|
|
pm_runtime_put_autosuspend(pfdev->dev);
|
|
|
|
From c0bae02328a32aabc9cd41f37ab93623ea2ea3e3 Mon Sep 17 00:00:00 2001
|
|
From: =?UTF-8?q?Cl=C3=A9ment=20P=C3=A9ron?= <peron.clem@gmail.com>
|
|
Date: Fri, 10 Jul 2020 11:54:00 +0200
|
|
Subject: [PATCH] drm/panfrost: use spinlock instead of atomic
|
|
MIME-Version: 1.0
|
|
Content-Type: text/plain; charset=UTF-8
|
|
Content-Transfer-Encoding: 8bit
|
|
|
|
Convert busy_count to a simple int protected by spinlock.
|
|
|
|
Reviewed-by: Steven Price <steven.price@arm.com>
|
|
Reviewed-by: Alyssa Rosenzweig <alyssa.rosenzweig@collabora.com>
|
|
Signed-off-by: Clément Péron <peron.clem@gmail.com>
|
|
Signed-off-by: Rob Herring <robh@kernel.org>
|
|
Link: https://patchwork.freedesktop.org/patch/msgid/20200710095409.407087-6-peron.clem@gmail.com
|
|
(cherry picked from commit ed85df3f60740bb4be23fbc2db283d59b361a834)
|
|
---
|
|
drivers/gpu/drm/panfrost/panfrost_devfreq.c | 43 +++++++++++++++++++++--------
|
|
drivers/gpu/drm/panfrost/panfrost_devfreq.h | 9 +++++-
|
|
2 files changed, 40 insertions(+), 12 deletions(-)
|
|
|
|
diff --git a/drivers/gpu/drm/panfrost/panfrost_devfreq.c b/drivers/gpu/drm/panfrost/panfrost_devfreq.c
|
|
index 962550363391..78753cfb59fb 100644
|
|
--- a/drivers/gpu/drm/panfrost/panfrost_devfreq.c
|
|
+++ b/drivers/gpu/drm/panfrost/panfrost_devfreq.c
|
|
@@ -12,16 +12,12 @@
|
|
|
|
static void panfrost_devfreq_update_utilization(struct panfrost_devfreq *pfdevfreq)
|
|
{
|
|
- ktime_t now;
|
|
- ktime_t last;
|
|
-
|
|
- if (!pfdevfreq->devfreq)
|
|
- return;
|
|
+ ktime_t now, last;
|
|
|
|
now = ktime_get();
|
|
last = pfdevfreq->time_last_update;
|
|
|
|
- if (atomic_read(&pfdevfreq->busy_count) > 0)
|
|
+ if (pfdevfreq->busy_count > 0)
|
|
pfdevfreq->busy_time += ktime_sub(now, last);
|
|
else
|
|
pfdevfreq->idle_time += ktime_sub(now, last);
|
|
@@ -59,10 +55,14 @@ static int panfrost_devfreq_get_dev_status(struct device *dev,
|
|
{
|
|
struct panfrost_device *pfdev = dev_get_drvdata(dev);
|
|
struct panfrost_devfreq *pfdevfreq = &pfdev->pfdevfreq;
|
|
+ unsigned long irqflags;
|
|
+
|
|
+ status->current_frequency = clk_get_rate(pfdev->clock);
|
|
+
|
|
+ spin_lock_irqsave(&pfdevfreq->lock, irqflags);
|
|
|
|
panfrost_devfreq_update_utilization(pfdevfreq);
|
|
|
|
- status->current_frequency = clk_get_rate(pfdev->clock);
|
|
status->total_time = ktime_to_ns(ktime_add(pfdevfreq->busy_time,
|
|
pfdevfreq->idle_time));
|
|
|
|
@@ -70,6 +70,8 @@ static int panfrost_devfreq_get_dev_status(struct device *dev,
|
|
|
|
panfrost_devfreq_reset(pfdevfreq);
|
|
|
|
+ spin_unlock_irqrestore(&pfdevfreq->lock, irqflags);
|
|
+
|
|
dev_dbg(pfdev->dev, "busy %lu total %lu %lu %% freq %lu MHz\n",
|
|
status->busy_time, status->total_time,
|
|
status->busy_time / (status->total_time / 100),
|
|
@@ -100,6 +102,8 @@ int panfrost_devfreq_init(struct panfrost_device *pfdev)
|
|
else if (ret)
|
|
return ret;
|
|
|
|
+ spin_lock_init(&pfdevfreq->lock);
|
|
+
|
|
panfrost_devfreq_reset(pfdevfreq);
|
|
|
|
cur_freq = clk_get_rate(pfdev->clock);
|
|
@@ -162,15 +166,32 @@ void panfrost_devfreq_suspend(struct panfrost_device *pfdev)
|
|
|
|
void panfrost_devfreq_record_busy(struct panfrost_devfreq *pfdevfreq)
|
|
{
|
|
+ unsigned long irqflags;
|
|
+
|
|
+ if (!pfdevfreq->devfreq)
|
|
+ return;
|
|
+
|
|
+ spin_lock_irqsave(&pfdevfreq->lock, irqflags);
|
|
+
|
|
panfrost_devfreq_update_utilization(pfdevfreq);
|
|
- atomic_inc(&pfdevfreq->busy_count);
|
|
+
|
|
+ pfdevfreq->busy_count++;
|
|
+
|
|
+ spin_unlock_irqrestore(&pfdevfreq->lock, irqflags);
|
|
}
|
|
|
|
void panfrost_devfreq_record_idle(struct panfrost_devfreq *pfdevfreq)
|
|
{
|
|
- int count;
|
|
+ unsigned long irqflags;
|
|
+
|
|
+ if (!pfdevfreq->devfreq)
|
|
+ return;
|
|
+
|
|
+ spin_lock_irqsave(&pfdevfreq->lock, irqflags);
|
|
|
|
panfrost_devfreq_update_utilization(pfdevfreq);
|
|
- count = atomic_dec_if_positive(&pfdevfreq->busy_count);
|
|
- WARN_ON(count < 0);
|
|
+
|
|
+ WARN_ON(--pfdevfreq->busy_count < 0);
|
|
+
|
|
+ spin_unlock_irqrestore(&pfdevfreq->lock, irqflags);
|
|
}
|
|
diff --git a/drivers/gpu/drm/panfrost/panfrost_devfreq.h b/drivers/gpu/drm/panfrost/panfrost_devfreq.h
|
|
index 0697f8d5aa34..3392df1020be 100644
|
|
--- a/drivers/gpu/drm/panfrost/panfrost_devfreq.h
|
|
+++ b/drivers/gpu/drm/panfrost/panfrost_devfreq.h
|
|
@@ -4,6 +4,7 @@
|
|
#ifndef __PANFROST_DEVFREQ_H__
|
|
#define __PANFROST_DEVFREQ_H__
|
|
|
|
+#include <linux/spinlock.h>
|
|
#include <linux/ktime.h>
|
|
|
|
struct devfreq;
|
|
@@ -14,10 +15,16 @@ struct panfrost_device;
|
|
struct panfrost_devfreq {
|
|
struct devfreq *devfreq;
|
|
struct thermal_cooling_device *cooling;
|
|
+
|
|
ktime_t busy_time;
|
|
ktime_t idle_time;
|
|
ktime_t time_last_update;
|
|
- atomic_t busy_count;
|
|
+ int busy_count;
|
|
+ /*
|
|
+ * Protect busy_time, idle_time, time_last_update and busy_count
|
|
+ * because these can be updated concurrently between multiple jobs.
|
|
+ */
|
|
+ spinlock_t lock;
|
|
};
|
|
|
|
int panfrost_devfreq_init(struct panfrost_device *pfdev);
|
|
|
|
From f2c14c5a166e0d30ef41f6b4e4b8e7904dc931da Mon Sep 17 00:00:00 2001
|
|
From: =?UTF-8?q?Cl=C3=A9ment=20P=C3=A9ron?= <peron.clem@gmail.com>
|
|
Date: Fri, 10 Jul 2020 11:54:01 +0200
|
|
Subject: [PATCH] drm/panfrost: properly handle error in probe
|
|
MIME-Version: 1.0
|
|
Content-Type: text/plain; charset=UTF-8
|
|
Content-Transfer-Encoding: 8bit
|
|
|
|
Introduce a boolean to know if opp table has been added.
|
|
|
|
With this, we can call panfrost_devfreq_fini() in case of error
|
|
and release what has been initialised.
|
|
|
|
Reviewed-by: Steven Price <steven.price@arm.com>
|
|
Reviewed-by: Alyssa Rosenzweig <alyssa.rosenzweig@collabora.com>
|
|
Signed-off-by: Clément Péron <peron.clem@gmail.com>
|
|
Signed-off-by: Rob Herring <robh@kernel.org>
|
|
Link: https://patchwork.freedesktop.org/patch/msgid/20200710095409.407087-7-peron.clem@gmail.com
|
|
(cherry picked from commit 81f2fbe62cb54b6cf3d91078c4d49451ba7b9877)
|
|
---
|
|
drivers/gpu/drm/panfrost/panfrost_devfreq.c | 25 +++++++++++++++++++------
|
|
drivers/gpu/drm/panfrost/panfrost_devfreq.h | 1 +
|
|
2 files changed, 20 insertions(+), 6 deletions(-)
|
|
|
|
diff --git a/drivers/gpu/drm/panfrost/panfrost_devfreq.c b/drivers/gpu/drm/panfrost/panfrost_devfreq.c
|
|
index 78753cfb59fb..d9007f44b772 100644
|
|
--- a/drivers/gpu/drm/panfrost/panfrost_devfreq.c
|
|
+++ b/drivers/gpu/drm/panfrost/panfrost_devfreq.c
|
|
@@ -101,6 +101,7 @@ int panfrost_devfreq_init(struct panfrost_device *pfdev)
|
|
return 0;
|
|
else if (ret)
|
|
return ret;
|
|
+ pfdevfreq->opp_of_table_added = true;
|
|
|
|
spin_lock_init(&pfdevfreq->lock);
|
|
|
|
@@ -109,8 +110,10 @@ int panfrost_devfreq_init(struct panfrost_device *pfdev)
|
|
cur_freq = clk_get_rate(pfdev->clock);
|
|
|
|
opp = devfreq_recommended_opp(dev, &cur_freq, 0);
|
|
- if (IS_ERR(opp))
|
|
- return PTR_ERR(opp);
|
|
+ if (IS_ERR(opp)) {
|
|
+ ret = PTR_ERR(opp);
|
|
+ goto err_fini;
|
|
+ }
|
|
|
|
panfrost_devfreq_profile.initial_freq = cur_freq;
|
|
dev_pm_opp_put(opp);
|
|
@@ -119,8 +122,8 @@ int panfrost_devfreq_init(struct panfrost_device *pfdev)
|
|
DEVFREQ_GOV_SIMPLE_ONDEMAND, NULL);
|
|
if (IS_ERR(devfreq)) {
|
|
DRM_DEV_ERROR(dev, "Couldn't initialize GPU devfreq\n");
|
|
- dev_pm_opp_of_remove_table(dev);
|
|
- return PTR_ERR(devfreq);
|
|
+ ret = PTR_ERR(devfreq);
|
|
+ goto err_fini;
|
|
}
|
|
pfdevfreq->devfreq = devfreq;
|
|
|
|
@@ -131,15 +134,25 @@ int panfrost_devfreq_init(struct panfrost_device *pfdev)
|
|
pfdevfreq->cooling = cooling;
|
|
|
|
return 0;
|
|
+
|
|
+err_fini:
|
|
+ panfrost_devfreq_fini(pfdev);
|
|
+ return ret;
|
|
}
|
|
|
|
void panfrost_devfreq_fini(struct panfrost_device *pfdev)
|
|
{
|
|
struct panfrost_devfreq *pfdevfreq = &pfdev->pfdevfreq;
|
|
|
|
- if (pfdevfreq->cooling)
|
|
+ if (pfdevfreq->cooling) {
|
|
devfreq_cooling_unregister(pfdevfreq->cooling);
|
|
- dev_pm_opp_of_remove_table(&pfdev->pdev->dev);
|
|
+ pfdevfreq->cooling = NULL;
|
|
+ }
|
|
+
|
|
+ if (pfdevfreq->opp_of_table_added) {
|
|
+ dev_pm_opp_of_remove_table(&pfdev->pdev->dev);
|
|
+ pfdevfreq->opp_of_table_added = false;
|
|
+ }
|
|
}
|
|
|
|
void panfrost_devfreq_resume(struct panfrost_device *pfdev)
|
|
diff --git a/drivers/gpu/drm/panfrost/panfrost_devfreq.h b/drivers/gpu/drm/panfrost/panfrost_devfreq.h
|
|
index 3392df1020be..210269944687 100644
|
|
--- a/drivers/gpu/drm/panfrost/panfrost_devfreq.h
|
|
+++ b/drivers/gpu/drm/panfrost/panfrost_devfreq.h
|
|
@@ -15,6 +15,7 @@ struct panfrost_device;
|
|
struct panfrost_devfreq {
|
|
struct devfreq *devfreq;
|
|
struct thermal_cooling_device *cooling;
|
|
+ bool opp_of_table_added;
|
|
|
|
ktime_t busy_time;
|
|
ktime_t idle_time;
|
|
|
|
From 6d5816fcaa6621b0f7bb9c07bdc4a74696b0d4f6 Mon Sep 17 00:00:00 2001
|
|
From: =?UTF-8?q?Cl=C3=A9ment=20P=C3=A9ron?= <peron.clem@gmail.com>
|
|
Date: Fri, 10 Jul 2020 11:54:04 +0200
|
|
Subject: [PATCH] drm/panfrost: dynamically alloc regulators
|
|
MIME-Version: 1.0
|
|
Content-Type: text/plain; charset=UTF-8
|
|
Content-Transfer-Encoding: 8bit
|
|
|
|
We will later introduce regulators managed by OPP.
|
|
|
|
Only alloc regulators when it's needed. This also help use
|
|
to release the regulators only when they are allocated.
|
|
|
|
Reviewed-by: Steven Price <steven.price@arm.com>
|
|
Reviewed-by: Alyssa Rosenzweig <alyssa.rosenzweig@collabora.com>
|
|
Signed-off-by: Clément Péron <peron.clem@gmail.com>
|
|
Signed-off-by: Rob Herring <robh@kernel.org>
|
|
Link: https://patchwork.freedesktop.org/patch/msgid/20200710095409.407087-10-peron.clem@gmail.com
|
|
(cherry picked from commit 512f21227fd3d2dbe7aad57a995b9732229c9b56)
|
|
---
|
|
drivers/gpu/drm/panfrost/panfrost_device.c | 14 +++++++++-----
|
|
drivers/gpu/drm/panfrost/panfrost_device.h | 3 +--
|
|
2 files changed, 10 insertions(+), 7 deletions(-)
|
|
|
|
diff --git a/drivers/gpu/drm/panfrost/panfrost_device.c b/drivers/gpu/drm/panfrost/panfrost_device.c
|
|
index 36b5c8fea3eb..f1474b961def 100644
|
|
--- a/drivers/gpu/drm/panfrost/panfrost_device.c
|
|
+++ b/drivers/gpu/drm/panfrost/panfrost_device.c
|
|
@@ -90,9 +90,11 @@ static int panfrost_regulator_init(struct panfrost_device *pfdev)
|
|
{
|
|
int ret, i;
|
|
|
|
- if (WARN(pfdev->comp->num_supplies > ARRAY_SIZE(pfdev->regulators),
|
|
- "Too many supplies in compatible structure.\n"))
|
|
- return -EINVAL;
|
|
+ pfdev->regulators = devm_kcalloc(pfdev->dev, pfdev->comp->num_supplies,
|
|
+ sizeof(*pfdev->regulators),
|
|
+ GFP_KERNEL);
|
|
+ if (!pfdev->regulators)
|
|
+ return -ENOMEM;
|
|
|
|
for (i = 0; i < pfdev->comp->num_supplies; i++)
|
|
pfdev->regulators[i].supply = pfdev->comp->supply_names[i];
|
|
@@ -119,8 +121,10 @@ static int panfrost_regulator_init(struct panfrost_device *pfdev)
|
|
|
|
static void panfrost_regulator_fini(struct panfrost_device *pfdev)
|
|
{
|
|
- regulator_bulk_disable(pfdev->comp->num_supplies,
|
|
- pfdev->regulators);
|
|
+ if (!pfdev->regulators)
|
|
+ return;
|
|
+
|
|
+ regulator_bulk_disable(pfdev->comp->num_supplies, pfdev->regulators);
|
|
}
|
|
|
|
static void panfrost_pm_domain_fini(struct panfrost_device *pfdev)
|
|
diff --git a/drivers/gpu/drm/panfrost/panfrost_device.h b/drivers/gpu/drm/panfrost/panfrost_device.h
|
|
index 2efa59c9d1c5..953f7536a773 100644
|
|
--- a/drivers/gpu/drm/panfrost/panfrost_device.h
|
|
+++ b/drivers/gpu/drm/panfrost/panfrost_device.h
|
|
@@ -22,7 +22,6 @@ struct panfrost_job;
|
|
struct panfrost_perfcnt;
|
|
|
|
#define NUM_JOB_SLOTS 3
|
|
-#define MAX_REGULATORS 2
|
|
#define MAX_PM_DOMAINS 3
|
|
|
|
struct panfrost_features {
|
|
@@ -81,7 +80,7 @@ struct panfrost_device {
|
|
void __iomem *iomem;
|
|
struct clk *clock;
|
|
struct clk *bus_clock;
|
|
- struct regulator_bulk_data regulators[MAX_REGULATORS];
|
|
+ struct regulator_bulk_data *regulators;
|
|
struct reset_control *rstc;
|
|
/* pm_domains for devices with more than one. */
|
|
struct device *pm_domain_devs[MAX_PM_DOMAINS];
|
|
|
|
From 132fdf3d6a3bb089fa4e7aab7306d98dfeff3273 Mon Sep 17 00:00:00 2001
|
|
From: =?UTF-8?q?Cl=C3=A9ment=20P=C3=A9ron?= <peron.clem@gmail.com>
|
|
Date: Fri, 10 Jul 2020 11:54:05 +0200
|
|
Subject: [PATCH] drm/panfrost: add regulators to devfreq
|
|
MIME-Version: 1.0
|
|
Content-Type: text/plain; charset=UTF-8
|
|
Content-Transfer-Encoding: 8bit
|
|
|
|
Some OPP tables specify voltage for each frequency. Devfreq can
|
|
handle these regulators but they should be get only 1 time to avoid
|
|
issue and know who is in charge.
|
|
|
|
If OPP table is probe don't init regulator.
|
|
|
|
Reviewed-by: Steven Price <steven.price@arm.com>
|
|
Reviewed-by: Alyssa Rosenzweig <alyssa.rosenzweig@collabora.com>
|
|
Signed-off-by: Clément Péron <peron.clem@gmail.com>
|
|
Signed-off-by: Rob Herring <robh@kernel.org>
|
|
Link: https://patchwork.freedesktop.org/patch/msgid/20200710095409.407087-11-peron.clem@gmail.com
|
|
(cherry picked from commit fd587ff01d59554144e2fd20f4113638a45c7c4e)
|
|
---
|
|
drivers/gpu/drm/panfrost/panfrost_devfreq.c | 29 +++++++++++++++++++++++++----
|
|
drivers/gpu/drm/panfrost/panfrost_devfreq.h | 2 ++
|
|
drivers/gpu/drm/panfrost/panfrost_device.c | 9 ++++++---
|
|
3 files changed, 33 insertions(+), 7 deletions(-)
|
|
|
|
diff --git a/drivers/gpu/drm/panfrost/panfrost_devfreq.c b/drivers/gpu/drm/panfrost/panfrost_devfreq.c
|
|
index d9007f44b772..8ab025d0035f 100644
|
|
--- a/drivers/gpu/drm/panfrost/panfrost_devfreq.c
|
|
+++ b/drivers/gpu/drm/panfrost/panfrost_devfreq.c
|
|
@@ -93,14 +93,30 @@ int panfrost_devfreq_init(struct panfrost_device *pfdev)
|
|
unsigned long cur_freq;
|
|
struct device *dev = &pfdev->pdev->dev;
|
|
struct devfreq *devfreq;
|
|
+ struct opp_table *opp_table;
|
|
struct thermal_cooling_device *cooling;
|
|
struct panfrost_devfreq *pfdevfreq = &pfdev->pfdevfreq;
|
|
|
|
+ opp_table = dev_pm_opp_set_regulators(dev, pfdev->comp->supply_names,
|
|
+ pfdev->comp->num_supplies);
|
|
+ if (IS_ERR(opp_table)) {
|
|
+ ret = PTR_ERR(opp_table);
|
|
+ /* Continue if the optional regulator is missing */
|
|
+ if (ret != -ENODEV) {
|
|
+ DRM_DEV_ERROR(dev, "Couldn't set OPP regulators\n");
|
|
+ goto err_fini;
|
|
+ }
|
|
+ } else {
|
|
+ pfdevfreq->regulators_opp_table = opp_table;
|
|
+ }
|
|
+
|
|
ret = dev_pm_opp_of_add_table(dev);
|
|
- if (ret == -ENODEV) /* Optional, continue without devfreq */
|
|
- return 0;
|
|
- else if (ret)
|
|
- return ret;
|
|
+ if (ret) {
|
|
+ /* Optional, continue without devfreq */
|
|
+ if (ret == -ENODEV)
|
|
+ ret = 0;
|
|
+ goto err_fini;
|
|
+ }
|
|
pfdevfreq->opp_of_table_added = true;
|
|
|
|
spin_lock_init(&pfdevfreq->lock);
|
|
@@ -153,6 +169,11 @@ void panfrost_devfreq_fini(struct panfrost_device *pfdev)
|
|
dev_pm_opp_of_remove_table(&pfdev->pdev->dev);
|
|
pfdevfreq->opp_of_table_added = false;
|
|
}
|
|
+
|
|
+ if (pfdevfreq->regulators_opp_table) {
|
|
+ dev_pm_opp_put_regulators(pfdevfreq->regulators_opp_table);
|
|
+ pfdevfreq->regulators_opp_table = NULL;
|
|
+ }
|
|
}
|
|
|
|
void panfrost_devfreq_resume(struct panfrost_device *pfdev)
|
|
diff --git a/drivers/gpu/drm/panfrost/panfrost_devfreq.h b/drivers/gpu/drm/panfrost/panfrost_devfreq.h
|
|
index 210269944687..db6ea48e21f9 100644
|
|
--- a/drivers/gpu/drm/panfrost/panfrost_devfreq.h
|
|
+++ b/drivers/gpu/drm/panfrost/panfrost_devfreq.h
|
|
@@ -8,12 +8,14 @@
|
|
#include <linux/ktime.h>
|
|
|
|
struct devfreq;
|
|
+struct opp_table;
|
|
struct thermal_cooling_device;
|
|
|
|
struct panfrost_device;
|
|
|
|
struct panfrost_devfreq {
|
|
struct devfreq *devfreq;
|
|
+ struct opp_table *regulators_opp_table;
|
|
struct thermal_cooling_device *cooling;
|
|
bool opp_of_table_added;
|
|
|
|
diff --git a/drivers/gpu/drm/panfrost/panfrost_device.c b/drivers/gpu/drm/panfrost/panfrost_device.c
|
|
index f1474b961def..e6896733838a 100644
|
|
--- a/drivers/gpu/drm/panfrost/panfrost_device.c
|
|
+++ b/drivers/gpu/drm/panfrost/panfrost_device.c
|
|
@@ -225,9 +225,12 @@ int panfrost_device_init(struct panfrost_device *pfdev)
|
|
goto out_clk;
|
|
}
|
|
|
|
- err = panfrost_regulator_init(pfdev);
|
|
- if (err)
|
|
- goto out_devfreq;
|
|
+ /* OPP will handle regulators */
|
|
+ if (!pfdev->pfdevfreq.opp_of_table_added) {
|
|
+ err = panfrost_regulator_init(pfdev);
|
|
+ if (err)
|
|
+ goto out_devfreq;
|
|
+ }
|
|
|
|
err = panfrost_reset_init(pfdev);
|
|
if (err) {
|
|
|
|
From d54c64a7033c7d9a55ec3a455a93ccfa09ba9549 Mon Sep 17 00:00:00 2001
|
|
From: Antonio Borneo <antonio.borneo@st.com>
|
|
Date: Wed, 8 Jul 2020 16:08:36 +0200
|
|
Subject: [PATCH] drm/bridge/synopsys: dsi: allow LP commands in video mode
|
|
|
|
Current code only sends LP commands in command mode.
|
|
|
|
Allows sending LP commands also in video mode by setting the
|
|
proper flag in DSI_VID_MODE_CFG.
|
|
|
|
Signed-off-by: Antonio Borneo <antonio.borneo@st.com>
|
|
Tested-by: Philippe Cornu <philippe.cornu@st.com>
|
|
Reviewed-by: Philippe Cornu <philippe.cornu@st.com>
|
|
Acked-by: Neil Armstrong <narmstrong@baylibre.com>
|
|
Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
|
|
Link: https://patchwork.freedesktop.org/patch/msgid/20200708140836.32418-1-yannick.fertre@st.com
|
|
(cherry picked from commit 6188b06e0357b3bc3b91d0b67783681d34ff2b64)
|
|
---
|
|
drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c | 8 ++++++++
|
|
1 file changed, 8 insertions(+)
|
|
|
|
diff --git a/drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c b/drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c
|
|
index d580b2aa4ce9..d41ce1de1067 100644
|
|
--- a/drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c
|
|
+++ b/drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c
|
|
@@ -89,6 +89,7 @@
|
|
#define VID_MODE_TYPE_NON_BURST_SYNC_EVENTS 0x1
|
|
#define VID_MODE_TYPE_BURST 0x2
|
|
#define VID_MODE_TYPE_MASK 0x3
|
|
+#define ENABLE_LOW_POWER_CMD BIT(15)
|
|
#define VID_MODE_VPG_ENABLE BIT(16)
|
|
#define VID_MODE_VPG_HORIZONTAL BIT(24)
|
|
|
|
@@ -367,6 +368,13 @@ static void dw_mipi_message_config(struct dw_mipi_dsi *dsi,
|
|
|
|
dsi_write(dsi, DSI_LPCLK_CTRL, lpm ? 0 : PHY_TXREQUESTCLKHS);
|
|
dsi_write(dsi, DSI_CMD_MODE_CFG, val);
|
|
+
|
|
+ val = dsi_read(dsi, DSI_VID_MODE_CFG);
|
|
+ if (lpm)
|
|
+ val |= ENABLE_LOW_POWER_CMD;
|
|
+ else
|
|
+ val &= ~ENABLE_LOW_POWER_CMD;
|
|
+ dsi_write(dsi, DSI_VID_MODE_CFG, val);
|
|
}
|
|
|
|
static int dw_mipi_dsi_gen_pkt_hdr_write(struct dw_mipi_dsi *dsi, u32 hdr_val)
|
|
|
|
From 071e4591b5ddac631fe65bd2e527d7ca28105c5b Mon Sep 17 00:00:00 2001
|
|
From: Antonio Borneo <antonio.borneo@st.com>
|
|
Date: Wed, 1 Jul 2020 16:31:31 +0200
|
|
Subject: [PATCH] drm/bridge/synopsys: dsi: allow sending longer LP commands
|
|
|
|
Current code does not properly computes the max length of LP
|
|
commands that can be send during H or V sync, and rely on static
|
|
values.
|
|
Limiting the max LP length to 4 byte during the V-sync is overly
|
|
conservative.
|
|
|
|
Relax the limit and allows longer LP commands (16 bytes) to be
|
|
sent during V-sync.
|
|
|
|
Signed-off-by: Antonio Borneo <antonio.borneo@st.com>
|
|
Tested-by: Philippe Cornu <philippe.cornu@st.com>
|
|
Reviewed-by: Philippe Cornu <philippe.cornu@st.com>
|
|
Acked-by: Neil Armstrong <narmstrong@baylibre.com>
|
|
Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
|
|
Link: https://patchwork.freedesktop.org/patch/msgid/20200701143131.841-1-yannick.fertre@st.com
|
|
(cherry picked from commit 9e025e80660fe35432c81e67d401109d8e7b0ff4)
|
|
---
|
|
drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c | 17 +++++++++--------
|
|
1 file changed, 9 insertions(+), 8 deletions(-)
|
|
|
|
diff --git a/drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c b/drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c
|
|
index d41ce1de1067..e9a0f42ff99f 100644
|
|
--- a/drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c
|
|
+++ b/drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c
|
|
@@ -361,6 +361,15 @@ static void dw_mipi_message_config(struct dw_mipi_dsi *dsi,
|
|
bool lpm = msg->flags & MIPI_DSI_MSG_USE_LPM;
|
|
u32 val = 0;
|
|
|
|
+ /*
|
|
+ * TODO dw drv improvements
|
|
+ * largest packet sizes during hfp or during vsa/vpb/vfp
|
|
+ * should be computed according to byte lane, lane number and only
|
|
+ * if sending lp cmds in high speed is enable (PHY_TXREQUESTCLKHS)
|
|
+ */
|
|
+ dsi_write(dsi, DSI_DPI_LP_CMD_TIM, OUTVACT_LPCMD_TIME(16)
|
|
+ | INVACT_LPCMD_TIME(4));
|
|
+
|
|
if (msg->flags & MIPI_DSI_MSG_REQ_ACK)
|
|
val |= ACK_RQST_EN;
|
|
if (lpm)
|
|
@@ -619,14 +628,6 @@ static void dw_mipi_dsi_dpi_config(struct dw_mipi_dsi *dsi,
|
|
dsi_write(dsi, DSI_DPI_VCID, DPI_VCID(dsi->channel));
|
|
dsi_write(dsi, DSI_DPI_COLOR_CODING, color);
|
|
dsi_write(dsi, DSI_DPI_CFG_POL, val);
|
|
- /*
|
|
- * TODO dw drv improvements
|
|
- * largest packet sizes during hfp or during vsa/vpb/vfp
|
|
- * should be computed according to byte lane, lane number and only
|
|
- * if sending lp cmds in high speed is enable (PHY_TXREQUESTCLKHS)
|
|
- */
|
|
- dsi_write(dsi, DSI_DPI_LP_CMD_TIM, OUTVACT_LPCMD_TIME(4)
|
|
- | INVACT_LPCMD_TIME(4));
|
|
}
|
|
|
|
static void dw_mipi_dsi_packet_handler_config(struct dw_mipi_dsi *dsi)
|
|
|
|
From b3ba2bd08c57aedc749e4f3e646b4b773147866b Mon Sep 17 00:00:00 2001
|
|
From: Angelo Ribeiro <Angelo.Ribeiro@synopsys.com>
|
|
Date: Mon, 6 Apr 2020 15:49:03 +0200
|
|
Subject: [PATCH] drm/bridge: dw-mipi-dsi.c: Add VPG runtime config through
|
|
debugfs
|
|
|
|
Add support for the video pattern generator (VPG) BER pattern mode and
|
|
configuration in runtime.
|
|
|
|
This enables using the debugfs interface to manipulate the VPG after
|
|
the pipeline is set.
|
|
Also, enables the usage of the VPG BER pattern.
|
|
|
|
Changes in v2:
|
|
- Added VID_MODE_VPG_MODE
|
|
- Solved incompatible return type on __get and __set
|
|
|
|
Reported-by: kbuild test robot <lkp@intel.com>
|
|
Reported-by: Adrian Pop <pop.adrian61@gmail.com>
|
|
Signed-off-by: Angelo Ribeiro <angelo.ribeiro@synopsys.com>
|
|
Tested-by: Yannick Fertre <yannick.fertre@st.com>
|
|
Tested-by: Adrian Pop <pop.adrian61@gmail.com>
|
|
Acked-by: Neil Armstrong <narmstrong@baylibre.com>
|
|
Cc: Gustavo Pimentel <gustavo.pimentel@synopsys.com>
|
|
Cc: Joao Pinto <jpinto@synopsys.com>
|
|
Cc: Jose Abreu <jose.abreu@synopsys.com>
|
|
Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
|
|
Link: https://patchwork.freedesktop.org/patch/msgid/a809feb7d7153a92e323416f744f1565e995da01.1586180592.git.angelo.ribeiro@synopsys.com
|
|
(cherry picked from commit e2435d69204c1f041e5742cac9af301021afa46f)
|
|
---
|
|
drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c | 98 ++++++++++++++++++++++++---
|
|
1 file changed, 90 insertions(+), 8 deletions(-)
|
|
|
|
diff --git a/drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c b/drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c
|
|
index 8510a84c4c63..0b3825a4fbdb 100644
|
|
--- a/drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c
|
|
+++ b/drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c
|
|
@@ -91,6 +91,7 @@
|
|
#define VID_MODE_TYPE_MASK 0x3
|
|
#define ENABLE_LOW_POWER_CMD BIT(15)
|
|
#define VID_MODE_VPG_ENABLE BIT(16)
|
|
+#define VID_MODE_VPG_MODE BIT(20)
|
|
#define VID_MODE_VPG_HORIZONTAL BIT(24)
|
|
|
|
#define DSI_VID_PKT_SIZE 0x3c
|
|
@@ -221,6 +222,21 @@
|
|
#define PHY_STATUS_TIMEOUT_US 10000
|
|
#define CMD_PKT_STATUS_TIMEOUT_US 20000
|
|
|
|
+#ifdef CONFIG_DEBUG_FS
|
|
+#define VPG_DEFS(name, dsi) \
|
|
+ ((void __force *)&((*dsi).vpg_defs.name))
|
|
+
|
|
+#define REGISTER(name, mask, dsi) \
|
|
+ { #name, VPG_DEFS(name, dsi), mask, dsi }
|
|
+
|
|
+struct debugfs_entries {
|
|
+ const char *name;
|
|
+ bool *reg;
|
|
+ u32 mask;
|
|
+ struct dw_mipi_dsi *dsi;
|
|
+};
|
|
+#endif /* CONFIG_DEBUG_FS */
|
|
+
|
|
struct dw_mipi_dsi {
|
|
struct drm_bridge bridge;
|
|
struct mipi_dsi_host dsi_host;
|
|
@@ -238,9 +254,12 @@ struct dw_mipi_dsi {
|
|
|
|
#ifdef CONFIG_DEBUG_FS
|
|
struct dentry *debugfs;
|
|
-
|
|
- bool vpg;
|
|
- bool vpg_horizontal;
|
|
+ struct debugfs_entries *debugfs_vpg;
|
|
+ struct {
|
|
+ bool vpg;
|
|
+ bool vpg_horizontal;
|
|
+ bool vpg_ber_pattern;
|
|
+ } vpg_defs;
|
|
#endif /* CONFIG_DEBUG_FS */
|
|
|
|
struct dw_mipi_dsi *master; /* dual-dsi master ptr */
|
|
@@ -545,9 +564,11 @@ static void dw_mipi_dsi_video_mode_config(struct dw_mipi_dsi *dsi)
|
|
val |= VID_MODE_TYPE_NON_BURST_SYNC_EVENTS;
|
|
|
|
#ifdef CONFIG_DEBUG_FS
|
|
- if (dsi->vpg) {
|
|
+ if (dsi->vpg_defs.vpg) {
|
|
val |= VID_MODE_VPG_ENABLE;
|
|
- val |= dsi->vpg_horizontal ? VID_MODE_VPG_HORIZONTAL : 0;
|
|
+ val |= dsi->vpg_defs.vpg_horizontal ?
|
|
+ VID_MODE_VPG_HORIZONTAL : 0;
|
|
+ val |= dsi->vpg_defs.vpg_ber_pattern ? VID_MODE_VPG_MODE : 0;
|
|
}
|
|
#endif /* CONFIG_DEBUG_FS */
|
|
|
|
@@ -978,6 +999,68 @@ static const struct drm_bridge_funcs dw_mipi_dsi_bridge_funcs = {
|
|
|
|
#ifdef CONFIG_DEBUG_FS
|
|
|
|
+int dw_mipi_dsi_debugfs_write(void *data, u64 val)
|
|
+{
|
|
+ struct debugfs_entries *vpg = data;
|
|
+ struct dw_mipi_dsi *dsi;
|
|
+ u32 mode_cfg;
|
|
+
|
|
+ if (!vpg)
|
|
+ return -ENODEV;
|
|
+
|
|
+ dsi = vpg->dsi;
|
|
+
|
|
+ *vpg->reg = (bool)val;
|
|
+
|
|
+ mode_cfg = dsi_read(dsi, DSI_VID_MODE_CFG);
|
|
+
|
|
+ if (*vpg->reg)
|
|
+ mode_cfg |= vpg->mask;
|
|
+ else
|
|
+ mode_cfg &= ~vpg->mask;
|
|
+
|
|
+ dsi_write(dsi, DSI_VID_MODE_CFG, mode_cfg);
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+int dw_mipi_dsi_debugfs_show(void *data, u64 *val)
|
|
+{
|
|
+ struct debugfs_entries *vpg = data;
|
|
+
|
|
+ if (!vpg)
|
|
+ return -ENODEV;
|
|
+
|
|
+ *val = *vpg->reg;
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+DEFINE_DEBUGFS_ATTRIBUTE(fops_x32, dw_mipi_dsi_debugfs_show,
|
|
+ dw_mipi_dsi_debugfs_write, "%llu\n");
|
|
+
|
|
+static void debugfs_create_files(void *data)
|
|
+{
|
|
+ struct dw_mipi_dsi *dsi = data;
|
|
+ struct debugfs_entries debugfs[] = {
|
|
+ REGISTER(vpg, VID_MODE_VPG_ENABLE, dsi),
|
|
+ REGISTER(vpg_horizontal, VID_MODE_VPG_HORIZONTAL, dsi),
|
|
+ REGISTER(vpg_ber_pattern, VID_MODE_VPG_MODE, dsi),
|
|
+ };
|
|
+ int i;
|
|
+
|
|
+ dsi->debugfs_vpg = kmalloc(sizeof(debugfs), GFP_KERNEL);
|
|
+ if (!dsi->debugfs_vpg)
|
|
+ return;
|
|
+
|
|
+ memcpy(dsi->debugfs_vpg, debugfs, sizeof(debugfs));
|
|
+
|
|
+ for (i = 0; i < ARRAY_SIZE(debugfs); i++)
|
|
+ debugfs_create_file(dsi->debugfs_vpg[i].name, 0644,
|
|
+ dsi->debugfs, &dsi->debugfs_vpg[i],
|
|
+ &fops_x32);
|
|
+}
|
|
+
|
|
static void dw_mipi_dsi_debugfs_init(struct dw_mipi_dsi *dsi)
|
|
{
|
|
dsi->debugfs = debugfs_create_dir(dev_name(dsi->dev), NULL);
|
|
@@ -986,14 +1069,13 @@ static void dw_mipi_dsi_debugfs_init(struct dw_mipi_dsi *dsi)
|
|
return;
|
|
}
|
|
|
|
- debugfs_create_bool("vpg", 0660, dsi->debugfs, &dsi->vpg);
|
|
- debugfs_create_bool("vpg_horizontal", 0660, dsi->debugfs,
|
|
- &dsi->vpg_horizontal);
|
|
+ debugfs_create_files(dsi);
|
|
}
|
|
|
|
static void dw_mipi_dsi_debugfs_remove(struct dw_mipi_dsi *dsi)
|
|
{
|
|
debugfs_remove_recursive(dsi->debugfs);
|
|
+ kfree(dsi->debugfs_vpg);
|
|
}
|
|
|
|
#else
|
|
|
|
From b48c8b2c43459f3c3bf28ffdec42553844412a83 Mon Sep 17 00:00:00 2001
|
|
From: Neil Armstrong <narmstrong@baylibre.com>
|
|
Date: Mon, 7 Sep 2020 12:27:11 +0200
|
|
Subject: [PATCH] drm/bridge: dw-mipi-dsi: fix dw_mipi_dsi_debugfs_show/write
|
|
warnings
|
|
|
|
This fixes the following warnings while building in W=1 :
|
|
dw-mipi-dsi.c:1002:5: warning: no previous prototype for 'dw_mipi_dsi_debugfs_write' [-Wmissing-prototypes]
|
|
dw-mipi-dsi.c:1027:5: warning: no previous prototype for 'dw_mipi_dsi_debugfs_show' [-Wmissing-prototypes]
|
|
|
|
Fixes: e2435d69204c ("drm/bridge: dw-mipi-dsi.c: Add VPG runtime config through debugfs")
|
|
Reported-by: kernel test robot <lkp@intel.com>
|
|
Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
|
|
Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch>
|
|
Cc: Angelo Ribeiro <angelo.ribeiro@synopsys.com>
|
|
Cc: Maxime Ripard <maxime@cerno.tech>
|
|
Cc: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
|
|
Cc: Thomas Zimmermann <tzimmermann@suse.de>
|
|
Link: https://patchwork.freedesktop.org/patch/msgid/20200907102711.23748-1-narmstrong@baylibre.com
|
|
(cherry picked from commit 25c4bcf9858e3e8752985fa0cda64a212ea328b7)
|
|
---
|
|
drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c | 4 ++--
|
|
1 file changed, 2 insertions(+), 2 deletions(-)
|
|
|
|
diff --git a/drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c b/drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c
|
|
index 0b3825a4fbdb..52f5c5a2ed64 100644
|
|
--- a/drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c
|
|
+++ b/drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c
|
|
@@ -999,7 +999,7 @@ static const struct drm_bridge_funcs dw_mipi_dsi_bridge_funcs = {
|
|
|
|
#ifdef CONFIG_DEBUG_FS
|
|
|
|
-int dw_mipi_dsi_debugfs_write(void *data, u64 val)
|
|
+static int dw_mipi_dsi_debugfs_write(void *data, u64 val)
|
|
{
|
|
struct debugfs_entries *vpg = data;
|
|
struct dw_mipi_dsi *dsi;
|
|
@@ -1024,7 +1024,7 @@ int dw_mipi_dsi_debugfs_write(void *data, u64 val)
|
|
return 0;
|
|
}
|
|
|
|
-int dw_mipi_dsi_debugfs_show(void *data, u64 *val)
|
|
+static int dw_mipi_dsi_debugfs_show(void *data, u64 *val)
|
|
{
|
|
struct debugfs_entries *vpg = data;
|
|
|
|
|
|
From 0765583a5df3824d6347f89088656d52f70d9de0 Mon Sep 17 00:00:00 2001
|
|
From: Gerd Hoffmann <kraxel@redhat.com>
|
|
Date: Mon, 7 Sep 2020 13:24:25 +0200
|
|
Subject: [PATCH] drm: allow limiting the scatter list size.
|
|
|
|
Add drm_device argument to drm_prime_pages_to_sg(), so we can
|
|
call dma_max_mapping_size() to figure the segment size limit
|
|
and call into __sg_alloc_table_from_pages() with the correct
|
|
limit.
|
|
|
|
This fixes virtio-gpu with sev. Possibly it'll fix other bugs
|
|
too given that drm seems to totaly ignore segment size limits
|
|
so far ...
|
|
|
|
v2: place max_segment in drm driver not gem object.
|
|
v3: move max_segment next to the other gem fields.
|
|
v4: just use dma_max_mapping_size().
|
|
|
|
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
|
|
Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch>
|
|
Link: http://patchwork.freedesktop.org/patch/msgid/20200907112425.15610-2-kraxel@redhat.com
|
|
(cherry picked from commit 707d561f77b5e2a6f90c9786bee44ee7a8dedc7e)
|
|
---
|
|
drivers/gpu/drm/amd/amdgpu/amdgpu_dma_buf.c | 3 ++-
|
|
drivers/gpu/drm/drm_gem_shmem_helper.c | 2 +-
|
|
drivers/gpu/drm/drm_prime.c | 13 ++++++++++---
|
|
drivers/gpu/drm/etnaviv/etnaviv_gem.c | 3 ++-
|
|
drivers/gpu/drm/etnaviv/etnaviv_gem_prime.c | 2 +-
|
|
drivers/gpu/drm/msm/msm_gem.c | 2 +-
|
|
drivers/gpu/drm/msm/msm_gem_prime.c | 2 +-
|
|
drivers/gpu/drm/nouveau/nouveau_prime.c | 2 +-
|
|
drivers/gpu/drm/radeon/radeon_prime.c | 2 +-
|
|
drivers/gpu/drm/rockchip/rockchip_drm_gem.c | 5 +++--
|
|
drivers/gpu/drm/tegra/gem.c | 2 +-
|
|
drivers/gpu/drm/vgem/vgem_drv.c | 2 +-
|
|
drivers/gpu/drm/xen/xen_drm_front_gem.c | 3 ++-
|
|
include/drm/drm_prime.h | 3 ++-
|
|
14 files changed, 29 insertions(+), 17 deletions(-)
|
|
|
|
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_dma_buf.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_dma_buf.c
|
|
index 519ce4427fce..d7050ab95946 100644
|
|
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_dma_buf.c
|
|
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_dma_buf.c
|
|
@@ -302,7 +302,8 @@ static struct sg_table *amdgpu_dma_buf_map(struct dma_buf_attachment *attach,
|
|
|
|
switch (bo->tbo.mem.mem_type) {
|
|
case TTM_PL_TT:
|
|
- sgt = drm_prime_pages_to_sg(bo->tbo.ttm->pages,
|
|
+ sgt = drm_prime_pages_to_sg(obj->dev,
|
|
+ bo->tbo.ttm->pages,
|
|
bo->tbo.num_pages);
|
|
if (IS_ERR(sgt))
|
|
return sgt;
|
|
diff --git a/drivers/gpu/drm/drm_gem_shmem_helper.c b/drivers/gpu/drm/drm_gem_shmem_helper.c
|
|
index 4b7cfbac4daa..0a952f27c184 100644
|
|
--- a/drivers/gpu/drm/drm_gem_shmem_helper.c
|
|
+++ b/drivers/gpu/drm/drm_gem_shmem_helper.c
|
|
@@ -656,7 +656,7 @@ struct sg_table *drm_gem_shmem_get_sg_table(struct drm_gem_object *obj)
|
|
|
|
WARN_ON(shmem->base.import_attach);
|
|
|
|
- return drm_prime_pages_to_sg(shmem->pages, obj->size >> PAGE_SHIFT);
|
|
+ return drm_prime_pages_to_sg(obj->dev, shmem->pages, obj->size >> PAGE_SHIFT);
|
|
}
|
|
EXPORT_SYMBOL_GPL(drm_gem_shmem_get_sg_table);
|
|
|
|
diff --git a/drivers/gpu/drm/drm_prime.c b/drivers/gpu/drm/drm_prime.c
|
|
index 1693aa7c14b5..8a6a3c99b7d8 100644
|
|
--- a/drivers/gpu/drm/drm_prime.c
|
|
+++ b/drivers/gpu/drm/drm_prime.c
|
|
@@ -802,9 +802,11 @@ static const struct dma_buf_ops drm_gem_prime_dmabuf_ops = {
|
|
*
|
|
* This is useful for implementing &drm_gem_object_funcs.get_sg_table.
|
|
*/
|
|
-struct sg_table *drm_prime_pages_to_sg(struct page **pages, unsigned int nr_pages)
|
|
+struct sg_table *drm_prime_pages_to_sg(struct drm_device *dev,
|
|
+ struct page **pages, unsigned int nr_pages)
|
|
{
|
|
struct sg_table *sg = NULL;
|
|
+ size_t max_segment = 0;
|
|
int ret;
|
|
|
|
sg = kmalloc(sizeof(struct sg_table), GFP_KERNEL);
|
|
@@ -813,8 +815,13 @@ struct sg_table *drm_prime_pages_to_sg(struct page **pages, unsigned int nr_page
|
|
goto out;
|
|
}
|
|
|
|
- ret = sg_alloc_table_from_pages(sg, pages, nr_pages, 0,
|
|
- nr_pages << PAGE_SHIFT, GFP_KERNEL);
|
|
+ if (dev)
|
|
+ max_segment = dma_max_mapping_size(dev->dev);
|
|
+ if (max_segment == 0 || max_segment > SCATTERLIST_MAX_SEGMENT)
|
|
+ max_segment = SCATTERLIST_MAX_SEGMENT;
|
|
+ ret = __sg_alloc_table_from_pages(sg, pages, nr_pages, 0,
|
|
+ nr_pages << PAGE_SHIFT,
|
|
+ max_segment, GFP_KERNEL);
|
|
if (ret)
|
|
goto out;
|
|
|
|
diff --git a/drivers/gpu/drm/etnaviv/etnaviv_gem.c b/drivers/gpu/drm/etnaviv/etnaviv_gem.c
|
|
index f06e19e7be04..ea19f1d27275 100644
|
|
--- a/drivers/gpu/drm/etnaviv/etnaviv_gem.c
|
|
+++ b/drivers/gpu/drm/etnaviv/etnaviv_gem.c
|
|
@@ -103,7 +103,8 @@ struct page **etnaviv_gem_get_pages(struct etnaviv_gem_object *etnaviv_obj)
|
|
int npages = etnaviv_obj->base.size >> PAGE_SHIFT;
|
|
struct sg_table *sgt;
|
|
|
|
- sgt = drm_prime_pages_to_sg(etnaviv_obj->pages, npages);
|
|
+ sgt = drm_prime_pages_to_sg(etnaviv_obj->base.dev,
|
|
+ etnaviv_obj->pages, npages);
|
|
if (IS_ERR(sgt)) {
|
|
dev_err(dev->dev, "failed to allocate sgt: %ld\n",
|
|
PTR_ERR(sgt));
|
|
diff --git a/drivers/gpu/drm/etnaviv/etnaviv_gem_prime.c b/drivers/gpu/drm/etnaviv/etnaviv_gem_prime.c
|
|
index 6d9e5c3c4dd5..4aa3426a9ba4 100644
|
|
--- a/drivers/gpu/drm/etnaviv/etnaviv_gem_prime.c
|
|
+++ b/drivers/gpu/drm/etnaviv/etnaviv_gem_prime.c
|
|
@@ -19,7 +19,7 @@ struct sg_table *etnaviv_gem_prime_get_sg_table(struct drm_gem_object *obj)
|
|
if (WARN_ON(!etnaviv_obj->pages)) /* should have already pinned! */
|
|
return ERR_PTR(-EINVAL);
|
|
|
|
- return drm_prime_pages_to_sg(etnaviv_obj->pages, npages);
|
|
+ return drm_prime_pages_to_sg(obj->dev, etnaviv_obj->pages, npages);
|
|
}
|
|
|
|
void *etnaviv_gem_prime_vmap(struct drm_gem_object *obj)
|
|
diff --git a/drivers/gpu/drm/msm/msm_gem.c b/drivers/gpu/drm/msm/msm_gem.c
|
|
index b2f49152b4d4..b4553caaa196 100644
|
|
--- a/drivers/gpu/drm/msm/msm_gem.c
|
|
+++ b/drivers/gpu/drm/msm/msm_gem.c
|
|
@@ -126,7 +126,7 @@ static struct page **get_pages(struct drm_gem_object *obj)
|
|
|
|
msm_obj->pages = p;
|
|
|
|
- msm_obj->sgt = drm_prime_pages_to_sg(p, npages);
|
|
+ msm_obj->sgt = drm_prime_pages_to_sg(obj->dev, p, npages);
|
|
if (IS_ERR(msm_obj->sgt)) {
|
|
void *ptr = ERR_CAST(msm_obj->sgt);
|
|
|
|
diff --git a/drivers/gpu/drm/msm/msm_gem_prime.c b/drivers/gpu/drm/msm/msm_gem_prime.c
|
|
index d7c8948427fe..515ef80816a0 100644
|
|
--- a/drivers/gpu/drm/msm/msm_gem_prime.c
|
|
+++ b/drivers/gpu/drm/msm/msm_gem_prime.c
|
|
@@ -19,7 +19,7 @@ struct sg_table *msm_gem_prime_get_sg_table(struct drm_gem_object *obj)
|
|
if (WARN_ON(!msm_obj->pages)) /* should have already pinned! */
|
|
return NULL;
|
|
|
|
- return drm_prime_pages_to_sg(msm_obj->pages, npages);
|
|
+ return drm_prime_pages_to_sg(obj->dev, msm_obj->pages, npages);
|
|
}
|
|
|
|
void *msm_gem_prime_vmap(struct drm_gem_object *obj)
|
|
diff --git a/drivers/gpu/drm/nouveau/nouveau_prime.c b/drivers/gpu/drm/nouveau/nouveau_prime.c
|
|
index bae6a3eccee0..7766b810653f 100644
|
|
--- a/drivers/gpu/drm/nouveau/nouveau_prime.c
|
|
+++ b/drivers/gpu/drm/nouveau/nouveau_prime.c
|
|
@@ -32,7 +32,7 @@ struct sg_table *nouveau_gem_prime_get_sg_table(struct drm_gem_object *obj)
|
|
struct nouveau_bo *nvbo = nouveau_gem_object(obj);
|
|
int npages = nvbo->bo.num_pages;
|
|
|
|
- return drm_prime_pages_to_sg(nvbo->bo.ttm->pages, npages);
|
|
+ return drm_prime_pages_to_sg(obj->dev, nvbo->bo.ttm->pages, npages);
|
|
}
|
|
|
|
void *nouveau_gem_prime_vmap(struct drm_gem_object *obj)
|
|
diff --git a/drivers/gpu/drm/radeon/radeon_prime.c b/drivers/gpu/drm/radeon/radeon_prime.c
|
|
index b906e8fbd5f3..ea4c900e7c41 100644
|
|
--- a/drivers/gpu/drm/radeon/radeon_prime.c
|
|
+++ b/drivers/gpu/drm/radeon/radeon_prime.c
|
|
@@ -36,7 +36,7 @@ struct sg_table *radeon_gem_prime_get_sg_table(struct drm_gem_object *obj)
|
|
struct radeon_bo *bo = gem_to_radeon_bo(obj);
|
|
int npages = bo->tbo.num_pages;
|
|
|
|
- return drm_prime_pages_to_sg(bo->tbo.ttm->pages, npages);
|
|
+ return drm_prime_pages_to_sg(obj->dev, bo->tbo.ttm->pages, npages);
|
|
}
|
|
|
|
void *radeon_gem_prime_vmap(struct drm_gem_object *obj)
|
|
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_gem.c b/drivers/gpu/drm/rockchip/rockchip_drm_gem.c
|
|
index b9275ba7c5a5..0055d86576f7 100644
|
|
--- a/drivers/gpu/drm/rockchip/rockchip_drm_gem.c
|
|
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_gem.c
|
|
@@ -85,7 +85,8 @@ static int rockchip_gem_get_pages(struct rockchip_gem_object *rk_obj)
|
|
|
|
rk_obj->num_pages = rk_obj->base.size >> PAGE_SHIFT;
|
|
|
|
- rk_obj->sgt = drm_prime_pages_to_sg(rk_obj->pages, rk_obj->num_pages);
|
|
+ rk_obj->sgt = drm_prime_pages_to_sg(rk_obj->base.dev,
|
|
+ rk_obj->pages, rk_obj->num_pages);
|
|
if (IS_ERR(rk_obj->sgt)) {
|
|
ret = PTR_ERR(rk_obj->sgt);
|
|
goto err_put_pages;
|
|
@@ -442,7 +443,7 @@ struct sg_table *rockchip_gem_prime_get_sg_table(struct drm_gem_object *obj)
|
|
int ret;
|
|
|
|
if (rk_obj->pages)
|
|
- return drm_prime_pages_to_sg(rk_obj->pages, rk_obj->num_pages);
|
|
+ return drm_prime_pages_to_sg(obj->dev, rk_obj->pages, rk_obj->num_pages);
|
|
|
|
sgt = kzalloc(sizeof(*sgt), GFP_KERNEL);
|
|
if (!sgt)
|
|
diff --git a/drivers/gpu/drm/tegra/gem.c b/drivers/gpu/drm/tegra/gem.c
|
|
index 723df142a981..47e2935b8c68 100644
|
|
--- a/drivers/gpu/drm/tegra/gem.c
|
|
+++ b/drivers/gpu/drm/tegra/gem.c
|
|
@@ -284,7 +284,7 @@ static int tegra_bo_get_pages(struct drm_device *drm, struct tegra_bo *bo)
|
|
|
|
bo->num_pages = bo->gem.size >> PAGE_SHIFT;
|
|
|
|
- bo->sgt = drm_prime_pages_to_sg(bo->pages, bo->num_pages);
|
|
+ bo->sgt = drm_prime_pages_to_sg(bo->gem.dev, bo->pages, bo->num_pages);
|
|
if (IS_ERR(bo->sgt)) {
|
|
err = PTR_ERR(bo->sgt);
|
|
goto put_pages;
|
|
diff --git a/drivers/gpu/drm/vgem/vgem_drv.c b/drivers/gpu/drm/vgem/vgem_drv.c
|
|
index a775feda1cc7..4f0fd71d2da1 100644
|
|
--- a/drivers/gpu/drm/vgem/vgem_drv.c
|
|
+++ b/drivers/gpu/drm/vgem/vgem_drv.c
|
|
@@ -321,7 +321,7 @@ static struct sg_table *vgem_prime_get_sg_table(struct drm_gem_object *obj)
|
|
{
|
|
struct drm_vgem_gem_object *bo = to_vgem_bo(obj);
|
|
|
|
- return drm_prime_pages_to_sg(bo->pages, bo->base.size >> PAGE_SHIFT);
|
|
+ return drm_prime_pages_to_sg(obj->dev, bo->pages, bo->base.size >> PAGE_SHIFT);
|
|
}
|
|
|
|
static struct drm_gem_object* vgem_prime_import(struct drm_device *dev,
|
|
diff --git a/drivers/gpu/drm/xen/xen_drm_front_gem.c b/drivers/gpu/drm/xen/xen_drm_front_gem.c
|
|
index 534daf37c97e..a8aefaa38bd3 100644
|
|
--- a/drivers/gpu/drm/xen/xen_drm_front_gem.c
|
|
+++ b/drivers/gpu/drm/xen/xen_drm_front_gem.c
|
|
@@ -180,7 +180,8 @@ struct sg_table *xen_drm_front_gem_get_sg_table(struct drm_gem_object *gem_obj)
|
|
if (!xen_obj->pages)
|
|
return ERR_PTR(-ENOMEM);
|
|
|
|
- return drm_prime_pages_to_sg(xen_obj->pages, xen_obj->num_pages);
|
|
+ return drm_prime_pages_to_sg(gem_obj->dev,
|
|
+ xen_obj->pages, xen_obj->num_pages);
|
|
}
|
|
|
|
struct drm_gem_object *
|
|
diff --git a/include/drm/drm_prime.h b/include/drm/drm_prime.h
|
|
index 9af7422b44cf..bf141e74a1c2 100644
|
|
--- a/include/drm/drm_prime.h
|
|
+++ b/include/drm/drm_prime.h
|
|
@@ -88,7 +88,8 @@ void drm_gem_dmabuf_vunmap(struct dma_buf *dma_buf, void *vaddr);
|
|
int drm_gem_prime_mmap(struct drm_gem_object *obj, struct vm_area_struct *vma);
|
|
int drm_gem_dmabuf_mmap(struct dma_buf *dma_buf, struct vm_area_struct *vma);
|
|
|
|
-struct sg_table *drm_prime_pages_to_sg(struct page **pages, unsigned int nr_pages);
|
|
+struct sg_table *drm_prime_pages_to_sg(struct drm_device *dev,
|
|
+ struct page **pages, unsigned int nr_pages);
|
|
struct dma_buf *drm_gem_prime_export(struct drm_gem_object *obj,
|
|
int flags);
|
|
|
|
|
|
From 0839a46485ed6cca60e13a706b8501267bd23bfa Mon Sep 17 00:00:00 2001
|
|
From: Marek Szyprowski <m.szyprowski@samsung.com>
|
|
Date: Fri, 8 May 2020 16:04:44 +0200
|
|
Subject: [PATCH] drm: prime: add common helper to check scatterlist contiguity
|
|
|
|
It is a common operation done by DRM drivers to check the contiguity
|
|
of the DMA-mapped buffer described by a scatterlist in the
|
|
sg_table object. Let's add a common helper for this operation.
|
|
|
|
Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com>
|
|
Reviewed-by: Andrzej Hajda <a.hajda@samsung.com>
|
|
Reviewed-by: Robin Murphy <robin.murphy@arm.com>
|
|
(cherry picked from commit d46e7ae24b81533d21edfa90914d27efa0c5f85d)
|
|
---
|
|
drivers/gpu/drm/drm_gem_cma_helper.c | 23 +++--------------------
|
|
drivers/gpu/drm/drm_prime.c | 31 +++++++++++++++++++++++++++++++
|
|
include/drm/drm_prime.h | 2 ++
|
|
3 files changed, 36 insertions(+), 20 deletions(-)
|
|
|
|
diff --git a/drivers/gpu/drm/drm_gem_cma_helper.c b/drivers/gpu/drm/drm_gem_cma_helper.c
|
|
index 822edeadbab3..59b9ca207b42 100644
|
|
--- a/drivers/gpu/drm/drm_gem_cma_helper.c
|
|
+++ b/drivers/gpu/drm/drm_gem_cma_helper.c
|
|
@@ -471,26 +471,9 @@ drm_gem_cma_prime_import_sg_table(struct drm_device *dev,
|
|
{
|
|
struct drm_gem_cma_object *cma_obj;
|
|
|
|
- if (sgt->nents != 1) {
|
|
- /* check if the entries in the sg_table are contiguous */
|
|
- dma_addr_t next_addr = sg_dma_address(sgt->sgl);
|
|
- struct scatterlist *s;
|
|
- unsigned int i;
|
|
-
|
|
- for_each_sg(sgt->sgl, s, sgt->nents, i) {
|
|
- /*
|
|
- * sg_dma_address(s) is only valid for entries
|
|
- * that have sg_dma_len(s) != 0
|
|
- */
|
|
- if (!sg_dma_len(s))
|
|
- continue;
|
|
-
|
|
- if (sg_dma_address(s) != next_addr)
|
|
- return ERR_PTR(-EINVAL);
|
|
-
|
|
- next_addr = sg_dma_address(s) + sg_dma_len(s);
|
|
- }
|
|
- }
|
|
+ /* check if the entries in the sg_table are contiguous */
|
|
+ if (drm_prime_get_contiguous_size(sgt) < attach->dmabuf->size)
|
|
+ return ERR_PTR(-EINVAL);
|
|
|
|
/* Create a CMA GEM buffer. */
|
|
cma_obj = __drm_gem_cma_create(dev, attach->dmabuf->size);
|
|
diff --git a/drivers/gpu/drm/drm_prime.c b/drivers/gpu/drm/drm_prime.c
|
|
index 8a6a3c99b7d8..5a134c63856f 100644
|
|
--- a/drivers/gpu/drm/drm_prime.c
|
|
+++ b/drivers/gpu/drm/drm_prime.c
|
|
@@ -832,6 +832,37 @@ struct sg_table *drm_prime_pages_to_sg(struct drm_device *dev,
|
|
}
|
|
EXPORT_SYMBOL(drm_prime_pages_to_sg);
|
|
|
|
+/**
|
|
+ * drm_prime_get_contiguous_size - returns the contiguous size of the buffer
|
|
+ * @sgt: sg_table describing the buffer to check
|
|
+ *
|
|
+ * This helper calculates the contiguous size in the DMA address space
|
|
+ * of the the buffer described by the provided sg_table.
|
|
+ *
|
|
+ * This is useful for implementing
|
|
+ * &drm_gem_object_funcs.gem_prime_import_sg_table.
|
|
+ */
|
|
+unsigned long drm_prime_get_contiguous_size(struct sg_table *sgt)
|
|
+{
|
|
+ dma_addr_t expected = sg_dma_address(sgt->sgl);
|
|
+ struct scatterlist *sg;
|
|
+ unsigned long size = 0;
|
|
+ int i;
|
|
+
|
|
+ for_each_sgtable_dma_sg(sgt, sg, i) {
|
|
+ unsigned int len = sg_dma_len(sg);
|
|
+
|
|
+ if (!len)
|
|
+ break;
|
|
+ if (sg_dma_address(sg) != expected)
|
|
+ break;
|
|
+ expected += len;
|
|
+ size += len;
|
|
+ }
|
|
+ return size;
|
|
+}
|
|
+EXPORT_SYMBOL(drm_prime_get_contiguous_size);
|
|
+
|
|
/**
|
|
* drm_gem_prime_export - helper library implementation of the export callback
|
|
* @obj: GEM object to export
|
|
diff --git a/include/drm/drm_prime.h b/include/drm/drm_prime.h
|
|
index bf141e74a1c2..0f69f9fbf12c 100644
|
|
--- a/include/drm/drm_prime.h
|
|
+++ b/include/drm/drm_prime.h
|
|
@@ -93,6 +93,8 @@ struct sg_table *drm_prime_pages_to_sg(struct drm_device *dev,
|
|
struct dma_buf *drm_gem_prime_export(struct drm_gem_object *obj,
|
|
int flags);
|
|
|
|
+unsigned long drm_prime_get_contiguous_size(struct sg_table *sgt);
|
|
+
|
|
/* helper functions for importing */
|
|
struct drm_gem_object *drm_gem_prime_import_dev(struct drm_device *dev,
|
|
struct dma_buf *dma_buf,
|
|
|
|
From 4e60d2c4b502537362bae39f3d15b56c41a20648 Mon Sep 17 00:00:00 2001
|
|
From: Marek Szyprowski <m.szyprowski@samsung.com>
|
|
Date: Fri, 8 May 2020 16:05:14 +0200
|
|
Subject: [PATCH] drm: prime: use sgtable iterators in
|
|
drm_prime_sg_to_page_addr_arrays()
|
|
|
|
Replace the current hand-crafted code for extracting pages and DMA
|
|
addresses from the given scatterlist by the much more robust
|
|
code based on the generic scatterlist iterators and recently
|
|
introduced sg_table-based wrappers. The resulting code is simple and
|
|
easy to understand, so the comment describing the old code is no
|
|
longer needed.
|
|
|
|
Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com>
|
|
Reviewed-by: Andrzej Hajda <a.hajda@samsung.com>
|
|
Reviewed-by: Robin Murphy <robin.murphy@arm.com>
|
|
(cherry picked from commit 0552daac2d18fc92c71c94492476b8eb521227e9)
|
|
---
|
|
drivers/gpu/drm/drm_prime.c | 49 ++++++++++++++-------------------------------
|
|
1 file changed, 15 insertions(+), 34 deletions(-)
|
|
|
|
diff --git a/drivers/gpu/drm/drm_prime.c b/drivers/gpu/drm/drm_prime.c
|
|
index 5a134c63856f..9d2643f2d9e7 100644
|
|
--- a/drivers/gpu/drm/drm_prime.c
|
|
+++ b/drivers/gpu/drm/drm_prime.c
|
|
@@ -997,45 +997,26 @@ EXPORT_SYMBOL(drm_gem_prime_import);
|
|
int drm_prime_sg_to_page_addr_arrays(struct sg_table *sgt, struct page **pages,
|
|
dma_addr_t *addrs, int max_entries)
|
|
{
|
|
- unsigned count;
|
|
- struct scatterlist *sg;
|
|
- struct page *page;
|
|
- u32 page_len, page_index;
|
|
- dma_addr_t addr;
|
|
- u32 dma_len, dma_index;
|
|
-
|
|
- /*
|
|
- * Scatterlist elements contains both pages and DMA addresses, but
|
|
- * one shoud not assume 1:1 relation between them. The sg->length is
|
|
- * the size of the physical memory chunk described by the sg->page,
|
|
- * while sg_dma_len(sg) is the size of the DMA (IO virtual) chunk
|
|
- * described by the sg_dma_address(sg).
|
|
- */
|
|
- page_index = 0;
|
|
- dma_index = 0;
|
|
- for_each_sg(sgt->sgl, sg, sgt->nents, count) {
|
|
- page_len = sg->length;
|
|
- page = sg_page(sg);
|
|
- dma_len = sg_dma_len(sg);
|
|
- addr = sg_dma_address(sg);
|
|
-
|
|
- while (pages && page_len > 0) {
|
|
- if (WARN_ON(page_index >= max_entries))
|
|
+ struct sg_dma_page_iter dma_iter;
|
|
+ struct sg_page_iter page_iter;
|
|
+ struct page **p = pages;
|
|
+ dma_addr_t *a = addrs;
|
|
+
|
|
+ if (pages) {
|
|
+ for_each_sgtable_page(sgt, &page_iter, 0) {
|
|
+ if (WARN_ON(p - pages >= max_entries))
|
|
return -1;
|
|
- pages[page_index] = page;
|
|
- page++;
|
|
- page_len -= PAGE_SIZE;
|
|
- page_index++;
|
|
+ *p++ = sg_page_iter_page(&page_iter);
|
|
}
|
|
- while (addrs && dma_len > 0) {
|
|
- if (WARN_ON(dma_index >= max_entries))
|
|
+ }
|
|
+ if (addrs) {
|
|
+ for_each_sgtable_dma_page(sgt, &dma_iter, 0) {
|
|
+ if (WARN_ON(a - addrs >= max_entries))
|
|
return -1;
|
|
- addrs[dma_index] = addr;
|
|
- addr += PAGE_SIZE;
|
|
- dma_len -= PAGE_SIZE;
|
|
- dma_index++;
|
|
+ *a++ = sg_page_iter_dma_address(&dma_iter);
|
|
}
|
|
}
|
|
+
|
|
return 0;
|
|
}
|
|
EXPORT_SYMBOL(drm_prime_sg_to_page_addr_arrays);
|
|
|
|
From ec3929e32f4ca8176edcb0d5ba72ea2051ccfd11 Mon Sep 17 00:00:00 2001
|
|
From: Marek Szyprowski <m.szyprowski@samsung.com>
|
|
Date: Mon, 11 May 2020 12:27:54 +0200
|
|
Subject: [PATCH] drm: core: fix common struct sg_table related issues
|
|
|
|
The Documentation/DMA-API-HOWTO.txt states that the dma_map_sg() function
|
|
returns the number of the created entries in the DMA address space.
|
|
However the subsequent calls to the dma_sync_sg_for_{device,cpu}() and
|
|
dma_unmap_sg must be called with the original number of the entries
|
|
passed to the dma_map_sg().
|
|
|
|
struct sg_table is a common structure used for describing a non-contiguous
|
|
memory buffer, used commonly in the DRM and graphics subsystems. It
|
|
consists of a scatterlist with memory pages and DMA addresses (sgl entry),
|
|
as well as the number of scatterlist entries: CPU pages (orig_nents entry)
|
|
and DMA mapped pages (nents entry).
|
|
|
|
It turned out that it was a common mistake to misuse nents and orig_nents
|
|
entries, calling DMA-mapping functions with a wrong number of entries or
|
|
ignoring the number of mapped entries returned by the dma_map_sg()
|
|
function.
|
|
|
|
To avoid such issues, lets use a common dma-mapping wrappers operating
|
|
directly on the struct sg_table objects and use scatterlist page
|
|
iterators where possible. This, almost always, hides references to the
|
|
nents and orig_nents entries, making the code robust, easier to follow
|
|
and copy/paste safe.
|
|
|
|
Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com>
|
|
Reviewed-by: Andrzej Hajda <a.hajda@samsung.com>
|
|
Reviewed-by: Robin Murphy <robin.murphy@arm.com>
|
|
(cherry picked from commit 6c6fa39ca958d5313ff90d3e6c3064e0043c1da3)
|
|
---
|
|
drivers/gpu/drm/drm_cache.c | 2 +-
|
|
drivers/gpu/drm/drm_gem_shmem_helper.c | 14 +++++++++-----
|
|
drivers/gpu/drm/drm_prime.c | 11 ++++++-----
|
|
3 files changed, 16 insertions(+), 11 deletions(-)
|
|
|
|
diff --git a/drivers/gpu/drm/drm_cache.c b/drivers/gpu/drm/drm_cache.c
|
|
index 03e01b000f7a..0fe3c496002a 100644
|
|
--- a/drivers/gpu/drm/drm_cache.c
|
|
+++ b/drivers/gpu/drm/drm_cache.c
|
|
@@ -127,7 +127,7 @@ drm_clflush_sg(struct sg_table *st)
|
|
struct sg_page_iter sg_iter;
|
|
|
|
mb(); /*CLFLUSH is ordered only by using memory barriers*/
|
|
- for_each_sg_page(st->sgl, &sg_iter, st->nents, 0)
|
|
+ for_each_sgtable_page(st, &sg_iter, 0)
|
|
drm_clflush_page(sg_page_iter_page(&sg_iter));
|
|
mb(); /*Make sure that all cache line entry is flushed*/
|
|
|
|
diff --git a/drivers/gpu/drm/drm_gem_shmem_helper.c b/drivers/gpu/drm/drm_gem_shmem_helper.c
|
|
index 0a952f27c184..d77c9f8ff26c 100644
|
|
--- a/drivers/gpu/drm/drm_gem_shmem_helper.c
|
|
+++ b/drivers/gpu/drm/drm_gem_shmem_helper.c
|
|
@@ -126,8 +126,8 @@ void drm_gem_shmem_free_object(struct drm_gem_object *obj)
|
|
drm_prime_gem_destroy(obj, shmem->sgt);
|
|
} else {
|
|
if (shmem->sgt) {
|
|
- dma_unmap_sg(obj->dev->dev, shmem->sgt->sgl,
|
|
- shmem->sgt->nents, DMA_BIDIRECTIONAL);
|
|
+ dma_unmap_sgtable(obj->dev->dev, shmem->sgt,
|
|
+ DMA_BIDIRECTIONAL, 0);
|
|
sg_free_table(shmem->sgt);
|
|
kfree(shmem->sgt);
|
|
}
|
|
@@ -424,8 +424,7 @@ void drm_gem_shmem_purge_locked(struct drm_gem_object *obj)
|
|
|
|
WARN_ON(!drm_gem_shmem_is_purgeable(shmem));
|
|
|
|
- dma_unmap_sg(obj->dev->dev, shmem->sgt->sgl,
|
|
- shmem->sgt->nents, DMA_BIDIRECTIONAL);
|
|
+ dma_unmap_sgtable(obj->dev->dev, shmem->sgt, DMA_BIDIRECTIONAL, 0);
|
|
sg_free_table(shmem->sgt);
|
|
kfree(shmem->sgt);
|
|
shmem->sgt = NULL;
|
|
@@ -697,12 +696,17 @@ struct sg_table *drm_gem_shmem_get_pages_sgt(struct drm_gem_object *obj)
|
|
goto err_put_pages;
|
|
}
|
|
/* Map the pages for use by the h/w. */
|
|
- dma_map_sg(obj->dev->dev, sgt->sgl, sgt->nents, DMA_BIDIRECTIONAL);
|
|
+ ret = dma_map_sgtable(obj->dev->dev, sgt, DMA_BIDIRECTIONAL, 0);
|
|
+ if (ret)
|
|
+ goto err_free_sgt;
|
|
|
|
shmem->sgt = sgt;
|
|
|
|
return sgt;
|
|
|
|
+err_free_sgt:
|
|
+ sg_free_table(sgt);
|
|
+ kfree(sgt);
|
|
err_put_pages:
|
|
drm_gem_shmem_put_pages(shmem);
|
|
return ERR_PTR(ret);
|
|
diff --git a/drivers/gpu/drm/drm_prime.c b/drivers/gpu/drm/drm_prime.c
|
|
index 9d2643f2d9e7..11fe9ff76fd5 100644
|
|
--- a/drivers/gpu/drm/drm_prime.c
|
|
+++ b/drivers/gpu/drm/drm_prime.c
|
|
@@ -617,6 +617,7 @@ struct sg_table *drm_gem_map_dma_buf(struct dma_buf_attachment *attach,
|
|
{
|
|
struct drm_gem_object *obj = attach->dmabuf->priv;
|
|
struct sg_table *sgt;
|
|
+ int ret;
|
|
|
|
if (WARN_ON(dir == DMA_NONE))
|
|
return ERR_PTR(-EINVAL);
|
|
@@ -626,11 +627,12 @@ struct sg_table *drm_gem_map_dma_buf(struct dma_buf_attachment *attach,
|
|
else
|
|
sgt = obj->dev->driver->gem_prime_get_sg_table(obj);
|
|
|
|
- if (!dma_map_sg_attrs(attach->dev, sgt->sgl, sgt->nents, dir,
|
|
- DMA_ATTR_SKIP_CPU_SYNC)) {
|
|
+ ret = dma_map_sgtable(attach->dev, sgt, dir,
|
|
+ DMA_ATTR_SKIP_CPU_SYNC);
|
|
+ if (ret) {
|
|
sg_free_table(sgt);
|
|
kfree(sgt);
|
|
- sgt = ERR_PTR(-ENOMEM);
|
|
+ sgt = ERR_PTR(ret);
|
|
}
|
|
|
|
return sgt;
|
|
@@ -652,8 +654,7 @@ void drm_gem_unmap_dma_buf(struct dma_buf_attachment *attach,
|
|
if (!sgt)
|
|
return;
|
|
|
|
- dma_unmap_sg_attrs(attach->dev, sgt->sgl, sgt->nents, dir,
|
|
- DMA_ATTR_SKIP_CPU_SYNC);
|
|
+ dma_unmap_sgtable(attach->dev, sgt, dir, DMA_ATTR_SKIP_CPU_SYNC);
|
|
sg_free_table(sgt);
|
|
kfree(sgt);
|
|
}
|
|
|
|
From 03fcee5f1d9c78e00f2000cf87843020c5fb1634 Mon Sep 17 00:00:00 2001
|
|
From: Marek Szyprowski <m.szyprowski@samsung.com>
|
|
Date: Thu, 30 Apr 2020 14:02:47 +0200
|
|
Subject: [PATCH] drm: rockchip: use common helper for a scatterlist contiguity
|
|
check
|
|
|
|
Use common helper for checking the contiguity of the imported dma-buf.
|
|
|
|
Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com>
|
|
Reviewed-by: Robin Murphy <robin.murphy@arm.com>
|
|
(cherry picked from commit 6a8f15c62cd9235a3a4eb1c96e79131061310d57)
|
|
---
|
|
drivers/gpu/drm/rockchip/rockchip_drm_gem.c | 19 +------------------
|
|
1 file changed, 1 insertion(+), 18 deletions(-)
|
|
|
|
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_gem.c b/drivers/gpu/drm/rockchip/rockchip_drm_gem.c
|
|
index 0055d86576f7..d1559146dcce 100644
|
|
--- a/drivers/gpu/drm/rockchip/rockchip_drm_gem.c
|
|
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_gem.c
|
|
@@ -461,23 +461,6 @@ struct sg_table *rockchip_gem_prime_get_sg_table(struct drm_gem_object *obj)
|
|
return sgt;
|
|
}
|
|
|
|
-static unsigned long rockchip_sg_get_contiguous_size(struct sg_table *sgt,
|
|
- int count)
|
|
-{
|
|
- struct scatterlist *s;
|
|
- dma_addr_t expected = sg_dma_address(sgt->sgl);
|
|
- unsigned int i;
|
|
- unsigned long size = 0;
|
|
-
|
|
- for_each_sg(sgt->sgl, s, count, i) {
|
|
- if (sg_dma_address(s) != expected)
|
|
- break;
|
|
- expected = sg_dma_address(s) + sg_dma_len(s);
|
|
- size += sg_dma_len(s);
|
|
- }
|
|
- return size;
|
|
-}
|
|
-
|
|
static int
|
|
rockchip_gem_iommu_map_sg(struct drm_device *drm,
|
|
struct dma_buf_attachment *attach,
|
|
@@ -499,7 +482,7 @@ rockchip_gem_dma_map_sg(struct drm_device *drm,
|
|
if (!count)
|
|
return -EINVAL;
|
|
|
|
- if (rockchip_sg_get_contiguous_size(sg, count) < attach->dmabuf->size) {
|
|
+ if (drm_prime_get_contiguous_size(sg) < attach->dmabuf->size) {
|
|
DRM_ERROR("failed to map sg_table to contiguous linear address.\n");
|
|
dma_unmap_sg(drm->dev, sg->sgl, sg->nents,
|
|
DMA_BIDIRECTIONAL);
|
|
|
|
From 11f9a73528dc2bd14e6d7e54cb8df803478eef68 Mon Sep 17 00:00:00 2001
|
|
From: Marek Szyprowski <m.szyprowski@samsung.com>
|
|
Date: Tue, 28 Apr 2020 13:10:01 +0200
|
|
Subject: [PATCH] drm: rockchip: fix common struct sg_table related issues
|
|
|
|
The Documentation/DMA-API-HOWTO.txt states that the dma_map_sg() function
|
|
returns the number of the created entries in the DMA address space.
|
|
However the subsequent calls to the dma_sync_sg_for_{device,cpu}() and
|
|
dma_unmap_sg must be called with the original number of the entries
|
|
passed to the dma_map_sg().
|
|
|
|
struct sg_table is a common structure used for describing a non-contiguous
|
|
memory buffer, used commonly in the DRM and graphics subsystems. It
|
|
consists of a scatterlist with memory pages and DMA addresses (sgl entry),
|
|
as well as the number of scatterlist entries: CPU pages (orig_nents entry)
|
|
and DMA mapped pages (nents entry).
|
|
|
|
It turned out that it was a common mistake to misuse nents and orig_nents
|
|
entries, calling DMA-mapping functions with a wrong number of entries or
|
|
ignoring the number of mapped entries returned by the dma_map_sg()
|
|
function.
|
|
|
|
To avoid such issues, lets use a common dma-mapping wrappers operating
|
|
directly on the struct sg_table objects and use scatterlist page
|
|
iterators where possible. This, almost always, hides references to the
|
|
nents and orig_nents entries, making the code robust, easier to follow
|
|
and copy/paste safe.
|
|
|
|
Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com>
|
|
Reviewed-by: Robin Murphy <robin.murphy@arm.com>
|
|
(cherry picked from commit 82c245b592da791c63316e7a82d9b9d01552c0c5)
|
|
---
|
|
drivers/gpu/drm/rockchip/rockchip_drm_gem.c | 23 ++++++++++-------------
|
|
1 file changed, 10 insertions(+), 13 deletions(-)
|
|
|
|
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_gem.c b/drivers/gpu/drm/rockchip/rockchip_drm_gem.c
|
|
index d1559146dcce..62e5d0970525 100644
|
|
--- a/drivers/gpu/drm/rockchip/rockchip_drm_gem.c
|
|
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_gem.c
|
|
@@ -36,8 +36,8 @@ static int rockchip_gem_iommu_map(struct rockchip_gem_object *rk_obj)
|
|
|
|
rk_obj->dma_addr = rk_obj->mm.start;
|
|
|
|
- ret = iommu_map_sg(private->domain, rk_obj->dma_addr, rk_obj->sgt->sgl,
|
|
- rk_obj->sgt->nents, prot);
|
|
+ ret = iommu_map_sgtable(private->domain, rk_obj->dma_addr, rk_obj->sgt,
|
|
+ prot);
|
|
if (ret < rk_obj->base.size) {
|
|
DRM_ERROR("failed to map buffer: size=%zd request_size=%zd\n",
|
|
ret, rk_obj->base.size);
|
|
@@ -99,11 +99,10 @@ static int rockchip_gem_get_pages(struct rockchip_gem_object *rk_obj)
|
|
* TODO: Replace this by drm_clflush_sg() once it can be implemented
|
|
* without relying on symbols that are not exported.
|
|
*/
|
|
- for_each_sg(rk_obj->sgt->sgl, s, rk_obj->sgt->nents, i)
|
|
+ for_each_sgtable_sg(rk_obj->sgt, s, i)
|
|
sg_dma_address(s) = sg_phys(s);
|
|
|
|
- dma_sync_sg_for_device(drm->dev, rk_obj->sgt->sgl, rk_obj->sgt->nents,
|
|
- DMA_TO_DEVICE);
|
|
+ dma_sync_sgtable_for_device(drm->dev, rk_obj->sgt, DMA_TO_DEVICE);
|
|
|
|
return 0;
|
|
|
|
@@ -351,8 +350,8 @@ void rockchip_gem_free_object(struct drm_gem_object *obj)
|
|
if (private->domain) {
|
|
rockchip_gem_iommu_unmap(rk_obj);
|
|
} else {
|
|
- dma_unmap_sg(drm->dev, rk_obj->sgt->sgl,
|
|
- rk_obj->sgt->nents, DMA_BIDIRECTIONAL);
|
|
+ dma_unmap_sgtable(drm->dev, rk_obj->sgt,
|
|
+ DMA_BIDIRECTIONAL, 0);
|
|
}
|
|
drm_prime_gem_destroy(obj, rk_obj->sgt);
|
|
} else {
|
|
@@ -477,15 +476,13 @@ rockchip_gem_dma_map_sg(struct drm_device *drm,
|
|
struct sg_table *sg,
|
|
struct rockchip_gem_object *rk_obj)
|
|
{
|
|
- int count = dma_map_sg(drm->dev, sg->sgl, sg->nents,
|
|
- DMA_BIDIRECTIONAL);
|
|
- if (!count)
|
|
- return -EINVAL;
|
|
+ int err = dma_map_sgtable(drm->dev, sg, DMA_BIDIRECTIONAL, 0);
|
|
+ if (err)
|
|
+ return err;
|
|
|
|
if (drm_prime_get_contiguous_size(sg) < attach->dmabuf->size) {
|
|
DRM_ERROR("failed to map sg_table to contiguous linear address.\n");
|
|
- dma_unmap_sg(drm->dev, sg->sgl, sg->nents,
|
|
- DMA_BIDIRECTIONAL);
|
|
+ dma_unmap_sgtable(drm->dev, sg, DMA_BIDIRECTIONAL, 0);
|
|
return -EINVAL;
|
|
}
|
|
|
|
|
|
From 314b770980da1e7d968e8178194de70cbb44fd6c Mon Sep 17 00:00:00 2001
|
|
From: Robin Murphy <robin.murphy@arm.com>
|
|
Date: Thu, 3 Sep 2020 14:59:23 +0100
|
|
Subject: [PATCH] drm/panfrost: Set DMA max segment size
|
|
|
|
Since all we do with scatterlists is map them in the MMU, we don't have
|
|
any hardware constraints on how they're laid out. Let the DMA layer know
|
|
so it won't warn when DMA API debugging is enabled.
|
|
|
|
Signed-off-by: Robin Murphy <robin.murphy@arm.com>
|
|
Reviewed-by: Steven Price <steven.price@arm.com>
|
|
Signed-off-by: Steven Price <steven.price@arm.com>
|
|
Link: https://patchwork.freedesktop.org/patch/msgid/04371bc36512076b7feee07f854e56b80675d953.1599141563.git.robin.murphy@arm.com
|
|
(cherry picked from commit ac5037afefd33fea9a9c1a4a5ac46ece396e7465)
|
|
---
|
|
drivers/gpu/drm/panfrost/panfrost_gpu.c | 1 +
|
|
1 file changed, 1 insertion(+)
|
|
|
|
diff --git a/drivers/gpu/drm/panfrost/panfrost_gpu.c b/drivers/gpu/drm/panfrost/panfrost_gpu.c
|
|
index e0f190e43813..eea049c640a6 100644
|
|
--- a/drivers/gpu/drm/panfrost/panfrost_gpu.c
|
|
+++ b/drivers/gpu/drm/panfrost/panfrost_gpu.c
|
|
@@ -344,6 +344,7 @@ int panfrost_gpu_init(struct panfrost_device *pfdev)
|
|
|
|
dma_set_mask_and_coherent(pfdev->dev,
|
|
DMA_BIT_MASK(FIELD_GET(0xff00, pfdev->features.mmu_features)));
|
|
+ dma_set_max_seg_size(pfdev->dev, UINT_MAX);
|
|
|
|
irq = platform_get_irq_byname(to_platform_device(pfdev->dev), "gpu");
|
|
if (irq <= 0)
|
|
|
|
From 99d273baa069a7838597fdd601e01248d12c2fd1 Mon Sep 17 00:00:00 2001
|
|
From: Alex Dewar <alex.dewar90@gmail.com>
|
|
Date: Wed, 9 Sep 2020 20:02:08 +0100
|
|
Subject: [PATCH] drm/bridge: dw-mipi-dsi: Use kmemdup cf. kmalloc+memcpy
|
|
|
|
kmemdup can be used instead of kmalloc+memcpy. Replace an occurrence of
|
|
this pattern.
|
|
|
|
Issue identified with Coccinelle.
|
|
|
|
Signed-off-by: Alex Dewar <alex.dewar90@gmail.com>
|
|
Acked-by: Neil Armstrong <narmstrong@baylibre.com>
|
|
Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
|
|
Link: https://patchwork.freedesktop.org/patch/msgid/20200909190213.156302-1-alex.dewar90@gmail.com
|
|
(cherry picked from commit 33f290811d4c1a09c4e92f5bf0458525835dbcba)
|
|
---
|
|
drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c | 4 +---
|
|
1 file changed, 1 insertion(+), 3 deletions(-)
|
|
|
|
diff --git a/drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c b/drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c
|
|
index 52f5c5a2ed64..7e9a62ad56e8 100644
|
|
--- a/drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c
|
|
+++ b/drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c
|
|
@@ -1049,12 +1049,10 @@ static void debugfs_create_files(void *data)
|
|
};
|
|
int i;
|
|
|
|
- dsi->debugfs_vpg = kmalloc(sizeof(debugfs), GFP_KERNEL);
|
|
+ dsi->debugfs_vpg = kmemdup(debugfs, sizeof(debugfs), GFP_KERNEL);
|
|
if (!dsi->debugfs_vpg)
|
|
return;
|
|
|
|
- memcpy(dsi->debugfs_vpg, debugfs, sizeof(debugfs));
|
|
-
|
|
for (i = 0; i < ARRAY_SIZE(debugfs); i++)
|
|
debugfs_create_file(dsi->debugfs_vpg[i].name, 0644,
|
|
dsi->debugfs, &dsi->debugfs_vpg[i],
|
|
|
|
From 0d1797eb5960177619add1f2ad6f2e57341a628b Mon Sep 17 00:00:00 2001
|
|
From: Neil Armstrong <narmstrong@baylibre.com>
|
|
Date: Fri, 4 Sep 2020 14:55:31 +0200
|
|
Subject: [PATCH] drm/bridge: dw-mipi-dsi: permit configuring the escape clock
|
|
rate
|
|
|
|
The Amlogic D-PHY in the Amlogic AXG SoC Family does support a frequency
|
|
higher than 10MHz for the TX Escape Clock, thus make the target rate
|
|
configurable.
|
|
|
|
Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
|
|
Reviewed-by: Philippe Cornu <philippe.cornu@st.com>
|
|
Link: https://patchwork.freedesktop.org/patch/msgid/20200904125531.15248-1-narmstrong@baylibre.com
|
|
(cherry picked from commit a328ca7e4af347e47742f36933df0fdac1c24ea5)
|
|
---
|
|
drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c | 25 ++++++++++++++++++++-----
|
|
include/drm/bridge/dw_mipi_dsi.h | 1 +
|
|
2 files changed, 21 insertions(+), 5 deletions(-)
|
|
|
|
diff --git a/drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c b/drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c
|
|
index 7e9a62ad56e8..6b268f9445b3 100644
|
|
--- a/drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c
|
|
+++ b/drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c
|
|
@@ -605,15 +605,30 @@ static void dw_mipi_dsi_disable(struct dw_mipi_dsi *dsi)
|
|
|
|
static void dw_mipi_dsi_init(struct dw_mipi_dsi *dsi)
|
|
{
|
|
+ const struct dw_mipi_dsi_phy_ops *phy_ops = dsi->plat_data->phy_ops;
|
|
+ unsigned int esc_rate; /* in MHz */
|
|
+ u32 esc_clk_division;
|
|
+ int ret;
|
|
+
|
|
/*
|
|
* The maximum permitted escape clock is 20MHz and it is derived from
|
|
- * lanebyteclk, which is running at "lane_mbps / 8". Thus we want:
|
|
- *
|
|
- * (lane_mbps >> 3) / esc_clk_division < 20
|
|
+ * lanebyteclk, which is running at "lane_mbps / 8".
|
|
+ */
|
|
+ if (phy_ops->get_esc_clk_rate) {
|
|
+ ret = phy_ops->get_esc_clk_rate(dsi->plat_data->priv_data,
|
|
+ &esc_rate);
|
|
+ if (ret)
|
|
+ DRM_DEBUG_DRIVER("Phy get_esc_clk_rate() failed\n");
|
|
+ } else
|
|
+ esc_rate = 20; /* Default to 20MHz */
|
|
+
|
|
+ /*
|
|
+ * We want :
|
|
+ * (lane_mbps >> 3) / esc_clk_division < X
|
|
* which is:
|
|
- * (lane_mbps >> 3) / 20 > esc_clk_division
|
|
+ * (lane_mbps >> 3) / X > esc_clk_division
|
|
*/
|
|
- u32 esc_clk_division = (dsi->lane_mbps >> 3) / 20 + 1;
|
|
+ esc_clk_division = (dsi->lane_mbps >> 3) / esc_rate + 1;
|
|
|
|
dsi_write(dsi, DSI_PWR_UP, RESET);
|
|
|
|
diff --git a/include/drm/bridge/dw_mipi_dsi.h b/include/drm/bridge/dw_mipi_dsi.h
|
|
index b0e390b3288e..bda8aa7c2280 100644
|
|
--- a/include/drm/bridge/dw_mipi_dsi.h
|
|
+++ b/include/drm/bridge/dw_mipi_dsi.h
|
|
@@ -36,6 +36,7 @@ struct dw_mipi_dsi_phy_ops {
|
|
unsigned int *lane_mbps);
|
|
int (*get_timing)(void *priv_data, unsigned int lane_mbps,
|
|
struct dw_mipi_dsi_dphy_timing *timing);
|
|
+ int (*get_esc_clk_rate)(void *priv_data, unsigned int *esc_clk_rate);
|
|
};
|
|
|
|
struct dw_mipi_dsi_host_ops {
|