summaryrefslogtreecommitdiff
path: root/samsung/exynos_drm_fb.c
diff options
context:
space:
mode:
authorKwanghyun Chung <khyun.chung@samsung.com>2022-02-15 18:26:53 +0900
committerLeo Chen <yinchiuan@google.com>2022-11-30 11:48:04 +0000
commitdbbb165b0f165b3de6a46b2c47888ec4f8368311 (patch)
tree98f385efc3ee0ebae88b5400d2a781ba3ad2f1f3 /samsung/exynos_drm_fb.c
parent09a22a6f6e06cf83560a2fa8729511d83c96308b (diff)
downloaddisplay-dbbb165b0f165b3de6a46b2c47888ec4f8368311.tar.gz
drm: samsung: support fb handover
Fb handover keeps a memory region for a frame from bootloader. This patch supports fb handover and controls reserved memory. Bug: 202947589 Test: Enable continuous splash Signed-off-by: Kwanghyun Chung <khyun.chung@samsung.com> Signed-off-by: Leo Chen <yinchiuan@google.com> (Cherry picked from commit 6164fbadf3ddbd87861a0d31f267398e8da485d8) Change-Id: I83189598c84a29cd06b7842520bf667f430b4f18
Diffstat (limited to 'samsung/exynos_drm_fb.c')
-rw-r--r--samsung/exynos_drm_fb.c77
1 files changed, 77 insertions, 0 deletions
diff --git a/samsung/exynos_drm_fb.c b/samsung/exynos_drm_fb.c
index 73183e1..d9c1770 100644
--- a/samsung/exynos_drm_fb.c
+++ b/samsung/exynos_drm_fb.c
@@ -24,6 +24,7 @@
#include <uapi/linux/videodev2_exynos_media.h>
#include <linux/dma-buf.h>
#include <linux/pm_runtime.h>
+#include <linux/of_reserved_mem.h>
#include <trace/dpu_trace.h>
@@ -469,6 +470,80 @@ static void exynos_atomic_bts_post_update(struct drm_device *dev,
}
}
+/*
+ * rmem_device_init is called in of_reserved_mem_device_init_by_idx function
+ * when reserved memory is required.
+ */
+static int rmem_device_init(struct reserved_mem *rmem, struct device *dev)
+{
+ struct decon_device *decon = dev_get_drvdata(dev);
+
+ decon->fb_handover.phys_addr = rmem->base;
+ decon->fb_handover.phys_size = rmem->size;
+ pr_debug("%s base(%pa) size(%pa)\n", __func__, &decon->fb_handover.phys_addr,
+ &decon->fb_handover.phys_size);
+
+ return 0;
+}
+
+/*
+ * rmem_device_release is called in of_reserved_mem_device_release function
+ * when reserved memory is no longer required.
+ */
+static void rmem_device_release(struct reserved_mem *rmem, struct device *dev)
+{
+ struct page *first = phys_to_page(PAGE_ALIGN(rmem->base));
+ struct page *last = phys_to_page((rmem->base + rmem->size) & PAGE_MASK);
+ struct page *page;
+
+ for (page = first; page != last; page++) {
+ __ClearPageReserved(page);
+ set_page_count(page, 1);
+ __free_pages(page, 0);
+ adjust_managed_page_count(page, 1);
+ }
+}
+
+static const struct reserved_mem_ops rmem_ops = {
+ .device_init = rmem_device_init,
+ .device_release = rmem_device_release,
+};
+
+void exynos_rmem_register(struct decon_device *decon)
+{
+ struct device_node *np, *rmem_np;
+ struct reserved_mem *rmem;
+ struct device *dev = decon->dev;
+
+ np = dev->of_node;
+
+ rmem_np = of_parse_phandle(np, "memory-region", 0);
+ if (!rmem_np) {
+ pr_debug("failed to get reserve memory phandle\n");
+ return;
+ }
+
+ rmem = of_reserved_mem_lookup(rmem_np);
+ if (!rmem) {
+ pr_err("failed to reserve memory lookup\n");
+ return;
+ }
+
+ of_node_put(rmem_np);
+ rmem->ops = &rmem_ops;
+ decon->fb_handover.rmem = rmem;
+ of_reserved_mem_device_init_by_idx(dev, np, 0);
+}
+
+static void exynos_rmem_free(struct decon_device *decon)
+{
+ of_reserved_mem_device_release(decon->dev);
+
+ decon->fb_handover.rmem = NULL;
+ decon->fb_handover.phys_size = 0;
+}
+
+
static void exynos_atomic_commit_tail(struct drm_atomic_state *old_state)
{
int i;
@@ -617,6 +692,8 @@ static void exynos_atomic_commit_tail(struct drm_atomic_state *old_state)
decon = crtc_to_decon(crtc);
if (disabling_crtc_mask & drm_crtc_mask(crtc))
pm_runtime_put_sync(decon->dev);
+ if (new_crtc_state->plane_mask && decon->fb_handover.rmem)
+ exynos_rmem_free(decon);
}
drm_atomic_helper_commit_hw_done(old_state);