diff options
author | Kwanghyun Chung <khyun.chung@samsung.com> | 2022-02-15 18:26:53 +0900 |
---|---|---|
committer | Leo Chen <yinchiuan@google.com> | 2022-11-30 11:48:04 +0000 |
commit | dbbb165b0f165b3de6a46b2c47888ec4f8368311 (patch) | |
tree | 98f385efc3ee0ebae88b5400d2a781ba3ad2f1f3 /samsung/exynos_drm_fb.c | |
parent | 09a22a6f6e06cf83560a2fa8729511d83c96308b (diff) | |
download | display-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.c | 77 |
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); |