fbdev: dpu20: reserved frame buffer memory area
authorChiHun Won <chihun.won@samsung.com>
Tue, 19 Jun 2018 01:04:20 +0000 (10:04 +0900)
committerEunyoung Lee <ey470.lee@samsung.com>
Wed, 20 Jun 2018 00:21:48 +0000 (09:21 +0900)
Change-Id: I67988ad14d30ae391702f8b9811f3b1577befce2
Signed-off-by: ChiHun Won <chihun.won@samsung.com>
drivers/video/fbdev/exynos/dpu20/decon_core.c
drivers/video/fbdev/exynos/dpu20/dsim.h
drivers/video/fbdev/exynos/dpu20/dsim_drv.c

index 8acc72d72fd620d47e77d610207bcb8c825daed9..7754858466f47f756a7b138ff16bbf8fa6ccf491 100644 (file)
@@ -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,
index 789c69bcacc48be1334620abaff167478e4925bf..d26bc51631877b8165b31f6b0e2fc9baee9ebf62 100644 (file)
@@ -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)
 
index 18a347529991ea93d15b9ddae5b484839dc0b02e..7ba3a987094a54c86824c47afc9683eac4d16feb 100644 (file)
@@ -41,6 +41,9 @@
 #include <linux/exynos_iovmm.h>
 #endif
 
+#include <linux/of_reserved_mem.h>
+#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 <yr613.shin@samsung.com>");
 MODULE_DESCRIPTION("Samusung EXYNOS DSIM driver");
 MODULE_LICENSE("GPL");