diff options
24 files changed, 324 insertions, 548 deletions
| diff --git a/drivers/gpu/drm/exynos/Makefile b/drivers/gpu/drm/exynos/Makefile index 3b323f1e0475..2ad146bbf4f5 100644 --- a/drivers/gpu/drm/exynos/Makefile +++ b/drivers/gpu/drm/exynos/Makefile @@ -4,7 +4,7 @@  # Direct Rendering Infrastructure (DRI) in XFree86 4.1.0 and higher.  exynosdrm-y := exynos_drm_drv.o exynos_drm_crtc.o exynos_drm_fb.o \ -		exynos_drm_gem.o exynos_drm_core.o exynos_drm_plane.o +		exynos_drm_gem.o exynos_drm_plane.o  exynosdrm-$(CONFIG_DRM_FBDEV_EMULATION) += exynos_drm_fbdev.o  exynosdrm-$(CONFIG_DRM_EXYNOS_IOMMU) += exynos_drm_iommu.o diff --git a/drivers/gpu/drm/exynos/exynos5433_drm_decon.c b/drivers/gpu/drm/exynos/exynos5433_drm_decon.c index 82c95c34447f..94529aa82339 100644 --- a/drivers/gpu/drm/exynos/exynos5433_drm_decon.c +++ b/drivers/gpu/drm/exynos/exynos5433_drm_decon.c @@ -265,7 +265,7 @@ static void decon_win_set_pixfmt(struct decon_context *ctx, unsigned int win,  	unsigned long val;  	val = readl(ctx->addr + DECON_WINCONx(win)); -	val &= ~WINCONx_BPPMODE_MASK; +	val &= WINCONx_ENWIN_F;  	switch (fb->format->format) {  	case DRM_FORMAT_XRGB1555: @@ -356,8 +356,8 @@ static void decon_update_plane(struct exynos_drm_crtc *crtc,  		writel(val, ctx->addr + DECON_VIDOSDxB(win));  	} -	val = VIDOSD_Wx_ALPHA_R_F(0x0) | VIDOSD_Wx_ALPHA_G_F(0x0) | -		VIDOSD_Wx_ALPHA_B_F(0x0); +	val = VIDOSD_Wx_ALPHA_R_F(0xff) | VIDOSD_Wx_ALPHA_G_F(0xff) | +		VIDOSD_Wx_ALPHA_B_F(0xff);  	writel(val, ctx->addr + DECON_VIDOSDxC(win));  	val = VIDOSD_Wx_ALPHA_R_F(0x0) | VIDOSD_Wx_ALPHA_G_F(0x0) | @@ -673,6 +673,8 @@ err:  static const struct dev_pm_ops exynos5433_decon_pm_ops = {  	SET_RUNTIME_PM_OPS(exynos5433_decon_suspend, exynos5433_decon_resume,  			   NULL) +	SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, +				     pm_runtime_force_resume)  };  static const struct of_device_id exynos5433_decon_driver_dt_match[] = { diff --git a/drivers/gpu/drm/exynos/exynos7_drm_decon.c b/drivers/gpu/drm/exynos/exynos7_drm_decon.c index 3931d5e33fe0..88cbd000eb09 100644 --- a/drivers/gpu/drm/exynos/exynos7_drm_decon.c +++ b/drivers/gpu/drm/exynos/exynos7_drm_decon.c @@ -832,6 +832,8 @@ static int exynos7_decon_resume(struct device *dev)  static const struct dev_pm_ops exynos7_decon_pm_ops = {  	SET_RUNTIME_PM_OPS(exynos7_decon_suspend, exynos7_decon_resume,  			   NULL) +	SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, +				pm_runtime_force_resume)  };  struct platform_driver decon_driver = { diff --git a/drivers/gpu/drm/exynos/exynos_dp.c b/drivers/gpu/drm/exynos/exynos_dp.c index af7ab1ceb50f..c8449ae4f4fe 100644 --- a/drivers/gpu/drm/exynos/exynos_dp.c +++ b/drivers/gpu/drm/exynos/exynos_dp.c @@ -16,6 +16,7 @@  #include <linux/clk.h>  #include <linux/of_graph.h>  #include <linux/component.h> +#include <linux/pm_runtime.h>  #include <video/of_display_timing.h>  #include <video/of_videomode.h>  #include <video/videomode.h> @@ -278,6 +279,8 @@ static int exynos_dp_resume(struct device *dev)  static const struct dev_pm_ops exynos_dp_pm_ops = {  	SET_RUNTIME_PM_OPS(exynos_dp_suspend, exynos_dp_resume, NULL) +	SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, +				pm_runtime_force_resume)  };  static const struct of_device_id exynos_dp_match[] = { diff --git a/drivers/gpu/drm/exynos/exynos_drm_core.c b/drivers/gpu/drm/exynos/exynos_drm_core.c deleted file mode 100644 index b0c0621fcdf7..000000000000 --- a/drivers/gpu/drm/exynos/exynos_drm_core.c +++ /dev/null @@ -1,119 +0,0 @@ -/* exynos_drm_core.c - * - * Copyright (c) 2011 Samsung Electronics Co., Ltd. - * Author: - *	Inki Dae <inki.dae@samsung.com> - *	Joonyoung Shim <jy0922.shim@samsung.com> - *	Seung-Woo Kim <sw0312.kim@samsung.com> - * - * This program is free software; you can redistribute  it and/or modify it - * under  the terms of  the GNU General  Public License as published by the - * Free Software Foundation;  either version 2 of the  License, or (at your - * option) any later version. - */ - -#include <drm/drmP.h> - -#include "exynos_drm_drv.h" -#include "exynos_drm_crtc.h" - -static LIST_HEAD(exynos_drm_subdrv_list); - -int exynos_drm_subdrv_register(struct exynos_drm_subdrv *subdrv) -{ -	if (!subdrv) -		return -EINVAL; - -	list_add_tail(&subdrv->list, &exynos_drm_subdrv_list); - -	return 0; -} - -int exynos_drm_subdrv_unregister(struct exynos_drm_subdrv *subdrv) -{ -	if (!subdrv) -		return -EINVAL; - -	list_del(&subdrv->list); - -	return 0; -} - -int exynos_drm_device_subdrv_probe(struct drm_device *dev) -{ -	struct exynos_drm_subdrv *subdrv, *n; -	int err; - -	if (!dev) -		return -EINVAL; - -	list_for_each_entry_safe(subdrv, n, &exynos_drm_subdrv_list, list) { -		if (subdrv->probe) { -			subdrv->drm_dev = dev; - -			/* -			 * this probe callback would be called by sub driver -			 * after setting of all resources to this sub driver, -			 * such as clock, irq and register map are done. -			 */ -			err = subdrv->probe(dev, subdrv->dev); -			if (err) { -				DRM_DEBUG("exynos drm subdrv probe failed.\n"); -				list_del(&subdrv->list); -				continue; -			} -		} -	} - -	return 0; -} - -int exynos_drm_device_subdrv_remove(struct drm_device *dev) -{ -	struct exynos_drm_subdrv *subdrv; - -	if (!dev) { -		WARN(1, "Unexpected drm device unregister!\n"); -		return -EINVAL; -	} - -	list_for_each_entry(subdrv, &exynos_drm_subdrv_list, list) { -		if (subdrv->remove) -			subdrv->remove(dev, subdrv->dev); -	} - -	return 0; -} - -int exynos_drm_subdrv_open(struct drm_device *dev, struct drm_file *file) -{ -	struct exynos_drm_subdrv *subdrv; -	int ret; - -	list_for_each_entry(subdrv, &exynos_drm_subdrv_list, list) { -		if (subdrv->open) { -			ret = subdrv->open(dev, subdrv->dev, file); -			if (ret) -				goto err; -		} -	} - -	return 0; - -err: -	list_for_each_entry_continue_reverse(subdrv, &exynos_drm_subdrv_list, list) { -		if (subdrv->close) -			subdrv->close(dev, subdrv->dev, file); -	} -	return ret; -} - -void exynos_drm_subdrv_close(struct drm_device *dev, struct drm_file *file) -{ -	struct exynos_drm_subdrv *subdrv; - -	list_for_each_entry(subdrv, &exynos_drm_subdrv_list, list) { -		if (subdrv->close) -			subdrv->close(dev, subdrv->dev, file); -	} -} diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.c b/drivers/gpu/drm/exynos/exynos_drm_drv.c index a81b4a5e24a7..b599f74692e5 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_drv.c +++ b/drivers/gpu/drm/exynos/exynos_drm_drv.c @@ -55,8 +55,7 @@ static int exynos_drm_open(struct drm_device *dev, struct drm_file *file)  		return -ENOMEM;  	file->driver_priv = file_priv; - -	ret = exynos_drm_subdrv_open(dev, file); +	ret = g2d_open(dev, file);  	if (ret)  		goto err_file_priv_free; @@ -70,7 +69,7 @@ err_file_priv_free:  static void exynos_drm_postclose(struct drm_device *dev, struct drm_file *file)  { -	exynos_drm_subdrv_close(dev, file); +	g2d_close(dev, file);  	kfree(file->driver_priv);  	file->driver_priv = NULL;  } @@ -147,13 +146,12 @@ static struct drm_driver exynos_drm_driver = {  	.minor	= DRIVER_MINOR,  }; -#ifdef CONFIG_PM_SLEEP  static int exynos_drm_suspend(struct device *dev)  {  	struct drm_device *drm_dev = dev_get_drvdata(dev);  	struct exynos_drm_private *private; -	if (pm_runtime_suspended(dev) || !drm_dev) +	if (!drm_dev)  		return 0;  	private = drm_dev->dev_private; @@ -170,25 +168,23 @@ static int exynos_drm_suspend(struct device *dev)  	return 0;  } -static int exynos_drm_resume(struct device *dev) +static void exynos_drm_resume(struct device *dev)  {  	struct drm_device *drm_dev = dev_get_drvdata(dev);  	struct exynos_drm_private *private; -	if (pm_runtime_suspended(dev) || !drm_dev) -		return 0; +	if (!drm_dev) +		return;  	private = drm_dev->dev_private;  	drm_atomic_helper_resume(drm_dev, private->suspend_state);  	exynos_drm_fbdev_resume(drm_dev);  	drm_kms_helper_poll_enable(drm_dev); - -	return 0;  } -#endif  static const struct dev_pm_ops exynos_drm_pm_ops = { -	SET_SYSTEM_SLEEP_PM_OPS(exynos_drm_suspend, exynos_drm_resume) +	.prepare = exynos_drm_suspend, +	.complete = exynos_drm_resume,  };  /* forward declaration */ @@ -240,6 +236,7 @@ static struct exynos_drm_driver_info exynos_drm_drivers[] = {  		DRM_COMPONENT_DRIVER | DRM_VIRTUAL_DEVICE  	}, {  		DRV_PTR(g2d_driver, CONFIG_DRM_EXYNOS_G2D), +		DRM_COMPONENT_DRIVER  	}, {  		DRV_PTR(fimc_driver, CONFIG_DRM_EXYNOS_FIMC),  		DRM_COMPONENT_DRIVER | DRM_FIMC_DEVICE, @@ -376,11 +373,6 @@ static int exynos_drm_bind(struct device *dev)  	if (ret)  		goto err_unbind_all; -	/* Probe non kms sub drivers and virtual display driver. */ -	ret = exynos_drm_device_subdrv_probe(drm); -	if (ret) -		goto err_unbind_all; -  	drm_mode_config_reset(drm);  	/* @@ -411,7 +403,6 @@ err_cleanup_fbdev:  	exynos_drm_fbdev_fini(drm);  err_cleanup_poll:  	drm_kms_helper_poll_fini(drm); -	exynos_drm_device_subdrv_remove(drm);  err_unbind_all:  	component_unbind_all(drm->dev, drm);  err_mode_config_cleanup: @@ -420,7 +411,7 @@ err_mode_config_cleanup:  err_free_private:  	kfree(private);  err_free_drm: -	drm_dev_unref(drm); +	drm_dev_put(drm);  	return ret;  } @@ -431,8 +422,6 @@ static void exynos_drm_unbind(struct device *dev)  	drm_dev_unregister(drm); -	exynos_drm_device_subdrv_remove(drm); -  	exynos_drm_fbdev_fini(drm);  	drm_kms_helper_poll_fini(drm); @@ -444,7 +433,7 @@ static void exynos_drm_unbind(struct device *dev)  	drm->dev_private = NULL;  	dev_set_drvdata(dev, NULL); -	drm_dev_unref(drm); +	drm_dev_put(drm);  }  static const struct component_master_ops exynos_drm_ops = { diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.h b/drivers/gpu/drm/exynos/exynos_drm_drv.h index 0f6d079a55c9..c737c4bd2c19 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_drv.h +++ b/drivers/gpu/drm/exynos/exynos_drm_drv.h @@ -179,17 +179,13 @@ static inline void exynos_drm_pipe_clk_enable(struct exynos_drm_crtc *crtc,  		crtc->pipe_clk->enable(crtc->pipe_clk, enable);  } -struct exynos_drm_g2d_private { -	struct device		*dev; +struct drm_exynos_file_private { +	/* for g2d api */  	struct list_head	inuse_cmdlist;  	struct list_head	event_list;  	struct list_head	userptr_list;  }; -struct drm_exynos_file_private { -	struct exynos_drm_g2d_private	*g2d_priv; -}; -  /*   * Exynos drm private structure.   * @@ -201,6 +197,7 @@ struct exynos_drm_private {  	struct drm_fb_helper *fb_helper;  	struct drm_atomic_state *suspend_state; +	struct device *g2d_dev;  	struct device *dma_dev;  	void *mapping; @@ -217,44 +214,6 @@ static inline struct device *to_dma_dev(struct drm_device *dev)  	return priv->dma_dev;  } -/* - * Exynos drm sub driver structure. - * - * @list: sub driver has its own list object to register to exynos drm driver. - * @dev: pointer to device object for subdrv device driver. - * @drm_dev: pointer to drm_device and this pointer would be set - *	when sub driver calls exynos_drm_subdrv_register(). - * @probe: this callback would be called by exynos drm driver after - *     subdrv is registered to it. - * @remove: this callback is used to release resources created - *     by probe callback. - * @open: this would be called with drm device file open. - * @close: this would be called with drm device file close. - */ -struct exynos_drm_subdrv { -	struct list_head list; -	struct device *dev; -	struct drm_device *drm_dev; - -	int (*probe)(struct drm_device *drm_dev, struct device *dev); -	void (*remove)(struct drm_device *drm_dev, struct device *dev); -	int (*open)(struct drm_device *drm_dev, struct device *dev, -			struct drm_file *file); -	void (*close)(struct drm_device *drm_dev, struct device *dev, -			struct drm_file *file); -}; - - /* This function would be called by non kms drivers such as g2d and ipp. */ -int exynos_drm_subdrv_register(struct exynos_drm_subdrv *drm_subdrv); - -/* this function removes subdrv list from exynos drm driver */ -int exynos_drm_subdrv_unregister(struct exynos_drm_subdrv *drm_subdrv); - -int exynos_drm_device_subdrv_probe(struct drm_device *dev); -int exynos_drm_device_subdrv_remove(struct drm_device *dev); -int exynos_drm_subdrv_open(struct drm_device *dev, struct drm_file *file); -void exynos_drm_subdrv_close(struct drm_device *dev, struct drm_file *file); -  #ifdef CONFIG_DRM_EXYNOS_DPI  struct drm_encoder *exynos_dpi_probe(struct device *dev);  int exynos_dpi_remove(struct drm_encoder *encoder); diff --git a/drivers/gpu/drm/exynos/exynos_drm_dsi.c b/drivers/gpu/drm/exynos/exynos_drm_dsi.c index a1ed6146a3b5..781b82c2c579 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_dsi.c +++ b/drivers/gpu/drm/exynos/exynos_drm_dsi.c @@ -1863,6 +1863,8 @@ err_clk:  static const struct dev_pm_ops exynos_dsi_pm_ops = {  	SET_RUNTIME_PM_OPS(exynos_dsi_suspend, exynos_dsi_resume, NULL) +	SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, +				pm_runtime_force_resume)  };  struct platform_driver dsi_driver = { diff --git a/drivers/gpu/drm/exynos/exynos_drm_fb.c b/drivers/gpu/drm/exynos/exynos_drm_fb.c index 7fcc1a7ab1a0..9f52382e19ee 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_fb.c +++ b/drivers/gpu/drm/exynos/exynos_drm_fb.c @@ -101,7 +101,6 @@ exynos_user_fb_create(struct drm_device *dev, struct drm_file *file_priv,  {  	const struct drm_format_info *info = drm_get_format_info(dev, mode_cmd);  	struct exynos_drm_gem *exynos_gem[MAX_FB_BUFFER]; -	struct drm_gem_object *obj;  	struct drm_framebuffer *fb;  	int i;  	int ret; @@ -112,15 +111,14 @@ exynos_user_fb_create(struct drm_device *dev, struct drm_file *file_priv,  		unsigned long size = height * mode_cmd->pitches[i] +  				     mode_cmd->offsets[i]; -		obj = drm_gem_object_lookup(file_priv, mode_cmd->handles[i]); -		if (!obj) { +		exynos_gem[i] = exynos_drm_gem_get(file_priv, +						   mode_cmd->handles[i]); +		if (!exynos_gem[i]) {  			DRM_ERROR("failed to lookup gem object\n");  			ret = -ENOENT;  			goto err;  		} -		exynos_gem[i] = to_exynos_gem(obj); -  		if (size > exynos_gem[i]->size) {  			i++;  			ret = -EINVAL; @@ -138,7 +136,7 @@ exynos_user_fb_create(struct drm_device *dev, struct drm_file *file_priv,  err:  	while (i--) -		drm_gem_object_unreference_unlocked(&exynos_gem[i]->base); +		exynos_drm_gem_put(exynos_gem[i]);  	return ERR_PTR(ret);  } diff --git a/drivers/gpu/drm/exynos/exynos_drm_fimc.c b/drivers/gpu/drm/exynos/exynos_drm_fimc.c index 6127ef25acd6..e8d0670bb5f8 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_fimc.c +++ b/drivers/gpu/drm/exynos/exynos_drm_fimc.c @@ -470,17 +470,18 @@ static void fimc_src_set_transf(struct fimc_context *ctx, unsigned int rotation)  static void fimc_set_window(struct fimc_context *ctx,  			    struct exynos_drm_ipp_buffer *buf)  { +	unsigned int real_width = buf->buf.pitch[0] / buf->format->cpp[0];  	u32 cfg, h1, h2, v1, v2;  	/* cropped image */  	h1 = buf->rect.x; -	h2 = buf->buf.width - buf->rect.w - buf->rect.x; +	h2 = real_width - buf->rect.w - buf->rect.x;  	v1 = buf->rect.y;  	v2 = buf->buf.height - buf->rect.h - buf->rect.y;  	DRM_DEBUG_KMS("x[%d]y[%d]w[%d]h[%d]hsize[%d]vsize[%d]\n",  		buf->rect.x, buf->rect.y, buf->rect.w, buf->rect.h, -		buf->buf.width, buf->buf.height); +		real_width, buf->buf.height);  	DRM_DEBUG_KMS("h1[%d]h2[%d]v1[%d]v2[%d]\n", h1, h2, v1, v2);  	/* @@ -503,12 +504,13 @@ static void fimc_set_window(struct fimc_context *ctx,  static void fimc_src_set_size(struct fimc_context *ctx,  			      struct exynos_drm_ipp_buffer *buf)  { +	unsigned int real_width = buf->buf.pitch[0] / buf->format->cpp[0];  	u32 cfg; -	DRM_DEBUG_KMS("hsize[%d]vsize[%d]\n", buf->buf.width, buf->buf.height); +	DRM_DEBUG_KMS("hsize[%d]vsize[%d]\n", real_width, buf->buf.height);  	/* original size */ -	cfg = (EXYNOS_ORGISIZE_HORIZONTAL(buf->buf.width) | +	cfg = (EXYNOS_ORGISIZE_HORIZONTAL(real_width) |  		EXYNOS_ORGISIZE_VERTICAL(buf->buf.height));  	fimc_write(ctx, cfg, EXYNOS_ORGISIZE); @@ -529,7 +531,7 @@ static void fimc_src_set_size(struct fimc_context *ctx,  	 * for now, we support only ITU601 8 bit mode  	 */  	cfg = (EXYNOS_CISRCFMT_ITU601_8BIT | -		EXYNOS_CISRCFMT_SOURCEHSIZE(buf->buf.width) | +		EXYNOS_CISRCFMT_SOURCEHSIZE(real_width) |  		EXYNOS_CISRCFMT_SOURCEVSIZE(buf->buf.height));  	fimc_write(ctx, cfg, EXYNOS_CISRCFMT); @@ -842,12 +844,13 @@ static void fimc_set_scaler(struct fimc_context *ctx, struct fimc_scaler *sc)  static void fimc_dst_set_size(struct fimc_context *ctx,  			     struct exynos_drm_ipp_buffer *buf)  { +	unsigned int real_width = buf->buf.pitch[0] / buf->format->cpp[0];  	u32 cfg, cfg_ext; -	DRM_DEBUG_KMS("hsize[%d]vsize[%d]\n", buf->buf.width, buf->buf.height); +	DRM_DEBUG_KMS("hsize[%d]vsize[%d]\n", real_width, buf->buf.height);  	/* original size */ -	cfg = (EXYNOS_ORGOSIZE_HORIZONTAL(buf->buf.width) | +	cfg = (EXYNOS_ORGOSIZE_HORIZONTAL(real_width) |  		EXYNOS_ORGOSIZE_VERTICAL(buf->buf.height));  	fimc_write(ctx, cfg, EXYNOS_ORGOSIZE); diff --git a/drivers/gpu/drm/exynos/exynos_drm_fimd.c b/drivers/gpu/drm/exynos/exynos_drm_fimd.c index 01b1570d0c3a..b7f56935a46b 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_fimd.c +++ b/drivers/gpu/drm/exynos/exynos_drm_fimd.c @@ -1192,6 +1192,8 @@ static int exynos_fimd_resume(struct device *dev)  static const struct dev_pm_ops exynos_fimd_pm_ops = {  	SET_RUNTIME_PM_OPS(exynos_fimd_suspend, exynos_fimd_resume, NULL) +	SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, +				pm_runtime_force_resume)  };  struct platform_driver fimd_driver = { diff --git a/drivers/gpu/drm/exynos/exynos_drm_g2d.c b/drivers/gpu/drm/exynos/exynos_drm_g2d.c index f68ef1b3a28c..f2481a2014bb 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_g2d.c +++ b/drivers/gpu/drm/exynos/exynos_drm_g2d.c @@ -9,6 +9,7 @@  #include <linux/kernel.h>  #include <linux/clk.h> +#include <linux/component.h>  #include <linux/err.h>  #include <linux/interrupt.h>  #include <linux/io.h> @@ -190,7 +191,7 @@ struct g2d_buf_desc {  struct g2d_buf_info {  	unsigned int		map_nr;  	enum g2d_reg_type	reg_types[MAX_REG_TYPE_NR]; -	unsigned long		handles[MAX_REG_TYPE_NR]; +	void			*obj[MAX_REG_TYPE_NR];  	unsigned int		types[MAX_REG_TYPE_NR];  	struct g2d_buf_desc	descs[MAX_REG_TYPE_NR];  }; @@ -237,7 +238,7 @@ struct g2d_data {  	int				irq;  	struct workqueue_struct		*g2d_workq;  	struct work_struct		runqueue_work; -	struct exynos_drm_subdrv	subdrv; +	struct drm_device		*drm_dev;  	unsigned long			flags;  	/* cmdlist */ @@ -268,14 +269,13 @@ static int g2d_init_cmdlist(struct g2d_data *g2d)  {  	struct device *dev = g2d->dev;  	struct g2d_cmdlist_node *node = g2d->cmdlist_node; -	struct exynos_drm_subdrv *subdrv = &g2d->subdrv;  	int nr;  	int ret;  	struct g2d_buf_info *buf_info;  	g2d->cmdlist_dma_attrs = DMA_ATTR_WRITE_COMBINE; -	g2d->cmdlist_pool_virt = dma_alloc_attrs(to_dma_dev(subdrv->drm_dev), +	g2d->cmdlist_pool_virt = dma_alloc_attrs(to_dma_dev(g2d->drm_dev),  						G2D_CMDLIST_POOL_SIZE,  						&g2d->cmdlist_pool, GFP_KERNEL,  						g2d->cmdlist_dma_attrs); @@ -308,7 +308,7 @@ static int g2d_init_cmdlist(struct g2d_data *g2d)  	return 0;  err: -	dma_free_attrs(to_dma_dev(subdrv->drm_dev), G2D_CMDLIST_POOL_SIZE, +	dma_free_attrs(to_dma_dev(g2d->drm_dev), G2D_CMDLIST_POOL_SIZE,  			g2d->cmdlist_pool_virt,  			g2d->cmdlist_pool, g2d->cmdlist_dma_attrs);  	return ret; @@ -316,12 +316,10 @@ err:  static void g2d_fini_cmdlist(struct g2d_data *g2d)  { -	struct exynos_drm_subdrv *subdrv = &g2d->subdrv; -  	kfree(g2d->cmdlist_node);  	if (g2d->cmdlist_pool_virt && g2d->cmdlist_pool) { -		dma_free_attrs(to_dma_dev(subdrv->drm_dev), +		dma_free_attrs(to_dma_dev(g2d->drm_dev),  				G2D_CMDLIST_POOL_SIZE,  				g2d->cmdlist_pool_virt,  				g2d->cmdlist_pool, g2d->cmdlist_dma_attrs); @@ -355,32 +353,31 @@ static void g2d_put_cmdlist(struct g2d_data *g2d, struct g2d_cmdlist_node *node)  	mutex_unlock(&g2d->cmdlist_mutex);  } -static void g2d_add_cmdlist_to_inuse(struct exynos_drm_g2d_private *g2d_priv, +static void g2d_add_cmdlist_to_inuse(struct drm_exynos_file_private *file_priv,  				     struct g2d_cmdlist_node *node)  {  	struct g2d_cmdlist_node *lnode; -	if (list_empty(&g2d_priv->inuse_cmdlist)) +	if (list_empty(&file_priv->inuse_cmdlist))  		goto add_to_list;  	/* this links to base address of new cmdlist */ -	lnode = list_entry(g2d_priv->inuse_cmdlist.prev, +	lnode = list_entry(file_priv->inuse_cmdlist.prev,  				struct g2d_cmdlist_node, list);  	lnode->cmdlist->data[lnode->cmdlist->last] = node->dma_addr;  add_to_list: -	list_add_tail(&node->list, &g2d_priv->inuse_cmdlist); +	list_add_tail(&node->list, &file_priv->inuse_cmdlist);  	if (node->event) -		list_add_tail(&node->event->base.link, &g2d_priv->event_list); +		list_add_tail(&node->event->base.link, &file_priv->event_list);  } -static void g2d_userptr_put_dma_addr(struct drm_device *drm_dev, -					unsigned long obj, +static void g2d_userptr_put_dma_addr(struct g2d_data *g2d, +					void *obj,  					bool force)  { -	struct g2d_cmdlist_userptr *g2d_userptr = -					(struct g2d_cmdlist_userptr *)obj; +	struct g2d_cmdlist_userptr *g2d_userptr = obj;  	struct page **pages;  	if (!obj) @@ -398,7 +395,7 @@ static void g2d_userptr_put_dma_addr(struct drm_device *drm_dev,  		return;  out: -	dma_unmap_sg(to_dma_dev(drm_dev), g2d_userptr->sgt->sgl, +	dma_unmap_sg(to_dma_dev(g2d->drm_dev), g2d_userptr->sgt->sgl,  			g2d_userptr->sgt->nents, DMA_BIDIRECTIONAL);  	pages = frame_vector_pages(g2d_userptr->vec); @@ -419,16 +416,14 @@ out:  	kfree(g2d_userptr);  } -static dma_addr_t *g2d_userptr_get_dma_addr(struct drm_device *drm_dev, +static dma_addr_t *g2d_userptr_get_dma_addr(struct g2d_data *g2d,  					unsigned long userptr,  					unsigned long size,  					struct drm_file *filp, -					unsigned long *obj) +					void **obj)  {  	struct drm_exynos_file_private *file_priv = filp->driver_priv; -	struct exynos_drm_g2d_private *g2d_priv = file_priv->g2d_priv;  	struct g2d_cmdlist_userptr *g2d_userptr; -	struct g2d_data *g2d;  	struct sg_table	*sgt;  	unsigned long start, end;  	unsigned int npages, offset; @@ -439,10 +434,8 @@ static dma_addr_t *g2d_userptr_get_dma_addr(struct drm_device *drm_dev,  		return ERR_PTR(-EINVAL);  	} -	g2d = dev_get_drvdata(g2d_priv->dev); -  	/* check if userptr already exists in userptr_list. */ -	list_for_each_entry(g2d_userptr, &g2d_priv->userptr_list, list) { +	list_for_each_entry(g2d_userptr, &file_priv->userptr_list, list) {  		if (g2d_userptr->userptr == userptr) {  			/*  			 * also check size because there could be same address @@ -450,7 +443,7 @@ static dma_addr_t *g2d_userptr_get_dma_addr(struct drm_device *drm_dev,  			 */  			if (g2d_userptr->size == size) {  				atomic_inc(&g2d_userptr->refcount); -				*obj = (unsigned long)g2d_userptr; +				*obj = g2d_userptr;  				return &g2d_userptr->dma_addr;  			} @@ -517,7 +510,7 @@ static dma_addr_t *g2d_userptr_get_dma_addr(struct drm_device *drm_dev,  	g2d_userptr->sgt = sgt; -	if (!dma_map_sg(to_dma_dev(drm_dev), sgt->sgl, sgt->nents, +	if (!dma_map_sg(to_dma_dev(g2d->drm_dev), sgt->sgl, sgt->nents,  				DMA_BIDIRECTIONAL)) {  		DRM_ERROR("failed to map sgt with dma region.\n");  		ret = -ENOMEM; @@ -527,14 +520,14 @@ static dma_addr_t *g2d_userptr_get_dma_addr(struct drm_device *drm_dev,  	g2d_userptr->dma_addr = sgt->sgl[0].dma_address;  	g2d_userptr->userptr = userptr; -	list_add_tail(&g2d_userptr->list, &g2d_priv->userptr_list); +	list_add_tail(&g2d_userptr->list, &file_priv->userptr_list);  	if (g2d->current_pool + (npages << PAGE_SHIFT) < g2d->max_pool) {  		g2d->current_pool += npages << PAGE_SHIFT;  		g2d_userptr->in_pool = true;  	} -	*obj = (unsigned long)g2d_userptr; +	*obj = g2d_userptr;  	return &g2d_userptr->dma_addr; @@ -556,19 +549,14 @@ err_free:  	return ERR_PTR(ret);  } -static void g2d_userptr_free_all(struct drm_device *drm_dev, -					struct g2d_data *g2d, -					struct drm_file *filp) +static void g2d_userptr_free_all(struct g2d_data *g2d, struct drm_file *filp)  {  	struct drm_exynos_file_private *file_priv = filp->driver_priv; -	struct exynos_drm_g2d_private *g2d_priv = file_priv->g2d_priv;  	struct g2d_cmdlist_userptr *g2d_userptr, *n; -	list_for_each_entry_safe(g2d_userptr, n, &g2d_priv->userptr_list, list) +	list_for_each_entry_safe(g2d_userptr, n, &file_priv->userptr_list, list)  		if (g2d_userptr->in_pool) -			g2d_userptr_put_dma_addr(drm_dev, -						(unsigned long)g2d_userptr, -						true); +			g2d_userptr_put_dma_addr(g2d, g2d_userptr, true);  	g2d->current_pool = 0;  } @@ -723,26 +711,23 @@ static int g2d_map_cmdlist_gem(struct g2d_data *g2d,  		buf_desc = &buf_info->descs[reg_type];  		if (buf_info->types[reg_type] == BUF_TYPE_GEM) { -			unsigned long size; +			struct exynos_drm_gem *exynos_gem; -			size = exynos_drm_gem_get_size(drm_dev, handle, file); -			if (!size) { +			exynos_gem = exynos_drm_gem_get(file, handle); +			if (!exynos_gem) {  				ret = -EFAULT;  				goto err;  			} -			if (!g2d_check_buf_desc_is_valid(buf_desc, reg_type, -									size)) { +			if (!g2d_check_buf_desc_is_valid(buf_desc, +							 reg_type, exynos_gem->size)) { +				exynos_drm_gem_put(exynos_gem);  				ret = -EFAULT;  				goto err;  			} -			addr = exynos_drm_gem_get_dma_addr(drm_dev, handle, -								file); -			if (IS_ERR(addr)) { -				ret = -EFAULT; -				goto err; -			} +			addr = &exynos_gem->dma_addr; +			buf_info->obj[reg_type] = exynos_gem;  		} else {  			struct drm_exynos_g2d_userptr g2d_userptr; @@ -758,11 +743,11 @@ static int g2d_map_cmdlist_gem(struct g2d_data *g2d,  				goto err;  			} -			addr = g2d_userptr_get_dma_addr(drm_dev, +			addr = g2d_userptr_get_dma_addr(g2d,  							g2d_userptr.userptr,  							g2d_userptr.size,  							file, -							&handle); +							&buf_info->obj[reg_type]);  			if (IS_ERR(addr)) {  				ret = -EFAULT;  				goto err; @@ -771,7 +756,6 @@ static int g2d_map_cmdlist_gem(struct g2d_data *g2d,  		cmdlist->data[reg_pos + 1] = *addr;  		buf_info->reg_types[i] = reg_type; -		buf_info->handles[reg_type] = handle;  	}  	return 0; @@ -785,29 +769,26 @@ static void g2d_unmap_cmdlist_gem(struct g2d_data *g2d,  				  struct g2d_cmdlist_node *node,  				  struct drm_file *filp)  { -	struct exynos_drm_subdrv *subdrv = &g2d->subdrv;  	struct g2d_buf_info *buf_info = &node->buf_info;  	int i;  	for (i = 0; i < buf_info->map_nr; i++) {  		struct g2d_buf_desc *buf_desc;  		enum g2d_reg_type reg_type; -		unsigned long handle; +		void *obj;  		reg_type = buf_info->reg_types[i];  		buf_desc = &buf_info->descs[reg_type]; -		handle = buf_info->handles[reg_type]; +		obj = buf_info->obj[reg_type];  		if (buf_info->types[reg_type] == BUF_TYPE_GEM) -			exynos_drm_gem_put_dma_addr(subdrv->drm_dev, handle, -							filp); +			exynos_drm_gem_put(obj);  		else -			g2d_userptr_put_dma_addr(subdrv->drm_dev, handle, -							false); +			g2d_userptr_put_dma_addr(g2d, obj, false);  		buf_info->reg_types[i] = REG_TYPE_NONE; -		buf_info->handles[reg_type] = 0; +		buf_info->obj[reg_type] = NULL;  		buf_info->types[reg_type] = 0;  		memset(buf_desc, 0x00, sizeof(*buf_desc));  	} @@ -922,7 +903,7 @@ static void g2d_runqueue_worker(struct work_struct *work)  static void g2d_finish_event(struct g2d_data *g2d, u32 cmdlist_no)  { -	struct drm_device *drm_dev = g2d->subdrv.drm_dev; +	struct drm_device *drm_dev = g2d->drm_dev;  	struct g2d_runqueue_node *runqueue_node = g2d->runqueue_node;  	struct drm_exynos_pending_g2d_event *e;  	struct timespec64 now; @@ -1031,7 +1012,7 @@ out:  	mutex_unlock(&g2d->runqueue_mutex);  } -static int g2d_check_reg_offset(struct device *dev, +static int g2d_check_reg_offset(struct g2d_data *g2d,  				struct g2d_cmdlist_node *node,  				int nr, bool for_addr)  { @@ -1131,7 +1112,7 @@ static int g2d_check_reg_offset(struct device *dev,  	return 0;  err: -	dev_err(dev, "Bad register offset: 0x%lx\n", cmdlist->data[index]); +	dev_err(g2d->dev, "Bad register offset: 0x%lx\n", cmdlist->data[index]);  	return -EINVAL;  } @@ -1139,23 +1120,8 @@ err:  int exynos_g2d_get_ver_ioctl(struct drm_device *drm_dev, void *data,  			     struct drm_file *file)  { -	struct drm_exynos_file_private *file_priv = file->driver_priv; -	struct exynos_drm_g2d_private *g2d_priv = file_priv->g2d_priv; -	struct device *dev; -	struct g2d_data *g2d;  	struct drm_exynos_g2d_get_ver *ver = data; -	if (!g2d_priv) -		return -ENODEV; - -	dev = g2d_priv->dev; -	if (!dev) -		return -ENODEV; - -	g2d = dev_get_drvdata(dev); -	if (!g2d) -		return -EFAULT; -  	ver->major = G2D_HW_MAJOR_VER;  	ver->minor = G2D_HW_MINOR_VER; @@ -1166,9 +1132,8 @@ int exynos_g2d_set_cmdlist_ioctl(struct drm_device *drm_dev, void *data,  				 struct drm_file *file)  {  	struct drm_exynos_file_private *file_priv = file->driver_priv; -	struct exynos_drm_g2d_private *g2d_priv = file_priv->g2d_priv; -	struct device *dev; -	struct g2d_data *g2d; +	struct exynos_drm_private *priv = drm_dev->dev_private; +	struct g2d_data *g2d = dev_get_drvdata(priv->g2d_dev);  	struct drm_exynos_g2d_set_cmdlist *req = data;  	struct drm_exynos_g2d_cmd *cmd;  	struct drm_exynos_pending_g2d_event *e; @@ -1177,17 +1142,6 @@ int exynos_g2d_set_cmdlist_ioctl(struct drm_device *drm_dev, void *data,  	int size;  	int ret; -	if (!g2d_priv) -		return -ENODEV; - -	dev = g2d_priv->dev; -	if (!dev) -		return -ENODEV; - -	g2d = dev_get_drvdata(dev); -	if (!g2d) -		return -EFAULT; -  	node = g2d_get_cmdlist(g2d);  	if (!node)  		return -ENOMEM; @@ -1199,7 +1153,7 @@ int exynos_g2d_set_cmdlist_ioctl(struct drm_device *drm_dev, void *data,  	 */  	if (req->cmd_nr > G2D_CMDLIST_DATA_NUM ||  	    req->cmd_buf_nr > G2D_CMDLIST_DATA_NUM) { -		dev_err(dev, "number of submitted G2D commands exceeds limit\n"); +		dev_err(g2d->dev, "number of submitted G2D commands exceeds limit\n");  		return -EINVAL;  	} @@ -1267,7 +1221,7 @@ int exynos_g2d_set_cmdlist_ioctl(struct drm_device *drm_dev, void *data,  	 */  	size = cmdlist->last + req->cmd_nr * 2 + req->cmd_buf_nr * 2 + 2;  	if (size > G2D_CMDLIST_DATA_NUM) { -		dev_err(dev, "cmdlist size is too big\n"); +		dev_err(g2d->dev, "cmdlist size is too big\n");  		ret = -EINVAL;  		goto err_free_event;  	} @@ -1282,7 +1236,7 @@ int exynos_g2d_set_cmdlist_ioctl(struct drm_device *drm_dev, void *data,  	}  	cmdlist->last += req->cmd_nr * 2; -	ret = g2d_check_reg_offset(dev, node, req->cmd_nr, false); +	ret = g2d_check_reg_offset(g2d, node, req->cmd_nr, false);  	if (ret < 0)  		goto err_free_event; @@ -1301,7 +1255,7 @@ int exynos_g2d_set_cmdlist_ioctl(struct drm_device *drm_dev, void *data,  		}  		cmdlist->last += req->cmd_buf_nr * 2; -		ret = g2d_check_reg_offset(dev, node, req->cmd_buf_nr, true); +		ret = g2d_check_reg_offset(g2d, node, req->cmd_buf_nr, true);  		if (ret < 0)  			goto err_free_event; @@ -1319,7 +1273,7 @@ int exynos_g2d_set_cmdlist_ioctl(struct drm_device *drm_dev, void *data,  	/* tail */  	cmdlist->data[cmdlist->last] = 0; -	g2d_add_cmdlist_to_inuse(g2d_priv, node); +	g2d_add_cmdlist_to_inuse(file_priv, node);  	return 0; @@ -1337,25 +1291,13 @@ int exynos_g2d_exec_ioctl(struct drm_device *drm_dev, void *data,  			  struct drm_file *file)  {  	struct drm_exynos_file_private *file_priv = file->driver_priv; -	struct exynos_drm_g2d_private *g2d_priv = file_priv->g2d_priv; -	struct device *dev; -	struct g2d_data *g2d; +	struct exynos_drm_private *priv = drm_dev->dev_private; +	struct g2d_data *g2d = dev_get_drvdata(priv->g2d_dev);  	struct drm_exynos_g2d_exec *req = data;  	struct g2d_runqueue_node *runqueue_node;  	struct list_head *run_cmdlist;  	struct list_head *event_list; -	if (!g2d_priv) -		return -ENODEV; - -	dev = g2d_priv->dev; -	if (!dev) -		return -ENODEV; - -	g2d = dev_get_drvdata(dev); -	if (!g2d) -		return -EFAULT; -  	runqueue_node = kmem_cache_alloc(g2d->runqueue_slab, GFP_KERNEL);  	if (!runqueue_node)  		return -ENOMEM; @@ -1367,11 +1309,11 @@ int exynos_g2d_exec_ioctl(struct drm_device *drm_dev, void *data,  	init_completion(&runqueue_node->complete);  	runqueue_node->async = req->async; -	list_splice_init(&g2d_priv->inuse_cmdlist, run_cmdlist); -	list_splice_init(&g2d_priv->event_list, event_list); +	list_splice_init(&file_priv->inuse_cmdlist, run_cmdlist); +	list_splice_init(&file_priv->event_list, event_list);  	if (list_empty(run_cmdlist)) { -		dev_err(dev, "there is no inuse cmdlist\n"); +		dev_err(g2d->dev, "there is no inuse cmdlist\n");  		kmem_cache_free(g2d->runqueue_slab, runqueue_node);  		return -EPERM;  	} @@ -1395,71 +1337,28 @@ out:  	return 0;  } -static int g2d_subdrv_probe(struct drm_device *drm_dev, struct device *dev) -{ -	struct g2d_data *g2d; -	int ret; - -	g2d = dev_get_drvdata(dev); -	if (!g2d) -		return -EFAULT; - -	/* allocate dma-aware cmdlist buffer. */ -	ret = g2d_init_cmdlist(g2d); -	if (ret < 0) { -		dev_err(dev, "cmdlist init failed\n"); -		return ret; -	} - -	ret = drm_iommu_attach_device(drm_dev, dev); -	if (ret < 0) { -		dev_err(dev, "failed to enable iommu.\n"); -		g2d_fini_cmdlist(g2d); -	} - -	return ret; - -} - -static void g2d_subdrv_remove(struct drm_device *drm_dev, struct device *dev) -{ -	drm_iommu_detach_device(drm_dev, dev); -} - -static int g2d_open(struct drm_device *drm_dev, struct device *dev, -			struct drm_file *file) +int g2d_open(struct drm_device *drm_dev, struct drm_file *file)  {  	struct drm_exynos_file_private *file_priv = file->driver_priv; -	struct exynos_drm_g2d_private *g2d_priv; - -	g2d_priv = kzalloc(sizeof(*g2d_priv), GFP_KERNEL); -	if (!g2d_priv) -		return -ENOMEM; -	g2d_priv->dev = dev; -	file_priv->g2d_priv = g2d_priv; - -	INIT_LIST_HEAD(&g2d_priv->inuse_cmdlist); -	INIT_LIST_HEAD(&g2d_priv->event_list); -	INIT_LIST_HEAD(&g2d_priv->userptr_list); +	INIT_LIST_HEAD(&file_priv->inuse_cmdlist); +	INIT_LIST_HEAD(&file_priv->event_list); +	INIT_LIST_HEAD(&file_priv->userptr_list);  	return 0;  } -static void g2d_close(struct drm_device *drm_dev, struct device *dev, -			struct drm_file *file) +void g2d_close(struct drm_device *drm_dev, struct drm_file *file)  {  	struct drm_exynos_file_private *file_priv = file->driver_priv; -	struct exynos_drm_g2d_private *g2d_priv = file_priv->g2d_priv; +	struct exynos_drm_private *priv = drm_dev->dev_private;  	struct g2d_data *g2d;  	struct g2d_cmdlist_node *node, *n; -	if (!dev) +	if (!priv->g2d_dev)  		return; -	g2d = dev_get_drvdata(dev); -	if (!g2d) -		return; +	g2d = dev_get_drvdata(priv->g2d_dev);  	/* Remove the runqueue nodes that belong to us. */  	mutex_lock(&g2d->runqueue_mutex); @@ -1480,24 +1379,70 @@ static void g2d_close(struct drm_device *drm_dev, struct device *dev,  	 * Properly unmap these buffers here.  	 */  	mutex_lock(&g2d->cmdlist_mutex); -	list_for_each_entry_safe(node, n, &g2d_priv->inuse_cmdlist, list) { +	list_for_each_entry_safe(node, n, &file_priv->inuse_cmdlist, list) {  		g2d_unmap_cmdlist_gem(g2d, node, file);  		list_move_tail(&node->list, &g2d->free_cmdlist);  	}  	mutex_unlock(&g2d->cmdlist_mutex);  	/* release all g2d_userptr in pool. */ -	g2d_userptr_free_all(drm_dev, g2d, file); +	g2d_userptr_free_all(g2d, file); +} + +static int g2d_bind(struct device *dev, struct device *master, void *data) +{ +	struct g2d_data *g2d = dev_get_drvdata(dev); +	struct drm_device *drm_dev = data; +	struct exynos_drm_private *priv = drm_dev->dev_private; +	int ret; + +	g2d->drm_dev = drm_dev; -	kfree(file_priv->g2d_priv); +	/* allocate dma-aware cmdlist buffer. */ +	ret = g2d_init_cmdlist(g2d); +	if (ret < 0) { +		dev_err(dev, "cmdlist init failed\n"); +		return ret; +	} + +	ret = drm_iommu_attach_device(drm_dev, dev); +	if (ret < 0) { +		dev_err(dev, "failed to enable iommu.\n"); +		g2d_fini_cmdlist(g2d); +		return ret; +	} +	priv->g2d_dev = dev; + +	dev_info(dev, "The Exynos G2D (ver %d.%d) successfully registered.\n", +			G2D_HW_MAJOR_VER, G2D_HW_MINOR_VER); +	return 0; +} + +static void g2d_unbind(struct device *dev, struct device *master, void *data) +{ +	struct g2d_data *g2d = dev_get_drvdata(dev); +	struct drm_device *drm_dev = data; +	struct exynos_drm_private *priv = drm_dev->dev_private; + +	/* Suspend operation and wait for engine idle. */ +	set_bit(G2D_BIT_SUSPEND_RUNQUEUE, &g2d->flags); +	g2d_wait_finish(g2d, NULL); +	priv->g2d_dev = NULL; + +	cancel_work_sync(&g2d->runqueue_work); +	drm_iommu_detach_device(g2d->drm_dev, dev);  } +static const struct component_ops g2d_component_ops = { +	.bind	= g2d_bind, +	.unbind = g2d_unbind, +}; +  static int g2d_probe(struct platform_device *pdev)  {  	struct device *dev = &pdev->dev;  	struct resource *res;  	struct g2d_data *g2d; -	struct exynos_drm_subdrv *subdrv;  	int ret;  	g2d = devm_kzalloc(dev, sizeof(*g2d), GFP_KERNEL); @@ -1564,22 +1509,12 @@ static int g2d_probe(struct platform_device *pdev)  	platform_set_drvdata(pdev, g2d); -	subdrv = &g2d->subdrv; -	subdrv->dev = dev; -	subdrv->probe = g2d_subdrv_probe; -	subdrv->remove = g2d_subdrv_remove; -	subdrv->open = g2d_open; -	subdrv->close = g2d_close; - -	ret = exynos_drm_subdrv_register(subdrv); +	ret = component_add(dev, &g2d_component_ops);  	if (ret < 0) {  		dev_err(dev, "failed to register drm g2d device\n");  		goto err_put_clk;  	} -	dev_info(dev, "The Exynos G2D (ver %d.%d) successfully probed.\n", -			G2D_HW_MAJOR_VER, G2D_HW_MINOR_VER); -  	return 0;  err_put_clk: @@ -1595,12 +1530,7 @@ static int g2d_remove(struct platform_device *pdev)  {  	struct g2d_data *g2d = platform_get_drvdata(pdev); -	/* Suspend operation and wait for engine idle. */ -	set_bit(G2D_BIT_SUSPEND_RUNQUEUE, &g2d->flags); -	g2d_wait_finish(g2d, NULL); - -	cancel_work_sync(&g2d->runqueue_work); -	exynos_drm_subdrv_unregister(&g2d->subdrv); +	component_del(&pdev->dev, &g2d_component_ops);  	/* There should be no locking needed here. */  	g2d_remove_runqueue_nodes(g2d, NULL); diff --git a/drivers/gpu/drm/exynos/exynos_drm_g2d.h b/drivers/gpu/drm/exynos/exynos_drm_g2d.h index 1a9c7ca8c15b..287b2ed8f178 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_g2d.h +++ b/drivers/gpu/drm/exynos/exynos_drm_g2d.h @@ -14,6 +14,9 @@ extern int exynos_g2d_set_cmdlist_ioctl(struct drm_device *dev, void *data,  					struct drm_file *file_priv);  extern int exynos_g2d_exec_ioctl(struct drm_device *dev, void *data,  				 struct drm_file *file_priv); + +extern int g2d_open(struct drm_device *drm_dev, struct drm_file *file); +extern void g2d_close(struct drm_device *drm_dev, struct drm_file *file);  #else  static inline int exynos_g2d_get_ver_ioctl(struct drm_device *dev, void *data,  					   struct drm_file *file_priv) @@ -33,4 +36,12 @@ static inline int exynos_g2d_exec_ioctl(struct drm_device *dev, void *data,  {  	return -ENODEV;  } + +int g2d_open(struct drm_device *drm_dev, struct drm_file *file) +{ +	return 0; +} + +void g2d_close(struct drm_device *drm_dev, struct drm_file *file) +{ }  #endif diff --git a/drivers/gpu/drm/exynos/exynos_drm_gem.c b/drivers/gpu/drm/exynos/exynos_drm_gem.c index 6e1494fa71b4..34ace85feb68 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_gem.c +++ b/drivers/gpu/drm/exynos/exynos_drm_gem.c @@ -143,7 +143,7 @@ static int exynos_drm_gem_handle_create(struct drm_gem_object *obj,  	DRM_DEBUG_KMS("gem handle = 0x%x\n", *handle);  	/* drop reference from allocate - handle holds it now. */ -	drm_gem_object_unreference_unlocked(obj); +	drm_gem_object_put_unlocked(obj);  	return 0;  } @@ -171,26 +171,6 @@ void exynos_drm_gem_destroy(struct exynos_drm_gem *exynos_gem)  	kfree(exynos_gem);  } -unsigned long exynos_drm_gem_get_size(struct drm_device *dev, -						unsigned int gem_handle, -						struct drm_file *file_priv) -{ -	struct exynos_drm_gem *exynos_gem; -	struct drm_gem_object *obj; - -	obj = drm_gem_object_lookup(file_priv, gem_handle); -	if (!obj) { -		DRM_ERROR("failed to lookup gem object.\n"); -		return 0; -	} - -	exynos_gem = to_exynos_gem(obj); - -	drm_gem_object_unreference_unlocked(obj); - -	return exynos_gem->size; -} -  static struct exynos_drm_gem *exynos_drm_gem_init(struct drm_device *dev,  						  unsigned long size)  { @@ -299,43 +279,15 @@ int exynos_drm_gem_map_ioctl(struct drm_device *dev, void *data,  				       &args->offset);  } -dma_addr_t *exynos_drm_gem_get_dma_addr(struct drm_device *dev, -					unsigned int gem_handle, -					struct drm_file *filp) -{ -	struct exynos_drm_gem *exynos_gem; -	struct drm_gem_object *obj; - -	obj = drm_gem_object_lookup(filp, gem_handle); -	if (!obj) { -		DRM_ERROR("failed to lookup gem object.\n"); -		return ERR_PTR(-EINVAL); -	} - -	exynos_gem = to_exynos_gem(obj); - -	return &exynos_gem->dma_addr; -} - -void exynos_drm_gem_put_dma_addr(struct drm_device *dev, -					unsigned int gem_handle, -					struct drm_file *filp) +struct exynos_drm_gem *exynos_drm_gem_get(struct drm_file *filp, +					  unsigned int gem_handle)  {  	struct drm_gem_object *obj;  	obj = drm_gem_object_lookup(filp, gem_handle); -	if (!obj) { -		DRM_ERROR("failed to lookup gem object.\n"); -		return; -	} - -	drm_gem_object_unreference_unlocked(obj); - -	/* -	 * decrease obj->refcount one more time because we has already -	 * increased it at exynos_drm_gem_get_dma_addr(). -	 */ -	drm_gem_object_unreference_unlocked(obj); +	if (!obj) +		return NULL; +	return to_exynos_gem(obj);  }  static int exynos_drm_gem_mmap_buffer(struct exynos_drm_gem *exynos_gem, @@ -383,7 +335,7 @@ int exynos_drm_gem_get_ioctl(struct drm_device *dev, void *data,  	args->flags = exynos_gem->flags;  	args->size = exynos_gem->size; -	drm_gem_object_unreference_unlocked(obj); +	drm_gem_object_put_unlocked(obj);  	return 0;  } diff --git a/drivers/gpu/drm/exynos/exynos_drm_gem.h b/drivers/gpu/drm/exynos/exynos_drm_gem.h index 9057d7f1d6ed..d46a62c30812 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_gem.h +++ b/drivers/gpu/drm/exynos/exynos_drm_gem.h @@ -77,32 +77,26 @@ int exynos_drm_gem_map_ioctl(struct drm_device *dev, void *data,  			     struct drm_file *file_priv);  /* - * get dma address from gem handle and this function could be used for + * get exynos drm object from gem handle, this function could be used for   * other drivers such as 2d/3d acceleration drivers.   * with this function call, gem object reference count would be increased.   */ -dma_addr_t *exynos_drm_gem_get_dma_addr(struct drm_device *dev, -					unsigned int gem_handle, -					struct drm_file *filp); +struct exynos_drm_gem *exynos_drm_gem_get(struct drm_file *filp, +					  unsigned int gem_handle);  /* - * put dma address from gem handle and this function could be used for - * other drivers such as 2d/3d acceleration drivers. - * with this function call, gem object reference count would be decreased. + * put exynos drm object acquired from exynos_drm_gem_get(), + * gem object reference count would be decreased.   */ -void exynos_drm_gem_put_dma_addr(struct drm_device *dev, -					unsigned int gem_handle, -					struct drm_file *filp); +static inline void exynos_drm_gem_put(struct exynos_drm_gem *exynos_gem) +{ +	drm_gem_object_put_unlocked(&exynos_gem->base); +}  /* get buffer information to memory region allocated by gem. */  int exynos_drm_gem_get_ioctl(struct drm_device *dev, void *data,  				      struct drm_file *file_priv); -/* get buffer size to gem handle. */ -unsigned long exynos_drm_gem_get_size(struct drm_device *dev, -						unsigned int gem_handle, -						struct drm_file *file_priv); -  /* free gem object. */  void exynos_drm_gem_free_object(struct drm_gem_object *obj); diff --git a/drivers/gpu/drm/exynos/exynos_drm_gsc.c b/drivers/gpu/drm/exynos/exynos_drm_gsc.c index 35ac66730563..7ba414b52faa 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_gsc.c +++ b/drivers/gpu/drm/exynos/exynos_drm_gsc.c @@ -492,21 +492,25 @@ static void gsc_src_set_fmt(struct gsc_context *ctx, u32 fmt)  			GSC_IN_CHROMA_ORDER_CRCB);  		break;  	case DRM_FORMAT_NV21: +		cfg |= (GSC_IN_CHROMA_ORDER_CRCB | GSC_IN_YUV420_2P); +		break;  	case DRM_FORMAT_NV61: -		cfg |= (GSC_IN_CHROMA_ORDER_CRCB | -			GSC_IN_YUV420_2P); +		cfg |= (GSC_IN_CHROMA_ORDER_CRCB | GSC_IN_YUV422_2P);  		break;  	case DRM_FORMAT_YUV422:  		cfg |= GSC_IN_YUV422_3P;  		break;  	case DRM_FORMAT_YUV420: +		cfg |= (GSC_IN_CHROMA_ORDER_CBCR | GSC_IN_YUV420_3P); +		break;  	case DRM_FORMAT_YVU420: -		cfg |= GSC_IN_YUV420_3P; +		cfg |= (GSC_IN_CHROMA_ORDER_CRCB | GSC_IN_YUV420_3P);  		break;  	case DRM_FORMAT_NV12: +		cfg |= (GSC_IN_CHROMA_ORDER_CBCR | GSC_IN_YUV420_2P); +		break;  	case DRM_FORMAT_NV16: -		cfg |= (GSC_IN_CHROMA_ORDER_CBCR | -			GSC_IN_YUV420_2P); +		cfg |= (GSC_IN_CHROMA_ORDER_CBCR | GSC_IN_YUV422_2P);  		break;  	} @@ -523,30 +527,30 @@ static void gsc_src_set_transf(struct gsc_context *ctx, unsigned int rotation)  	switch (degree) {  	case DRM_MODE_ROTATE_0: -		if (rotation & DRM_MODE_REFLECT_Y) -			cfg |= GSC_IN_ROT_XFLIP;  		if (rotation & DRM_MODE_REFLECT_X) +			cfg |= GSC_IN_ROT_XFLIP; +		if (rotation & DRM_MODE_REFLECT_Y)  			cfg |= GSC_IN_ROT_YFLIP;  		break;  	case DRM_MODE_ROTATE_90:  		cfg |= GSC_IN_ROT_90; -		if (rotation & DRM_MODE_REFLECT_Y) -			cfg |= GSC_IN_ROT_XFLIP;  		if (rotation & DRM_MODE_REFLECT_X) +			cfg |= GSC_IN_ROT_XFLIP; +		if (rotation & DRM_MODE_REFLECT_Y)  			cfg |= GSC_IN_ROT_YFLIP;  		break;  	case DRM_MODE_ROTATE_180:  		cfg |= GSC_IN_ROT_180; -		if (rotation & DRM_MODE_REFLECT_Y) -			cfg &= ~GSC_IN_ROT_XFLIP;  		if (rotation & DRM_MODE_REFLECT_X) +			cfg &= ~GSC_IN_ROT_XFLIP; +		if (rotation & DRM_MODE_REFLECT_Y)  			cfg &= ~GSC_IN_ROT_YFLIP;  		break;  	case DRM_MODE_ROTATE_270:  		cfg |= GSC_IN_ROT_270; -		if (rotation & DRM_MODE_REFLECT_Y) -			cfg &= ~GSC_IN_ROT_XFLIP;  		if (rotation & DRM_MODE_REFLECT_X) +			cfg &= ~GSC_IN_ROT_XFLIP; +		if (rotation & DRM_MODE_REFLECT_Y)  			cfg &= ~GSC_IN_ROT_YFLIP;  		break;  	} @@ -577,7 +581,7 @@ static void gsc_src_set_size(struct gsc_context *ctx,  	cfg &= ~(GSC_SRCIMG_HEIGHT_MASK |  		GSC_SRCIMG_WIDTH_MASK); -	cfg |= (GSC_SRCIMG_WIDTH(buf->buf.width) | +	cfg |= (GSC_SRCIMG_WIDTH(buf->buf.pitch[0] / buf->format->cpp[0]) |  		GSC_SRCIMG_HEIGHT(buf->buf.height));  	gsc_write(cfg, GSC_SRCIMG_SIZE); @@ -672,18 +676,25 @@ static void gsc_dst_set_fmt(struct gsc_context *ctx, u32 fmt)  			GSC_OUT_CHROMA_ORDER_CRCB);  		break;  	case DRM_FORMAT_NV21: -	case DRM_FORMAT_NV61:  		cfg |= (GSC_OUT_CHROMA_ORDER_CRCB | GSC_OUT_YUV420_2P);  		break; +	case DRM_FORMAT_NV61: +		cfg |= (GSC_OUT_CHROMA_ORDER_CRCB | GSC_OUT_YUV422_2P); +		break;  	case DRM_FORMAT_YUV422: +		cfg |= GSC_OUT_YUV422_3P; +		break;  	case DRM_FORMAT_YUV420: +		cfg |= (GSC_OUT_CHROMA_ORDER_CBCR | GSC_OUT_YUV420_3P); +		break;  	case DRM_FORMAT_YVU420: -		cfg |= GSC_OUT_YUV420_3P; +		cfg |= (GSC_OUT_CHROMA_ORDER_CRCB | GSC_OUT_YUV420_3P);  		break;  	case DRM_FORMAT_NV12: +		cfg |= (GSC_OUT_CHROMA_ORDER_CBCR | GSC_OUT_YUV420_2P); +		break;  	case DRM_FORMAT_NV16: -		cfg |= (GSC_OUT_CHROMA_ORDER_CBCR | -			GSC_OUT_YUV420_2P); +		cfg |= (GSC_OUT_CHROMA_ORDER_CBCR | GSC_OUT_YUV422_2P);  		break;  	} @@ -868,7 +879,7 @@ static void gsc_dst_set_size(struct gsc_context *ctx,  	/* original size */  	cfg = gsc_read(GSC_DSTIMG_SIZE);  	cfg &= ~(GSC_DSTIMG_HEIGHT_MASK | GSC_DSTIMG_WIDTH_MASK); -	cfg |= GSC_DSTIMG_WIDTH(buf->buf.width) | +	cfg |= GSC_DSTIMG_WIDTH(buf->buf.pitch[0] / buf->format->cpp[0]) |  	       GSC_DSTIMG_HEIGHT(buf->buf.height);  	gsc_write(cfg, GSC_DSTIMG_SIZE); @@ -1341,7 +1352,7 @@ static const struct drm_exynos_ipp_limit gsc_5420_limits[] = {  };  static const struct drm_exynos_ipp_limit gsc_5433_limits[] = { -	{ IPP_SIZE_LIMIT(BUFFER, .h = { 32, 8191, 2 }, .v = { 16, 8191, 2 }) }, +	{ IPP_SIZE_LIMIT(BUFFER, .h = { 32, 8191, 16 }, .v = { 16, 8191, 2 }) },  	{ IPP_SIZE_LIMIT(AREA, .h = { 16, 4800, 1 }, .v = { 8, 3344, 1 }) },  	{ IPP_SIZE_LIMIT(ROTATED, .h = { 32, 2047 }, .v = { 8, 8191 }) },  	{ IPP_SCALE_LIMIT(.h = { (1 << 16) / 16, (1 << 16) * 8 }, diff --git a/drivers/gpu/drm/exynos/exynos_drm_ipp.c b/drivers/gpu/drm/exynos/exynos_drm_ipp.c index 26374e58c557..23226a0212e8 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_ipp.c +++ b/drivers/gpu/drm/exynos/exynos_drm_ipp.c @@ -345,39 +345,18 @@ static int exynos_drm_ipp_task_setup_buffer(struct exynos_drm_ipp_buffer *buf,  	int ret = 0;  	int i; -	/* basic checks */ -	if (buf->buf.width == 0 || buf->buf.height == 0) -		return -EINVAL; -	buf->format = drm_format_info(buf->buf.fourcc); -	for (i = 0; i < buf->format->num_planes; i++) { -		unsigned int width = (i == 0) ? buf->buf.width : -			     DIV_ROUND_UP(buf->buf.width, buf->format->hsub); - -		if (buf->buf.pitch[i] == 0) -			buf->buf.pitch[i] = width * buf->format->cpp[i]; -		if (buf->buf.pitch[i] < width * buf->format->cpp[i]) -			return -EINVAL; -		if (!buf->buf.gem_id[i]) -			return -ENOENT; -	} - -	/* pitch for additional planes must match */ -	if (buf->format->num_planes > 2 && -	    buf->buf.pitch[1] != buf->buf.pitch[2]) -		return -EINVAL; -  	/* get GEM buffers and check their size */  	for (i = 0; i < buf->format->num_planes; i++) {  		unsigned int height = (i == 0) ? buf->buf.height :  			     DIV_ROUND_UP(buf->buf.height, buf->format->vsub);  		unsigned long size = height * buf->buf.pitch[i]; -		struct drm_gem_object *obj = drm_gem_object_lookup(filp, +		struct exynos_drm_gem *gem = exynos_drm_gem_get(filp,  							    buf->buf.gem_id[i]); -		if (!obj) { +		if (!gem) {  			ret = -ENOENT;  			goto gem_free;  		} -		buf->exynos_gem[i] = to_exynos_gem(obj); +		buf->exynos_gem[i] = gem;  		if (size + buf->buf.offset[i] > buf->exynos_gem[i]->size) {  			i++; @@ -391,7 +370,7 @@ static int exynos_drm_ipp_task_setup_buffer(struct exynos_drm_ipp_buffer *buf,  	return 0;  gem_free:  	while (i--) { -		drm_gem_object_put_unlocked(&buf->exynos_gem[i]->base); +		exynos_drm_gem_put(buf->exynos_gem[i]);  		buf->exynos_gem[i] = NULL;  	}  	return ret; @@ -404,7 +383,7 @@ static void exynos_drm_ipp_task_release_buf(struct exynos_drm_ipp_buffer *buf)  	if (!buf->exynos_gem[0])  		return;  	for (i = 0; i < buf->format->num_planes; i++) -		drm_gem_object_put_unlocked(&buf->exynos_gem[i]->base); +		exynos_drm_gem_put(buf->exynos_gem[i]);  }  static void exynos_drm_ipp_task_free(struct exynos_drm_ipp *ipp, @@ -428,7 +407,7 @@ enum drm_ipp_size_id {  	IPP_LIMIT_BUFFER, IPP_LIMIT_AREA, IPP_LIMIT_ROTATED, IPP_LIMIT_MAX  }; -static const enum drm_ipp_size_id limit_id_fallback[IPP_LIMIT_MAX][4] = { +static const enum drm_exynos_ipp_limit_type limit_id_fallback[IPP_LIMIT_MAX][4] = {  	[IPP_LIMIT_BUFFER]  = { DRM_EXYNOS_IPP_LIMIT_SIZE_BUFFER },  	[IPP_LIMIT_AREA]    = { DRM_EXYNOS_IPP_LIMIT_SIZE_AREA,  				DRM_EXYNOS_IPP_LIMIT_SIZE_BUFFER }, @@ -495,12 +474,13 @@ static int exynos_drm_ipp_check_size_limits(struct exynos_drm_ipp_buffer *buf,  	enum drm_ipp_size_id id = rotate ? IPP_LIMIT_ROTATED : IPP_LIMIT_AREA;  	struct drm_ipp_limit l;  	struct drm_exynos_ipp_limit_val *lh = &l.h, *lv = &l.v; +	int real_width = buf->buf.pitch[0] / buf->format->cpp[0];  	if (!limits)  		return 0;  	__get_size_limit(limits, num_limits, IPP_LIMIT_BUFFER, &l); -	if (!__size_limit_check(buf->buf.width, &l.h) || +	if (!__size_limit_check(real_width, &l.h) ||  	    !__size_limit_check(buf->buf.height, &l.v))  		return -EINVAL; @@ -560,10 +540,62 @@ static int exynos_drm_ipp_check_scale_limits(  	return 0;  } +static int exynos_drm_ipp_check_format(struct exynos_drm_ipp_task *task, +				       struct exynos_drm_ipp_buffer *buf, +				       struct exynos_drm_ipp_buffer *src, +				       struct exynos_drm_ipp_buffer *dst, +				       bool rotate, bool swap) +{ +	const struct exynos_drm_ipp_formats *fmt; +	int ret, i; + +	fmt = __ipp_format_get(task->ipp, buf->buf.fourcc, buf->buf.modifier, +			       buf == src ? DRM_EXYNOS_IPP_FORMAT_SOURCE : +					    DRM_EXYNOS_IPP_FORMAT_DESTINATION); +	if (!fmt) { +		DRM_DEBUG_DRIVER("Task %pK: %s format not supported\n", task, +				 buf == src ? "src" : "dst"); +		return -EINVAL; +	} + +	/* basic checks */ +	if (buf->buf.width == 0 || buf->buf.height == 0) +		return -EINVAL; + +	buf->format = drm_format_info(buf->buf.fourcc); +	for (i = 0; i < buf->format->num_planes; i++) { +		unsigned int width = (i == 0) ? buf->buf.width : +			     DIV_ROUND_UP(buf->buf.width, buf->format->hsub); + +		if (buf->buf.pitch[i] == 0) +			buf->buf.pitch[i] = width * buf->format->cpp[i]; +		if (buf->buf.pitch[i] < width * buf->format->cpp[i]) +			return -EINVAL; +		if (!buf->buf.gem_id[i]) +			return -ENOENT; +	} + +	/* pitch for additional planes must match */ +	if (buf->format->num_planes > 2 && +	    buf->buf.pitch[1] != buf->buf.pitch[2]) +		return -EINVAL; + +	/* check driver limits */ +	ret = exynos_drm_ipp_check_size_limits(buf, fmt->limits, +					       fmt->num_limits, +					       rotate, +					       buf == dst ? swap : false); +	if (ret) +		return ret; +	ret = exynos_drm_ipp_check_scale_limits(&src->rect, &dst->rect, +						fmt->limits, +						fmt->num_limits, swap); +	return ret; +} +  static int exynos_drm_ipp_task_check(struct exynos_drm_ipp_task *task)  {  	struct exynos_drm_ipp *ipp = task->ipp; -	const struct exynos_drm_ipp_formats *src_fmt, *dst_fmt;  	struct exynos_drm_ipp_buffer *src = &task->src, *dst = &task->dst;  	unsigned int rotation = task->transform.rotation;  	int ret = 0; @@ -607,37 +639,11 @@ static int exynos_drm_ipp_task_check(struct exynos_drm_ipp_task *task)  		return -EINVAL;  	} -	src_fmt = __ipp_format_get(ipp, src->buf.fourcc, src->buf.modifier, -				   DRM_EXYNOS_IPP_FORMAT_SOURCE); -	if (!src_fmt) { -		DRM_DEBUG_DRIVER("Task %pK: src format not supported\n", task); -		return -EINVAL; -	} -	ret = exynos_drm_ipp_check_size_limits(src, src_fmt->limits, -					       src_fmt->num_limits, -					       rotate, false); -	if (ret) -		return ret; -	ret = exynos_drm_ipp_check_scale_limits(&src->rect, &dst->rect, -						src_fmt->limits, -						src_fmt->num_limits, swap); +	ret = exynos_drm_ipp_check_format(task, src, src, dst, rotate, swap);  	if (ret)  		return ret; -	dst_fmt = __ipp_format_get(ipp, dst->buf.fourcc, dst->buf.modifier, -				   DRM_EXYNOS_IPP_FORMAT_DESTINATION); -	if (!dst_fmt) { -		DRM_DEBUG_DRIVER("Task %pK: dst format not supported\n", task); -		return -EINVAL; -	} -	ret = exynos_drm_ipp_check_size_limits(dst, dst_fmt->limits, -					       dst_fmt->num_limits, -					       false, swap); -	if (ret) -		return ret; -	ret = exynos_drm_ipp_check_scale_limits(&src->rect, &dst->rect, -						dst_fmt->limits, -						dst_fmt->num_limits, swap); +	ret = exynos_drm_ipp_check_format(task, dst, src, dst, false, swap);  	if (ret)  		return ret; diff --git a/drivers/gpu/drm/exynos/exynos_drm_mic.c b/drivers/gpu/drm/exynos/exynos_drm_mic.c index 2174814273e2..2fd299a58297 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_mic.c +++ b/drivers/gpu/drm/exynos/exynos_drm_mic.c @@ -367,6 +367,8 @@ static int exynos_mic_resume(struct device *dev)  static const struct dev_pm_ops exynos_mic_pm_ops = {  	SET_RUNTIME_PM_OPS(exynos_mic_suspend, exynos_mic_resume, NULL) +	SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, +				pm_runtime_force_resume)  };  static int exynos_mic_probe(struct platform_device *pdev) diff --git a/drivers/gpu/drm/exynos/exynos_drm_plane.c b/drivers/gpu/drm/exynos/exynos_drm_plane.c index eb9915da7dec..dba29aec59b4 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_plane.c +++ b/drivers/gpu/drm/exynos/exynos_drm_plane.c @@ -132,7 +132,7 @@ static void exynos_drm_plane_reset(struct drm_plane *plane)  	if (plane->state) {  		exynos_state = to_exynos_plane_state(plane->state);  		if (exynos_state->base.fb) -			drm_framebuffer_unreference(exynos_state->base.fb); +			drm_framebuffer_put(exynos_state->base.fb);  		kfree(exynos_state);  		plane->state = NULL;  	} diff --git a/drivers/gpu/drm/exynos/exynos_drm_rotator.c b/drivers/gpu/drm/exynos/exynos_drm_rotator.c index 1a76dd3d52e1..a820a68429b9 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_rotator.c +++ b/drivers/gpu/drm/exynos/exynos_drm_rotator.c @@ -168,9 +168,9 @@ static void rotator_dst_set_transf(struct rot_context *rot,  	val &= ~ROT_CONTROL_FLIP_MASK;  	if (rotation & DRM_MODE_REFLECT_X) -		val |= ROT_CONTROL_FLIP_HORIZONTAL; -	if (rotation & DRM_MODE_REFLECT_Y)  		val |= ROT_CONTROL_FLIP_VERTICAL; +	if (rotation & DRM_MODE_REFLECT_Y) +		val |= ROT_CONTROL_FLIP_HORIZONTAL;  	val &= ~ROT_CONTROL_ROT_MASK; diff --git a/drivers/gpu/drm/exynos/exynos_drm_scaler.c b/drivers/gpu/drm/exynos/exynos_drm_scaler.c index 91d4382343d0..0ddb6eec7b11 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_scaler.c +++ b/drivers/gpu/drm/exynos/exynos_drm_scaler.c @@ -30,6 +30,7 @@  #define scaler_write(cfg, offset)	writel(cfg, scaler->regs + (offset))  #define SCALER_MAX_CLK			4  #define SCALER_AUTOSUSPEND_DELAY	2000 +#define SCALER_RESET_WAIT_RETRIES	100  struct scaler_data {  	const char	*clk_name[SCALER_MAX_CLK]; @@ -51,9 +52,9 @@ struct scaler_context {  static u32 scaler_get_format(u32 drm_fmt)  {  	switch (drm_fmt) { -	case DRM_FORMAT_NV21: -		return SCALER_YUV420_2P_UV;  	case DRM_FORMAT_NV12: +		return SCALER_YUV420_2P_UV; +	case DRM_FORMAT_NV21:  		return SCALER_YUV420_2P_VU;  	case DRM_FORMAT_YUV420:  		return SCALER_YUV420_3P; @@ -63,15 +64,15 @@ static u32 scaler_get_format(u32 drm_fmt)  		return SCALER_YUV422_1P_UYVY;  	case DRM_FORMAT_YVYU:  		return SCALER_YUV422_1P_YVYU; -	case DRM_FORMAT_NV61: -		return SCALER_YUV422_2P_UV;  	case DRM_FORMAT_NV16: +		return SCALER_YUV422_2P_UV; +	case DRM_FORMAT_NV61:  		return SCALER_YUV422_2P_VU;  	case DRM_FORMAT_YUV422:  		return SCALER_YUV422_3P; -	case DRM_FORMAT_NV42: -		return SCALER_YUV444_2P_UV;  	case DRM_FORMAT_NV24: +		return SCALER_YUV444_2P_UV; +	case DRM_FORMAT_NV42:  		return SCALER_YUV444_2P_VU;  	case DRM_FORMAT_YUV444:  		return SCALER_YUV444_3P; @@ -100,6 +101,23 @@ static u32 scaler_get_format(u32 drm_fmt)  	return 0;  } +static inline int scaler_reset(struct scaler_context *scaler) +{ +	int retry = SCALER_RESET_WAIT_RETRIES; + +	scaler_write(SCALER_CFG_SOFT_RESET, SCALER_CFG); +	do { +		cpu_relax(); +	} while (retry > 1 && +		 scaler_read(SCALER_CFG) & SCALER_CFG_SOFT_RESET); +	do { +		cpu_relax(); +		scaler_write(1, SCALER_INT_EN); +	} while (retry > 0 && scaler_read(SCALER_INT_EN) != 1); + +	return retry ? 0 : -EIO; +} +  static inline void scaler_enable_int(struct scaler_context *scaler)  {  	u32 val; @@ -354,9 +372,13 @@ static int scaler_commit(struct exynos_drm_ipp *ipp,  	u32 dst_fmt = scaler_get_format(task->dst.buf.fourcc);  	struct drm_exynos_ipp_task_rect *dst_pos = &task->dst.rect; -	scaler->task = task; -  	pm_runtime_get_sync(scaler->dev); +	if (scaler_reset(scaler)) { +		pm_runtime_put(scaler->dev); +		return -EIO; +	} + +	scaler->task = task;  	scaler_set_src_fmt(scaler, src_fmt);  	scaler_set_src_base(scaler, &task->src); @@ -394,7 +416,11 @@ static inline void scaler_disable_int(struct scaler_context *scaler)  static inline u32 scaler_get_int_status(struct scaler_context *scaler)  { -	return scaler_read(SCALER_INT_STATUS); +	u32 val = scaler_read(SCALER_INT_STATUS); + +	scaler_write(val, SCALER_INT_STATUS); + +	return val;  }  static inline int scaler_task_done(u32 val) diff --git a/drivers/gpu/drm/exynos/exynos_hdmi.c b/drivers/gpu/drm/exynos/exynos_hdmi.c index 3a11c719a580..2092a650df7d 100644 --- a/drivers/gpu/drm/exynos/exynos_hdmi.c +++ b/drivers/gpu/drm/exynos/exynos_hdmi.c @@ -2093,6 +2093,8 @@ static int __maybe_unused exynos_hdmi_resume(struct device *dev)  static const struct dev_pm_ops exynos_hdmi_pm_ops = {  	SET_RUNTIME_PM_OPS(exynos_hdmi_suspend, exynos_hdmi_resume, NULL) +	SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, +				pm_runtime_force_resume)  };  struct platform_driver hdmi_driver = { diff --git a/drivers/gpu/drm/exynos/exynos_mixer.c b/drivers/gpu/drm/exynos/exynos_mixer.c index 272c79f5f5bf..ffbf4a950f69 100644 --- a/drivers/gpu/drm/exynos/exynos_mixer.c +++ b/drivers/gpu/drm/exynos/exynos_mixer.c @@ -837,8 +837,6 @@ static int mixer_initialize(struct mixer_context *mixer_ctx,  			struct drm_device *drm_dev)  {  	int ret; -	struct exynos_drm_private *priv; -	priv = drm_dev->dev_private;  	mixer_ctx->drm_dev = drm_dev; @@ -1271,6 +1269,8 @@ static int __maybe_unused exynos_mixer_resume(struct device *dev)  static const struct dev_pm_ops exynos_mixer_pm_ops = {  	SET_RUNTIME_PM_OPS(exynos_mixer_suspend, exynos_mixer_resume, NULL) +	SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, +				pm_runtime_force_resume)  };  struct platform_driver mixer_driver = { diff --git a/drivers/gpu/drm/exynos/regs-gsc.h b/drivers/gpu/drm/exynos/regs-gsc.h index 4704a993cbb7..16b39734115c 100644 --- a/drivers/gpu/drm/exynos/regs-gsc.h +++ b/drivers/gpu/drm/exynos/regs-gsc.h @@ -138,6 +138,7 @@  #define GSC_OUT_YUV420_3P		(3 << 4)  #define GSC_OUT_YUV422_1P		(4 << 4)  #define GSC_OUT_YUV422_2P		(5 << 4) +#define GSC_OUT_YUV422_3P		(6 << 4)  #define GSC_OUT_YUV444			(7 << 4)  #define GSC_OUT_TILE_TYPE_MASK		(1 << 2)  #define GSC_OUT_TILE_C_16x8		(0 << 2) | 
