From 081f8fe6fa92586572a59a09999504284ab3364c Mon Sep 17 00:00:00 2001 From: ChiHun Won Date: Tue, 19 Jun 2018 10:04:20 +0900 Subject: [PATCH] fbdev: dpu20: reserved frame buffer memory area Change-Id: I67988ad14d30ae391702f8b9811f3b1577befce2 Signed-off-by: ChiHun Won --- drivers/video/fbdev/exynos/dpu20/decon_core.c | 11 +++ drivers/video/fbdev/exynos/dpu20/dsim.h | 7 ++ drivers/video/fbdev/exynos/dpu20/dsim_drv.c | 94 +++++++++++++++++++ 3 files changed, 112 insertions(+) diff --git a/drivers/video/fbdev/exynos/dpu20/decon_core.c b/drivers/video/fbdev/exynos/dpu20/decon_core.c index 8acc72d72fd6..7754858466f4 100644 --- a/drivers/video/fbdev/exynos/dpu20/decon_core.c +++ b/drivers/video/fbdev/exynos/dpu20/decon_core.c @@ -1866,6 +1866,7 @@ static void decon_release_old_bufs(struct decon_device *decon, int *plane_cnt) { int i, j; + struct dsim_device *dsim; for (i = 0; i < decon->dt.max_win; i++) { for (j = 0; j < plane_cnt[i]; ++j) @@ -1875,6 +1876,16 @@ static void decon_release_old_bufs(struct decon_device *decon, decon_free_dma_buf(decon, &dma_bufs[i][j]); } + if (decon->dt.out_type == DECON_OUT_DSI) { + if (decon->lcd_info->mode == DECON_VIDEO_MODE) { + dsim = v4l2_get_subdevdata(decon->out_sd[0]); + if (dsim->fb_reservation) { + v4l2_subdev_call(decon->out_sd[0], core, ioctl, + DSIM_IOC_FREE_FB_RES, NULL); + } + } + } + if (decon->dt.out_type == DECON_OUT_WB) { for (j = 0; j < plane_cnt[0]; ++j) decon_free_dma_buf(decon, diff --git a/drivers/video/fbdev/exynos/dpu20/dsim.h b/drivers/video/fbdev/exynos/dpu20/dsim.h index 789c69bcacc4..d26bc5163187 100644 --- a/drivers/video/fbdev/exynos/dpu20/dsim.h +++ b/drivers/video/fbdev/exynos/dpu20/dsim.h @@ -233,6 +233,12 @@ struct dsim_device { int total_underrun_cnt; struct backlight_device *bd; int idle_ip_index; + + /* true - fb reserved */ + /* false - fb not reserved */ + bool fb_reservation; + phys_addr_t phys_addr; + phys_addr_t phys_size; }; struct dsim_lcd_driver { @@ -388,6 +394,7 @@ static inline bool IS_DSIM_OFF_STATE(struct dsim_device *dsim) #define DSIM_IOC_DUMP _IOW('D', 8, u32) #define DSIM_IOC_GET_WCLK _IOW('D', 9, u32) #define DSIM_IOC_SET_CONFIG _IOW('D', 10, u32) +#define DSIM_IOC_FREE_FB_RES _IOW('D', 11, u32) #define DSIM_IOC_DOZE _IOW('D', 20, u32) #define DSIM_IOC_DOZE_SUSPEND _IOW('D', 21, u32) diff --git a/drivers/video/fbdev/exynos/dpu20/dsim_drv.c b/drivers/video/fbdev/exynos/dpu20/dsim_drv.c index 18a347529991..7ba3a987094a 100644 --- a/drivers/video/fbdev/exynos/dpu20/dsim_drv.c +++ b/drivers/video/fbdev/exynos/dpu20/dsim_drv.c @@ -41,6 +41,9 @@ #include #endif +#include +#include "../../../../../mm/internal.h" + #include "decon.h" #include "dsim.h" @@ -981,6 +984,47 @@ static int dsim_s_stream(struct v4l2_subdev *sd, int enable) return dsim_disable(dsim); } +static int dsim_free_fb_resource(struct dsim_device *dsim) +{ + dsim_info("one to one unmapping: 0x%x\n", dsim->phys_addr); + + /* unmap */ + iovmm_unmap_oto(dsim->dev, dsim->phys_addr); + + /* unreserve memory */ + of_reserved_mem_device_release(dsim->dev); + + /* update state */ + dsim->fb_reservation = false; + dsim->phys_addr = 0xdead; + dsim->phys_size = 0; + + return 0; +} + +static int dsim_acquire_fb_resource(struct dsim_device *dsim) +{ + int ret = 0; + + ret = of_reserved_mem_device_init_by_idx(dsim->dev, dsim->dev->of_node, 0); + if (ret) { + dsim_err("failed reserved mem device init: %d\n", ret); + dsim->fb_reservation = false; + goto err; + } else + dsim->fb_reservation = true; + + ret = iovmm_map_oto(dsim->dev, dsim->phys_addr, dsim->phys_size); + if (ret) + dsim_err("failed one to one mapping: %d\n", ret); + else + dsim_info("one to one mapping: 0x%x, 0x%x\n", + dsim->phys_addr, + dsim->phys_size); +err: + return ret; +} + static long dsim_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg) { struct dsim_device *dsim = container_of(sd, struct dsim_device, sd); @@ -1009,6 +1053,10 @@ static long dsim_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg) case EXYNOS_DPU_GET_ACLK: return clk_get_rate(dsim->res.aclk); + case DSIM_IOC_FREE_FB_RES: + ret = dsim_free_fb_resource(dsim); + break; + case DSIM_IOC_DOZE: ret = dsim_doze(dsim); break; @@ -1497,6 +1545,9 @@ static int dsim_probe(struct platform_device *pdev) exynos_update_ip_idle_status(dsim->idle_ip_index, 1); #endif + if (dsim->lcd_info.mode == DECON_VIDEO_MODE) + dsim_acquire_fb_resource(dsim); + pm_runtime_enable(dev); ret = iovmm_activate(dev); @@ -1631,6 +1682,49 @@ static void __exit dsim_exit(void) } module_exit(dsim_exit); + +static int rmem_device_init(struct reserved_mem *rmem, struct device *dev) +{ + struct dsim_device *dsim = dev_get_drvdata(dev); + + dsim->phys_addr = rmem->base; + dsim->phys_size = rmem->size; + + return 0; +} + +/* of_reserved_mem_device_release(dev) when reserved memory is no logner 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; + + pr_info("%s: base=%pa, size=%pa, first=%pa, last=%pa\n", + __func__, &rmem->base, &rmem->size, first, last); + + 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, +}; + +static int __init fb_rmem_setup(struct reserved_mem *rmem) +{ + pr_info("%s: base=%pa, size=%pa\n", __func__, &rmem->base, &rmem->size); + + rmem->ops = &rmem_ops; + return 0; +} +RESERVEDMEM_OF_DECLARE(fb_rmem, "exynos,fb_rmem", fb_rmem_setup); + MODULE_AUTHOR("Yeongran Shin "); MODULE_DESCRIPTION("Samusung EXYNOS DSIM driver"); MODULE_LICENSE("GPL"); -- 2.20.1