mbox series

[v3,0/9] Exynos DRM: rewrite IPP subsystem and userspace API

Message ID 20171017110752.25096-1-m.szyprowski@samsung.com
Headers show
Series Exynos DRM: rewrite IPP subsystem and userspace API | expand

Message

Marek Szyprowski Oct. 17, 2017, 11:07 a.m. UTC
Dear all,

This patchset performs complete rewrite of Exynos DRM IPP subsystem and
its userspace API.

Why such rewrite is needed? Exynos DRM IPP API is over-engineered in
general, but not really extensible on the other side. It is also buggy,
with significant design flaws:
- Userspace API covers memory-2-memory picture operations together with
  CRTC writeback and duplicating features, which belongs to video plane.
- Lack of support of the all required image formats (for example NV12
  Samsung-tiled cannot be used due to lack of pixel format modifier
  support).
- Userspace API designed only to mimic hardware behaviour, not easy to
  understand.
- Lack of proper input validation in the core, drivers also didn't do that
  correctly, so it was possible to set incorrect parameters and easil
  trigger IOMMU fault or memory trash.
- Drivers were partially disfunctional or supported only a subset of modes.

Due to the above limitations and issues the Exynos DRM IPP API was not
used by any of the open-source projects. I assume that it is safe to remove
this broken API without any damage to open-source community. All remaining
users (mainly Tizen project related) will be updated to the new version.

This patchset changes Exynos DRM IPP subsystem to something useful. The
userspace API is much simpler, state-less and easy to understand. Also
the code of the core and driver is significantly smaller and easier to
understand.

Patches were tested on Exynos4412 based Odroid U3, Exynos5422
Odroid XU3 and Exynos5433 TM2 boards, on top of Linux next-20171016 kernel.

Best regards
Marek Szyprowski
Samsung R&D Institute Poland


Changelog:

v3:
- fixed minor issues and added features pointed by other developers:
  * fixed missing ipp_unregister (Hoegeun)
  * added missing limits to FIMC and GSC driver (Hoegeun)
  * added more specific compatible strings to GSC driver (Hoegeun)
  * added Exynos5433 support to GSC driver (Hoegeun)
  * added autosuspend runtime PM to all IPP drivers (Tobias)
- added Exynos5433 support to Scaler driver (thanks to Andrzej)
- dropped Exynos5420 clk patch, which has been alredy merged

v2: https://www.spinics.net/lists/dri-devel/msg153418.html
- fixed minor issues pointed by other developers:
  * fixed possible null pointer dereferrence (Tobias)
  * changed limits_size to limits_count (Tobias)
  * renamed struct exynos_drm_ipp_format to drm_exynos_ipp_format (Andrzej)
  * added proper return value from exynos_drm_ipp_get_res_ioctl when no IPP
    driver is present (Andrzej)
  * properly aligned all uapi structures to be 32/64 bit safe (Emil)
  * properly initialize all strucutres
- added new Exynos Scaler driver from Andrzej Pietrasiewicz

v1: https://www.spinics.net/lists/linux-samsung-soc/msg60492.html
- initial version of IPP v2

My previous works in this area:

"[RFC v2 0/2] Exynos DRM: add Picture Processor extension"
https://www.spinics.net/lists/dri-devel/msg140669.html
- removed usage of DRM objects and properties - replaced them with simple
  list of parameters with predefined IDs

"[RFC 0/4] Exynos DRM: add Picture Processor extension"
https://www.spinics.net/lists/linux-samsung-soc/msg59323.html
- moved this feature from DRM core to Exynos DRM driver
- changed name from framebuffer processor to picture processor
- simplified code to cover only things needed by Exynos drivers
- implemented simple fifo task scheduler
- cleaned up rotator driver conversion (removed IPP remainings)

"[RFC 0/2] New feature: Framebuffer processors"
https://www.spinics.net/lists/linux-samsung-soc/msg54810.html
- generic approach implemented in DRM core, rejected


Patch summary:

Andrzej Pietrasiewicz (3):
  drm/exynos: Add driver for Exynos Scaler module
  ARM: dts: exynos: Add mem-2-mem Scaler devices
  ARM64: dts: exynos: Add mem-2-mem Scaler devices

Marek Szyprowski (6):
  drm/exynos: ipp: Remove Exynos DRM IPP subsystem
  drm/exynos: ipp: Add IPP v2 framework
  drm/exynos: rotator: Convert driver to IPP v2 core API
  drm/exynos: gsc: Convert driver to IPP v2 core API
  drm/exynos: Add generic support for devices shared with V4L2 subsystem
  drm/exynos: fimc: Convert driver to IPP v2 core API

 .../devicetree/bindings/gpu/samsung-scaler.txt     |   26 +
 arch/arm/boot/dts/exynos5420.dtsi                  |   35 +
 arch/arm64/boot/dts/exynos/exynos5433.dtsi         |   42 +
 drivers/gpu/drm/exynos/Kconfig                     |   17 +-
 drivers/gpu/drm/exynos/Makefile                    |    1 +
 drivers/gpu/drm/exynos/exynos_drm_drv.c            |   36 +-
 drivers/gpu/drm/exynos/exynos_drm_drv.h            |    5 +-
 drivers/gpu/drm/exynos/exynos_drm_fimc.c           |  930 +++-----
 drivers/gpu/drm/exynos/exynos_drm_fimc.h           |   23 -
 drivers/gpu/drm/exynos/exynos_drm_gsc.c            |  995 +++------
 drivers/gpu/drm/exynos/exynos_drm_gsc.h            |   24 -
 drivers/gpu/drm/exynos/exynos_drm_ipp.c            | 2240 ++++++--------------
 drivers/gpu/drm/exynos/exynos_drm_ipp.h            |  357 ++--
 drivers/gpu/drm/exynos/exynos_drm_rotator.c        |  740 ++-----
 drivers/gpu/drm/exynos/exynos_drm_rotator.h        |   19 -
 drivers/gpu/drm/exynos/exynos_drm_scaler.c         |  717 +++++++
 drivers/gpu/drm/exynos/regs-scaler.h               |  426 ++++
 include/uapi/drm/exynos_drm.h                      |  326 +--
 18 files changed, 3057 insertions(+), 3902 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/gpu/samsung-scaler.txt
 delete mode 100644 drivers/gpu/drm/exynos/exynos_drm_fimc.h
 delete mode 100644 drivers/gpu/drm/exynos/exynos_drm_gsc.h
 delete mode 100644 drivers/gpu/drm/exynos/exynos_drm_rotator.h
 create mode 100644 drivers/gpu/drm/exynos/exynos_drm_scaler.c
 create mode 100644 drivers/gpu/drm/exynos/regs-scaler.h

-- 
2.14.2

--
To unsubscribe from this list: send the line "unsubscribe linux-samsung-soc" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Comments

Daniel Vetter Oct. 17, 2017, 12:24 p.m. UTC | #1
On Tue, Oct 17, 2017 at 01:07:43PM +0200, Marek Szyprowski wrote:
> Dear all,

> 

> This patchset performs complete rewrite of Exynos DRM IPP subsystem and

> its userspace API.

> 

> Why such rewrite is needed? Exynos DRM IPP API is over-engineered in

> general, but not really extensible on the other side. It is also buggy,

> with significant design flaws:

> - Userspace API covers memory-2-memory picture operations together with

>   CRTC writeback and duplicating features, which belongs to video plane.

> - Lack of support of the all required image formats (for example NV12

>   Samsung-tiled cannot be used due to lack of pixel format modifier

>   support).

> - Userspace API designed only to mimic hardware behaviour, not easy to

>   understand.

> - Lack of proper input validation in the core, drivers also didn't do that

>   correctly, so it was possible to set incorrect parameters and easil

>   trigger IOMMU fault or memory trash.

> - Drivers were partially disfunctional or supported only a subset of modes.

> 

> Due to the above limitations and issues the Exynos DRM IPP API was not

> used by any of the open-source projects. I assume that it is safe to remove

> this broken API without any damage to open-source community. All remaining

> users (mainly Tizen project related) will be updated to the new version.

> 

> This patchset changes Exynos DRM IPP subsystem to something useful. The

> userspace API is much simpler, state-less and easy to understand. Also

> the code of the core and driver is significantly smaller and easier to

> understand.

> 

> Patches were tested on Exynos4412 based Odroid U3, Exynos5422

> Odroid XU3 and Exynos5433 TM2 boards, on top of Linux next-20171016 kernel.


When submitting uapi changes, please link to the corresponding userspace
work. Otherwise pretty hard to find this stuff.
-Daniel

> 

> Best regards

> Marek Szyprowski

> Samsung R&D Institute Poland

> 

> 

> Changelog:

> 

> v3:

> - fixed minor issues and added features pointed by other developers:

>   * fixed missing ipp_unregister (Hoegeun)

>   * added missing limits to FIMC and GSC driver (Hoegeun)

>   * added more specific compatible strings to GSC driver (Hoegeun)

>   * added Exynos5433 support to GSC driver (Hoegeun)

>   * added autosuspend runtime PM to all IPP drivers (Tobias)

> - added Exynos5433 support to Scaler driver (thanks to Andrzej)

> - dropped Exynos5420 clk patch, which has been alredy merged

> 

> v2: https://www.spinics.net/lists/dri-devel/msg153418.html

> - fixed minor issues pointed by other developers:

>   * fixed possible null pointer dereferrence (Tobias)

>   * changed limits_size to limits_count (Tobias)

>   * renamed struct exynos_drm_ipp_format to drm_exynos_ipp_format (Andrzej)

>   * added proper return value from exynos_drm_ipp_get_res_ioctl when no IPP

>     driver is present (Andrzej)

>   * properly aligned all uapi structures to be 32/64 bit safe (Emil)

>   * properly initialize all strucutres

> - added new Exynos Scaler driver from Andrzej Pietrasiewicz

> 

> v1: https://www.spinics.net/lists/linux-samsung-soc/msg60492.html

> - initial version of IPP v2

> 

> My previous works in this area:

> 

> "[RFC v2 0/2] Exynos DRM: add Picture Processor extension"

> https://www.spinics.net/lists/dri-devel/msg140669.html

> - removed usage of DRM objects and properties - replaced them with simple

>   list of parameters with predefined IDs

> 

> "[RFC 0/4] Exynos DRM: add Picture Processor extension"

> https://www.spinics.net/lists/linux-samsung-soc/msg59323.html

> - moved this feature from DRM core to Exynos DRM driver

> - changed name from framebuffer processor to picture processor

> - simplified code to cover only things needed by Exynos drivers

> - implemented simple fifo task scheduler

> - cleaned up rotator driver conversion (removed IPP remainings)

> 

> "[RFC 0/2] New feature: Framebuffer processors"

> https://www.spinics.net/lists/linux-samsung-soc/msg54810.html

> - generic approach implemented in DRM core, rejected

> 

> 

> Patch summary:

> 

> Andrzej Pietrasiewicz (3):

>   drm/exynos: Add driver for Exynos Scaler module

>   ARM: dts: exynos: Add mem-2-mem Scaler devices

>   ARM64: dts: exynos: Add mem-2-mem Scaler devices

> 

> Marek Szyprowski (6):

>   drm/exynos: ipp: Remove Exynos DRM IPP subsystem

>   drm/exynos: ipp: Add IPP v2 framework

>   drm/exynos: rotator: Convert driver to IPP v2 core API

>   drm/exynos: gsc: Convert driver to IPP v2 core API

>   drm/exynos: Add generic support for devices shared with V4L2 subsystem

>   drm/exynos: fimc: Convert driver to IPP v2 core API

> 

>  .../devicetree/bindings/gpu/samsung-scaler.txt     |   26 +

>  arch/arm/boot/dts/exynos5420.dtsi                  |   35 +

>  arch/arm64/boot/dts/exynos/exynos5433.dtsi         |   42 +

>  drivers/gpu/drm/exynos/Kconfig                     |   17 +-

>  drivers/gpu/drm/exynos/Makefile                    |    1 +

>  drivers/gpu/drm/exynos/exynos_drm_drv.c            |   36 +-

>  drivers/gpu/drm/exynos/exynos_drm_drv.h            |    5 +-

>  drivers/gpu/drm/exynos/exynos_drm_fimc.c           |  930 +++-----

>  drivers/gpu/drm/exynos/exynos_drm_fimc.h           |   23 -

>  drivers/gpu/drm/exynos/exynos_drm_gsc.c            |  995 +++------

>  drivers/gpu/drm/exynos/exynos_drm_gsc.h            |   24 -

>  drivers/gpu/drm/exynos/exynos_drm_ipp.c            | 2240 ++++++--------------

>  drivers/gpu/drm/exynos/exynos_drm_ipp.h            |  357 ++--

>  drivers/gpu/drm/exynos/exynos_drm_rotator.c        |  740 ++-----

>  drivers/gpu/drm/exynos/exynos_drm_rotator.h        |   19 -

>  drivers/gpu/drm/exynos/exynos_drm_scaler.c         |  717 +++++++

>  drivers/gpu/drm/exynos/regs-scaler.h               |  426 ++++

>  include/uapi/drm/exynos_drm.h                      |  326 +--

>  18 files changed, 3057 insertions(+), 3902 deletions(-)

>  create mode 100644 Documentation/devicetree/bindings/gpu/samsung-scaler.txt

>  delete mode 100644 drivers/gpu/drm/exynos/exynos_drm_fimc.h

>  delete mode 100644 drivers/gpu/drm/exynos/exynos_drm_gsc.h

>  delete mode 100644 drivers/gpu/drm/exynos/exynos_drm_rotator.h

>  create mode 100644 drivers/gpu/drm/exynos/exynos_drm_scaler.c

>  create mode 100644 drivers/gpu/drm/exynos/regs-scaler.h

> 

> -- 

> 2.14.2

> 

> _______________________________________________

> dri-devel mailing list

> dri-devel@lists.freedesktop.org

> https://lists.freedesktop.org/mailman/listinfo/dri-devel


-- 
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch
--
To unsubscribe from this list: send the line "unsubscribe linux-samsung-soc" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Marek Szyprowski Oct. 18, 2017, 7:41 a.m. UTC | #2
Hi Daniel,

On 2017-10-17 14:24, Daniel Vetter wrote:
> On Tue, Oct 17, 2017 at 01:07:43PM +0200, Marek Szyprowski wrote:

>> This patchset performs complete rewrite of Exynos DRM IPP subsystem and

>> its userspace API.

>>

>> Why such rewrite is needed? Exynos DRM IPP API is over-engineered in

>> general, but not really extensible on the other side. It is also buggy,

>> with significant design flaws:

>> - Userspace API covers memory-2-memory picture operations together with

>>    CRTC writeback and duplicating features, which belongs to video plane.

>> - Lack of support of the all required image formats (for example NV12

>>    Samsung-tiled cannot be used due to lack of pixel format modifier

>>    support).

>> - Userspace API designed only to mimic hardware behaviour, not easy to

>>    understand.

>> - Lack of proper input validation in the core, drivers also didn't do that

>>    correctly, so it was possible to set incorrect parameters and easil

>>    trigger IOMMU fault or memory trash.

>> - Drivers were partially disfunctional or supported only a subset of modes.

>>

>> Due to the above limitations and issues the Exynos DRM IPP API was not

>> used by any of the open-source projects. I assume that it is safe to remove

>> this broken API without any damage to open-source community. All remaining

>> users (mainly Tizen project related) will be updated to the new version.

>>

>> This patchset changes Exynos DRM IPP subsystem to something useful. The

>> userspace API is much simpler, state-less and easy to understand. Also

>> the code of the core and driver is significantly smaller and easier to

>> understand.

>>

>> Patches were tested on Exynos4412 based Odroid U3, Exynos5422

>> Odroid XU3 and Exynos5433 TM2 boards, on top of Linux next-20171016 kernel.

> When submitting uapi changes, please link to the corresponding userspace

> work. Otherwise pretty hard to find this stuff.


A simple userspace test tool has been sent together with v1:
https://www.spinics.net/lists/linux-samsung-soc/msg60498.html

Tobias Jakobi has added support for this new API to his fork of libdrm and
mpv video player:
https://github.com/tobiasjakobi/libdrm/tree/ippv2
https://github.com/tobiasjakobi/mpv

Best regards
-- 
Marek Szyprowski, PhD
Samsung R&D Institute Poland

--
To unsubscribe from this list: send the line "unsubscribe linux-samsung-soc" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Tobias Jakobi Oct. 19, 2017, 1:02 p.m. UTC | #3
Hey Marek,


Marek Szyprowski wrote:
> This patch adapts Exynos DRM rotator driver to new IPP v2 core API.

you probably mean "DRM gsc driver" here (or GSC, not sure about capitalisation).

- Tobias


> The side effect of this conversion is a switch to driver component API

> to register properly in the Exynos DRM core.

> 

> Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com>

> Tested-by: Hoegeun Kwon <hoegeun.kwon@samsung.com>

> ---

>  drivers/gpu/drm/exynos/Kconfig          |   3 +-

>  drivers/gpu/drm/exynos/exynos_drm_drv.c |   1 +

>  drivers/gpu/drm/exynos/exynos_drm_gsc.c | 995 ++++++++++----------------------

>  drivers/gpu/drm/exynos/exynos_drm_gsc.h |  24 -

>  4 files changed, 315 insertions(+), 708 deletions(-)

>  delete mode 100644 drivers/gpu/drm/exynos/exynos_drm_gsc.h

> 

> diff --git a/drivers/gpu/drm/exynos/Kconfig b/drivers/gpu/drm/exynos/Kconfig

> index c10c9ca0d8b4..4bb9edb00601 100644

> --- a/drivers/gpu/drm/exynos/Kconfig

> +++ b/drivers/gpu/drm/exynos/Kconfig

> @@ -111,7 +111,8 @@ config DRM_EXYNOS_ROTATOR

>  

>  config DRM_EXYNOS_GSC

>  	bool "GScaler"

> -	depends on BROKEN && ARCH_EXYNOS5 && VIDEO_SAMSUNG_EXYNOS_GSC=n

> +	depends on ARCH_EXYNOS5 && VIDEO_SAMSUNG_EXYNOS_GSC=n

> +	select DRM_EXYNOS_IPP

>  	help

>  	  Choose this option if you want to use Exynos GSC for DRM.

>  

> diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.c b/drivers/gpu/drm/exynos/exynos_drm_drv.c

> index 3ade2b0ad15d..cac0d84385d3 100644

> --- a/drivers/gpu/drm/exynos/exynos_drm_drv.c

> +++ b/drivers/gpu/drm/exynos/exynos_drm_drv.c

> @@ -260,6 +260,7 @@ static struct exynos_drm_driver_info exynos_drm_drivers[] = {

>  		DRM_COMPONENT_DRIVER

>  	}, {

>  		DRV_PTR(gsc_driver, CONFIG_DRM_EXYNOS_GSC),

> +		DRM_COMPONENT_DRIVER

>  	}, {

>  		&exynos_drm_platform_driver,

>  		DRM_VIRTUAL_DEVICE

> diff --git a/drivers/gpu/drm/exynos/exynos_drm_gsc.c b/drivers/gpu/drm/exynos/exynos_drm_gsc.c

> index 0506b2b17ac1..f99d4fea9df1 100644

> --- a/drivers/gpu/drm/exynos/exynos_drm_gsc.c

> +++ b/drivers/gpu/drm/exynos/exynos_drm_gsc.c

> @@ -12,18 +12,20 @@

>   *

>   */

>  #include <linux/kernel.h>

> +#include <linux/component.h>

>  #include <linux/platform_device.h>

>  #include <linux/clk.h>

>  #include <linux/pm_runtime.h>

>  #include <linux/mfd/syscon.h>

> +#include <linux/of_device.h>

>  #include <linux/regmap.h>

>  

>  #include <drm/drmP.h>

>  #include <drm/exynos_drm.h>

>  #include "regs-gsc.h"

>  #include "exynos_drm_drv.h"

> +#include "exynos_drm_iommu.h"

>  #include "exynos_drm_ipp.h"

> -#include "exynos_drm_gsc.h"

>  

>  /*

>   * GSC stands for General SCaler and

> @@ -31,26 +33,10 @@

>   * input DMA reads image data from the memory.

>   * output DMA writes image data to memory.

>   * GSC supports image rotation and image effect functions.

> - *

> - * M2M operation : supports crop/scale/rotation/csc so on.

> - * Memory ----> GSC H/W ----> Memory.

> - * Writeback operation : supports cloned screen with FIMD.

> - * FIMD ----> GSC H/W ----> Memory.

> - * Output operation : supports direct display using local path.

> - * Memory ----> GSC H/W ----> FIMD, Mixer.

>   */

>  

> -/*

> - * TODO

> - * 1. check suspend/resume api if needed.

> - * 2. need to check use case platform_device_id.

> - * 3. check src/dst size with, height.

> - * 4. added check_prepare api for right register.

> - * 5. need to add supported list in prop_list.

> - * 6. check prescaler/scaler optimization.

> - */

>  

> -#define GSC_MAX_DEVS	4

> +#define GSC_MAX_CLOCKS	8

>  #define GSC_MAX_SRC		4

>  #define GSC_MAX_DST		16

>  #define GSC_RESET_TIMEOUT	50

> @@ -65,8 +51,6 @@

>  #define GSC_SC_DOWN_RATIO_4_8		131072

>  #define GSC_SC_DOWN_RATIO_3_8		174762

>  #define GSC_SC_DOWN_RATIO_2_8		262144

> -#define GSC_REFRESH_MIN	12

> -#define GSC_REFRESH_MAX	60

>  #define GSC_CROP_MAX	8192

>  #define GSC_CROP_MIN	32

>  #define GSC_SCALE_MAX	4224

> @@ -77,10 +61,9 @@

>  #define GSC_COEF_H_8T	8

>  #define GSC_COEF_V_4T	4

>  #define GSC_COEF_DEPTH	3

> +#define GSC_AUTOSUSPEND_DELAY		2000

>  

>  #define get_gsc_context(dev)	platform_get_drvdata(to_platform_device(dev))

> -#define get_ctx_from_ippdrv(ippdrv)	container_of(ippdrv,\

> -					struct gsc_context, ippdrv);

>  #define gsc_read(offset)		readl(ctx->regs + (offset))

>  #define gsc_write(cfg, offset)	writel(cfg, ctx->regs + (offset))

>  

> @@ -124,7 +107,6 @@ struct gsc_capability {

>  /*

>   * A structure of gsc context.

>   *

> - * @ippdrv: prepare initialization using ippdrv.

>   * @regs_res: register resources.

>   * @regs: memory mapped io registers.

>   * @sysreg: handle to SYSREG block regmap.

> @@ -137,12 +119,18 @@ struct gsc_capability {

>   * @suspended: qos operations.

>   */

>  struct gsc_context {

> -	struct exynos_drm_ippdrv	ippdrv;

> +	struct exynos_drm_ipp ipp;

> +	struct drm_device *drm_dev;

> +	struct device	*dev;

> +	struct exynos_drm_ipp_task	*task;

> +	struct exynos_drm_ipp_formats	*formats;

> +

>  	struct resource	*regs_res;

>  	void __iomem	*regs;

>  	struct regmap	*sysreg;

> -	struct mutex	lock;

> -	struct clk	*gsc_clk;

> +	const char	**clk_names;

> +	struct clk	*clocks[GSC_MAX_CLOCKS];

> +	int		num_clocks;

>  	struct gsc_scaler	sc;

>  	int	id;

>  	int	irq;

> @@ -150,6 +138,19 @@ struct gsc_context {

>  	bool	suspended;

>  };

>  

> +/**

> + * struct gsc_driverdata - per device type driver data for init time.

> + *

> + * @limits: picture size limits array

> + * @clk_names: names of clocks needed by this variant

> + * @num_clocks: the number of clocks needed by this variant

> + */

> +struct gsc_driverdata {

> +	const struct drm_exynos_ipp_limit *limits;

> +	const char	*clk_names[GSC_MAX_CLOCKS];

> +	int		num_clocks;

> +};

> +

>  /* 8-tap Filter Coefficient */

>  static const int h_coef_8t[GSC_COEF_RATIO][GSC_COEF_ATTR][GSC_COEF_H_8T] = {

>  	{	/* Ratio <= 65536 (~8:8) */

> @@ -438,25 +439,6 @@ static int gsc_sw_reset(struct gsc_context *ctx)

>  	return 0;

>  }

>  

> -static void gsc_set_gscblk_fimd_wb(struct gsc_context *ctx, bool enable)

> -{

> -	unsigned int gscblk_cfg;

> -

> -	if (!ctx->sysreg)

> -		return;

> -

> -	regmap_read(ctx->sysreg, SYSREG_GSCBLK_CFG1, &gscblk_cfg);

> -

> -	if (enable)

> -		gscblk_cfg |= GSC_BLK_DISP1WB_DEST(ctx->id) |

> -				GSC_BLK_GSCL_WB_IN_SRC_SEL(ctx->id) |

> -				GSC_BLK_SW_RESET_WB_DEST(ctx->id);

> -	else

> -		gscblk_cfg |= GSC_BLK_PXLASYNC_LO_MASK_WB(ctx->id);

> -

> -	regmap_write(ctx->sysreg, SYSREG_GSCBLK_CFG1, gscblk_cfg);

> -}

> -

>  static void gsc_handle_irq(struct gsc_context *ctx, bool enable,

>  		bool overflow, bool done)

>  {

> @@ -487,10 +469,8 @@ static void gsc_handle_irq(struct gsc_context *ctx, bool enable,

>  }

>  

>  

> -static int gsc_src_set_fmt(struct device *dev, u32 fmt)

> +static int gsc_src_set_fmt(struct gsc_context *ctx, u32 fmt)

>  {

> -	struct gsc_context *ctx = get_gsc_context(dev);

> -	struct exynos_drm_ippdrv *ippdrv = &ctx->ippdrv;

>  	u32 cfg;

>  

>  	DRM_DEBUG_KMS("fmt[0x%x]\n", fmt);

> @@ -549,7 +529,7 @@ static int gsc_src_set_fmt(struct device *dev, u32 fmt)

>  			GSC_IN_YUV420_2P);

>  		break;

>  	default:

> -		dev_err(ippdrv->dev, "invalid target yuv order 0x%x.\n", fmt);

> +		dev_err(ctx->dev, "invalid target yuv order 0x%x.\n", fmt);

>  		return -EINVAL;

>  	}

>  

> @@ -558,105 +538,81 @@ static int gsc_src_set_fmt(struct device *dev, u32 fmt)

>  	return 0;

>  }

>  

> -static int gsc_src_set_transf(struct device *dev,

> -		enum drm_exynos_degree degree,

> -		enum drm_exynos_flip flip, bool *swap)

> +static int gsc_src_set_transf(struct gsc_context *ctx, unsigned int rotation)

>  {

> -	struct gsc_context *ctx = get_gsc_context(dev);

> -	struct exynos_drm_ippdrv *ippdrv = &ctx->ippdrv;

> +	unsigned int degree = rotation & DRM_MODE_ROTATE_MASK;

>  	u32 cfg;

>  

> -	DRM_DEBUG_KMS("degree[%d]flip[0x%x]\n", degree, flip);

> -

>  	cfg = gsc_read(GSC_IN_CON);

>  	cfg &= ~GSC_IN_ROT_MASK;

>  

>  	switch (degree) {

> -	case EXYNOS_DRM_DEGREE_0:

> -		if (flip & EXYNOS_DRM_FLIP_VERTICAL)

> +	case DRM_MODE_ROTATE_0:

> +		if (rotation & DRM_MODE_REFLECT_Y)

>  			cfg |= GSC_IN_ROT_XFLIP;

> -		if (flip & EXYNOS_DRM_FLIP_HORIZONTAL)

> +		if (rotation & DRM_MODE_REFLECT_X)

>  			cfg |= GSC_IN_ROT_YFLIP;

>  		break;

> -	case EXYNOS_DRM_DEGREE_90:

> -		if (flip & EXYNOS_DRM_FLIP_VERTICAL)

> +	case DRM_MODE_ROTATE_90:

> +		if (rotation & DRM_MODE_REFLECT_Y)

>  			cfg |= GSC_IN_ROT_90_XFLIP;

> -		else if (flip & EXYNOS_DRM_FLIP_HORIZONTAL)

> +		else if (rotation & DRM_MODE_REFLECT_X)

>  			cfg |= GSC_IN_ROT_90_YFLIP;

>  		else

>  			cfg |= GSC_IN_ROT_90;

>  		break;

> -	case EXYNOS_DRM_DEGREE_180:

> +	case DRM_MODE_ROTATE_180:

>  		cfg |= GSC_IN_ROT_180;

> -		if (flip & EXYNOS_DRM_FLIP_VERTICAL)

> +		if (rotation & DRM_MODE_REFLECT_Y)

>  			cfg &= ~GSC_IN_ROT_XFLIP;

> -		if (flip & EXYNOS_DRM_FLIP_HORIZONTAL)

> +		if (rotation & DRM_MODE_REFLECT_X)

>  			cfg &= ~GSC_IN_ROT_YFLIP;

>  		break;

> -	case EXYNOS_DRM_DEGREE_270:

> +	case DRM_MODE_ROTATE_270:

>  		cfg |= GSC_IN_ROT_270;

> -		if (flip & EXYNOS_DRM_FLIP_VERTICAL)

> +		if (rotation & DRM_MODE_REFLECT_Y)

>  			cfg &= ~GSC_IN_ROT_XFLIP;

> -		if (flip & EXYNOS_DRM_FLIP_HORIZONTAL)

> +		if (rotation & DRM_MODE_REFLECT_X)

>  			cfg &= ~GSC_IN_ROT_YFLIP;

>  		break;

> -	default:

> -		dev_err(ippdrv->dev, "invalid degree value %d.\n", degree);

> -		return -EINVAL;

>  	}

>  

>  	gsc_write(cfg, GSC_IN_CON);

>  

>  	ctx->rotation = (cfg & GSC_IN_ROT_90) ? 1 : 0;

> -	*swap = ctx->rotation;

> -

>  	return 0;

>  }

>  

> -static int gsc_src_set_size(struct device *dev, int swap,

> -		struct drm_exynos_pos *pos, struct drm_exynos_sz *sz)

> +static int gsc_src_set_size(struct gsc_context *ctx,

> +		struct exynos_drm_ipp_buffer *buf)

>  {

> -	struct gsc_context *ctx = get_gsc_context(dev);

> -	struct drm_exynos_pos img_pos = *pos;

>  	struct gsc_scaler *sc = &ctx->sc;

>  	u32 cfg;

>  

> -	DRM_DEBUG_KMS("swap[%d]x[%d]y[%d]w[%d]h[%d]\n",

> -		swap, pos->x, pos->y, pos->w, pos->h);

> -

> -	if (swap) {

> -		img_pos.w = pos->h;

> -		img_pos.h = pos->w;

> -	}

> -

>  	/* pixel offset */

> -	cfg = (GSC_SRCIMG_OFFSET_X(img_pos.x) |

> -		GSC_SRCIMG_OFFSET_Y(img_pos.y));

> +	cfg = (GSC_SRCIMG_OFFSET_X(buf->rect.x) |

> +		GSC_SRCIMG_OFFSET_Y(buf->rect.y));

>  	gsc_write(cfg, GSC_SRCIMG_OFFSET);

>  

>  	/* cropped size */

> -	cfg = (GSC_CROPPED_WIDTH(img_pos.w) |

> -		GSC_CROPPED_HEIGHT(img_pos.h));

> +	cfg = (GSC_CROPPED_WIDTH(buf->rect.w) |

> +		GSC_CROPPED_HEIGHT(buf->rect.h));

>  	gsc_write(cfg, GSC_CROPPED_SIZE);

>  

> -	DRM_DEBUG_KMS("hsize[%d]vsize[%d]\n", sz->hsize, sz->vsize);

> -

>  	/* original size */

>  	cfg = gsc_read(GSC_SRCIMG_SIZE);

>  	cfg &= ~(GSC_SRCIMG_HEIGHT_MASK |

>  		GSC_SRCIMG_WIDTH_MASK);

>  

> -	cfg |= (GSC_SRCIMG_WIDTH(sz->hsize) |

> -		GSC_SRCIMG_HEIGHT(sz->vsize));

> +	cfg |= (GSC_SRCIMG_WIDTH(buf->buf.width) |

> +		GSC_SRCIMG_HEIGHT(buf->buf.height));

>  

>  	gsc_write(cfg, GSC_SRCIMG_SIZE);

>  

>  	cfg = gsc_read(GSC_IN_CON);

>  	cfg &= ~GSC_IN_RGB_TYPE_MASK;

>  

> -	DRM_DEBUG_KMS("width[%d]range[%d]\n", pos->w, sc->range);

> -

> -	if (pos->w >= GSC_WIDTH_ITU_709)

> +	if (buf->rect.w >= GSC_WIDTH_ITU_709)

>  		if (sc->range)

>  			cfg |= GSC_IN_RGB_HD_WIDE;

>  		else

> @@ -673,30 +629,15 @@ static int gsc_src_set_size(struct device *dev, int swap,

>  }

>  

>  static int gsc_src_set_buf_seq(struct gsc_context *ctx, u32 buf_id,

> -		enum drm_exynos_ipp_buf_type buf_type)

> +			       bool enqueue)

>  {

> -	struct exynos_drm_ippdrv *ippdrv = &ctx->ippdrv;

> -	bool masked;

> +	bool masked = !enqueue;

>  	u32 cfg;

>  	u32 mask = 0x00000001 << buf_id;

>  

> -	DRM_DEBUG_KMS("buf_id[%d]buf_type[%d]\n", buf_id, buf_type);

> -

>  	/* mask register set */

>  	cfg = gsc_read(GSC_IN_BASE_ADDR_Y_MASK);

>  

> -	switch (buf_type) {

> -	case IPP_BUF_ENQUEUE:

> -		masked = false;

> -		break;

> -	case IPP_BUF_DEQUEUE:

> -		masked = true;

> -		break;

> -	default:

> -		dev_err(ippdrv->dev, "invalid buf ctrl parameter.\n");

> -		return -EINVAL;

> -	}

> -

>  	/* sequence id */

>  	cfg &= ~mask;

>  	cfg |= masked << buf_id;

> @@ -707,64 +648,19 @@ static int gsc_src_set_buf_seq(struct gsc_context *ctx, u32 buf_id,

>  	return 0;

>  }

>  

> -static int gsc_src_set_addr(struct device *dev,

> -		struct drm_exynos_ipp_buf_info *buf_info, u32 buf_id,

> -		enum drm_exynos_ipp_buf_type buf_type)

> +static int gsc_src_set_addr(struct gsc_context *ctx, u32 buf_id,

> +			    struct exynos_drm_ipp_buffer *buf)

>  {

> -	struct gsc_context *ctx = get_gsc_context(dev);

> -	struct exynos_drm_ippdrv *ippdrv = &ctx->ippdrv;

> -	struct drm_exynos_ipp_cmd_node *c_node = ippdrv->c_node;

> -	struct drm_exynos_ipp_property *property;

> -

> -	if (!c_node) {

> -		DRM_ERROR("failed to get c_node.\n");

> -		return -EFAULT;

> -	}

> -

> -	property = &c_node->property;

> -

> -	DRM_DEBUG_KMS("prop_id[%d]buf_id[%d]buf_type[%d]\n",

> -		property->prop_id, buf_id, buf_type);

> -

> -	if (buf_id > GSC_MAX_SRC) {

> -		dev_info(ippdrv->dev, "invalid buf_id %d.\n", buf_id);

> -		return -EINVAL;

> -	}

> -

>  	/* address register set */

> -	switch (buf_type) {

> -	case IPP_BUF_ENQUEUE:

> -		gsc_write(buf_info->base[EXYNOS_DRM_PLANAR_Y],

> -			GSC_IN_BASE_ADDR_Y(buf_id));

> -		gsc_write(buf_info->base[EXYNOS_DRM_PLANAR_CB],

> -			GSC_IN_BASE_ADDR_CB(buf_id));

> -		gsc_write(buf_info->base[EXYNOS_DRM_PLANAR_CR],

> -			GSC_IN_BASE_ADDR_CR(buf_id));

> -		break;

> -	case IPP_BUF_DEQUEUE:

> -		gsc_write(0x0, GSC_IN_BASE_ADDR_Y(buf_id));

> -		gsc_write(0x0, GSC_IN_BASE_ADDR_CB(buf_id));

> -		gsc_write(0x0, GSC_IN_BASE_ADDR_CR(buf_id));

> -		break;

> -	default:

> -		/* bypass */

> -		break;

> -	}

> +	gsc_write(buf->dma_addr[0], GSC_IN_BASE_ADDR_Y(buf_id));

> +	gsc_write(buf->dma_addr[1], GSC_IN_BASE_ADDR_CB(buf_id));

> +	gsc_write(buf->dma_addr[2], GSC_IN_BASE_ADDR_CR(buf_id));

>  

> -	return gsc_src_set_buf_seq(ctx, buf_id, buf_type);

> +	return gsc_src_set_buf_seq(ctx, buf_id, true);

>  }

>  

> -static struct exynos_drm_ipp_ops gsc_src_ops = {

> -	.set_fmt = gsc_src_set_fmt,

> -	.set_transf = gsc_src_set_transf,

> -	.set_size = gsc_src_set_size,

> -	.set_addr = gsc_src_set_addr,

> -};

> -

> -static int gsc_dst_set_fmt(struct device *dev, u32 fmt)

> +static int gsc_dst_set_fmt(struct gsc_context *ctx, u32 fmt)

>  {

> -	struct gsc_context *ctx = get_gsc_context(dev);

> -	struct exynos_drm_ippdrv *ippdrv = &ctx->ippdrv;

>  	u32 cfg;

>  

>  	DRM_DEBUG_KMS("fmt[0x%x]\n", fmt);

> @@ -819,9 +715,6 @@ static int gsc_dst_set_fmt(struct device *dev, u32 fmt)

>  		cfg |= (GSC_OUT_CHROMA_ORDER_CBCR |

>  			GSC_OUT_YUV420_2P);

>  		break;

> -	default:

> -		dev_err(ippdrv->dev, "invalid target yuv order 0x%x.\n", fmt);

> -		return -EINVAL;

>  	}

>  

>  	gsc_write(cfg, GSC_OUT_CON);

> @@ -829,61 +722,6 @@ static int gsc_dst_set_fmt(struct device *dev, u32 fmt)

>  	return 0;

>  }

>  

> -static int gsc_dst_set_transf(struct device *dev,

> -		enum drm_exynos_degree degree,

> -		enum drm_exynos_flip flip, bool *swap)

> -{

> -	struct gsc_context *ctx = get_gsc_context(dev);

> -	struct exynos_drm_ippdrv *ippdrv = &ctx->ippdrv;

> -	u32 cfg;

> -

> -	DRM_DEBUG_KMS("degree[%d]flip[0x%x]\n", degree, flip);

> -

> -	cfg = gsc_read(GSC_IN_CON);

> -	cfg &= ~GSC_IN_ROT_MASK;

> -

> -	switch (degree) {

> -	case EXYNOS_DRM_DEGREE_0:

> -		if (flip & EXYNOS_DRM_FLIP_VERTICAL)

> -			cfg |= GSC_IN_ROT_XFLIP;

> -		if (flip & EXYNOS_DRM_FLIP_HORIZONTAL)

> -			cfg |= GSC_IN_ROT_YFLIP;

> -		break;

> -	case EXYNOS_DRM_DEGREE_90:

> -		if (flip & EXYNOS_DRM_FLIP_VERTICAL)

> -			cfg |= GSC_IN_ROT_90_XFLIP;

> -		else if (flip & EXYNOS_DRM_FLIP_HORIZONTAL)

> -			cfg |= GSC_IN_ROT_90_YFLIP;

> -		else

> -			cfg |= GSC_IN_ROT_90;

> -		break;

> -	case EXYNOS_DRM_DEGREE_180:

> -		cfg |= GSC_IN_ROT_180;

> -		if (flip & EXYNOS_DRM_FLIP_VERTICAL)

> -			cfg &= ~GSC_IN_ROT_XFLIP;

> -		if (flip & EXYNOS_DRM_FLIP_HORIZONTAL)

> -			cfg &= ~GSC_IN_ROT_YFLIP;

> -		break;

> -	case EXYNOS_DRM_DEGREE_270:

> -		cfg |= GSC_IN_ROT_270;

> -		if (flip & EXYNOS_DRM_FLIP_VERTICAL)

> -			cfg &= ~GSC_IN_ROT_XFLIP;

> -		if (flip & EXYNOS_DRM_FLIP_HORIZONTAL)

> -			cfg &= ~GSC_IN_ROT_YFLIP;

> -		break;

> -	default:

> -		dev_err(ippdrv->dev, "invalid degree value %d.\n", degree);

> -		return -EINVAL;

> -	}

> -

> -	gsc_write(cfg, GSC_IN_CON);

> -

> -	ctx->rotation = (cfg & GSC_IN_ROT_90) ? 1 : 0;

> -	*swap = ctx->rotation;

> -

> -	return 0;

> -}

> -

>  static int gsc_get_ratio_shift(u32 src, u32 dst, u32 *ratio)

>  {

>  	DRM_DEBUG_KMS("src[%d]dst[%d]\n", src, dst);

> @@ -919,9 +757,8 @@ static void gsc_get_prescaler_shfactor(u32 hratio, u32 vratio, u32 *shfactor)

>  }

>  

>  static int gsc_set_prescaler(struct gsc_context *ctx, struct gsc_scaler *sc,

> -		struct drm_exynos_pos *src, struct drm_exynos_pos *dst)

> +     struct drm_exynos_ipp_task_rect *src, struct drm_exynos_ipp_task_rect *dst)

>  {

> -	struct exynos_drm_ippdrv *ippdrv = &ctx->ippdrv;

>  	u32 cfg;

>  	u32 src_w, src_h, dst_w, dst_h;

>  	int ret = 0;

> @@ -939,13 +776,13 @@ static int gsc_set_prescaler(struct gsc_context *ctx, struct gsc_scaler *sc,

>  

>  	ret = gsc_get_ratio_shift(src_w, dst_w, &sc->pre_hratio);

>  	if (ret) {

> -		dev_err(ippdrv->dev, "failed to get ratio horizontal.\n");

> +		dev_err(ctx->dev, "failed to get ratio horizontal.\n");

>  		return ret;

>  	}

>  

>  	ret = gsc_get_ratio_shift(src_h, dst_h, &sc->pre_vratio);

>  	if (ret) {

> -		dev_err(ippdrv->dev, "failed to get ratio vertical.\n");

> +		dev_err(ctx->dev, "failed to get ratio vertical.\n");

>  		return ret;

>  	}

>  

> @@ -1039,47 +876,31 @@ static void gsc_set_scaler(struct gsc_context *ctx, struct gsc_scaler *sc)

>  	gsc_write(cfg, GSC_MAIN_V_RATIO);

>  }

>  

> -static int gsc_dst_set_size(struct device *dev, int swap,

> -		struct drm_exynos_pos *pos, struct drm_exynos_sz *sz)

> +static int gsc_dst_set_size(struct gsc_context *ctx,

> +			    struct exynos_drm_ipp_buffer *buf)

>  {

> -	struct gsc_context *ctx = get_gsc_context(dev);

> -	struct drm_exynos_pos img_pos = *pos;

>  	struct gsc_scaler *sc = &ctx->sc;

>  	u32 cfg;

>  

> -	DRM_DEBUG_KMS("swap[%d]x[%d]y[%d]w[%d]h[%d]\n",

> -		swap, pos->x, pos->y, pos->w, pos->h);

> -

> -	if (swap) {

> -		img_pos.w = pos->h;

> -		img_pos.h = pos->w;

> -	}

> -

>  	/* pixel offset */

> -	cfg = (GSC_DSTIMG_OFFSET_X(pos->x) |

> -		GSC_DSTIMG_OFFSET_Y(pos->y));

> +	cfg = (GSC_DSTIMG_OFFSET_X(buf->rect.x) |

> +		GSC_DSTIMG_OFFSET_Y(buf->rect.y));

>  	gsc_write(cfg, GSC_DSTIMG_OFFSET);

>  

>  	/* scaled size */

> -	cfg = (GSC_SCALED_WIDTH(img_pos.w) | GSC_SCALED_HEIGHT(img_pos.h));

> +	cfg = (GSC_SCALED_WIDTH(buf->rect.w) | GSC_SCALED_HEIGHT(buf->rect.h));

>  	gsc_write(cfg, GSC_SCALED_SIZE);

>  

> -	DRM_DEBUG_KMS("hsize[%d]vsize[%d]\n", sz->hsize, sz->vsize);

> -

>  	/* original size */

>  	cfg = gsc_read(GSC_DSTIMG_SIZE);

> -	cfg &= ~(GSC_DSTIMG_HEIGHT_MASK |

> -		GSC_DSTIMG_WIDTH_MASK);

> -	cfg |= (GSC_DSTIMG_WIDTH(sz->hsize) |

> -		GSC_DSTIMG_HEIGHT(sz->vsize));

> +	cfg &= ~(GSC_DSTIMG_HEIGHT_MASK | GSC_DSTIMG_WIDTH_MASK);

> +	cfg |= (GSC_DSTIMG_WIDTH(buf->buf.width) | GSC_DSTIMG_HEIGHT(buf->buf.height));

>  	gsc_write(cfg, GSC_DSTIMG_SIZE);

>  

>  	cfg = gsc_read(GSC_OUT_CON);

>  	cfg &= ~GSC_OUT_RGB_TYPE_MASK;

>  

> -	DRM_DEBUG_KMS("width[%d]range[%d]\n", pos->w, sc->range);

> -

> -	if (pos->w >= GSC_WIDTH_ITU_709)

> +	if (buf->rect.w >= GSC_WIDTH_ITU_709)

>  		if (sc->range)

>  			cfg |= GSC_OUT_RGB_HD_WIDE;

>  		else

> @@ -1112,34 +933,16 @@ static int gsc_dst_get_buf_seq(struct gsc_context *ctx)

>  }

>  

>  static int gsc_dst_set_buf_seq(struct gsc_context *ctx, u32 buf_id,

> -		enum drm_exynos_ipp_buf_type buf_type)

> +			       bool enqueue)

>  {

> -	struct exynos_drm_ippdrv *ippdrv = &ctx->ippdrv;

> -	bool masked;

> +	bool masked = !enqueue;

>  	u32 cfg;

>  	u32 mask = 0x00000001 << buf_id;

>  	int ret = 0;

>  

> -	DRM_DEBUG_KMS("buf_id[%d]buf_type[%d]\n", buf_id, buf_type);

> -

> -	mutex_lock(&ctx->lock);

> -

>  	/* mask register set */

>  	cfg = gsc_read(GSC_OUT_BASE_ADDR_Y_MASK);

>  

> -	switch (buf_type) {

> -	case IPP_BUF_ENQUEUE:

> -		masked = false;

> -		break;

> -	case IPP_BUF_DEQUEUE:

> -		masked = true;

> -		break;

> -	default:

> -		dev_err(ippdrv->dev, "invalid buf ctrl parameter.\n");

> -		ret =  -EINVAL;

> -		goto err_unlock;

> -	}

> -

>  	/* sequence id */

>  	cfg &= ~mask;

>  	cfg |= masked << buf_id;

> @@ -1148,87 +951,25 @@ static int gsc_dst_set_buf_seq(struct gsc_context *ctx, u32 buf_id,

>  	gsc_write(cfg, GSC_OUT_BASE_ADDR_CR_MASK);

>  

>  	/* interrupt enable */

> -	if (buf_type == IPP_BUF_ENQUEUE &&

> -	    gsc_dst_get_buf_seq(ctx) >= GSC_BUF_START)

> +	if (enqueue && gsc_dst_get_buf_seq(ctx) >= GSC_BUF_START)

>  		gsc_handle_irq(ctx, true, false, true);

>  

>  	/* interrupt disable */

> -	if (buf_type == IPP_BUF_DEQUEUE &&

> -	    gsc_dst_get_buf_seq(ctx) <= GSC_BUF_STOP)

> +	if (!enqueue && gsc_dst_get_buf_seq(ctx) <= GSC_BUF_STOP)

>  		gsc_handle_irq(ctx, false, false, true);

>  

> -err_unlock:

> -	mutex_unlock(&ctx->lock);

>  	return ret;

>  }

>  

> -static int gsc_dst_set_addr(struct device *dev,

> -		struct drm_exynos_ipp_buf_info *buf_info, u32 buf_id,

> -		enum drm_exynos_ipp_buf_type buf_type)

> +static int gsc_dst_set_addr(struct gsc_context *ctx,

> +		u32 buf_id, struct exynos_drm_ipp_buffer *buf)

>  {

> -	struct gsc_context *ctx = get_gsc_context(dev);

> -	struct exynos_drm_ippdrv *ippdrv = &ctx->ippdrv;

> -	struct drm_exynos_ipp_cmd_node *c_node = ippdrv->c_node;

> -	struct drm_exynos_ipp_property *property;

> -

> -	if (!c_node) {

> -		DRM_ERROR("failed to get c_node.\n");

> -		return -EFAULT;

> -	}

> -

> -	property = &c_node->property;

> -

> -	DRM_DEBUG_KMS("prop_id[%d]buf_id[%d]buf_type[%d]\n",

> -		property->prop_id, buf_id, buf_type);

> -

> -	if (buf_id > GSC_MAX_DST) {

> -		dev_info(ippdrv->dev, "invalid buf_id %d.\n", buf_id);

> -		return -EINVAL;

> -	}

> -

>  	/* address register set */

> -	switch (buf_type) {

> -	case IPP_BUF_ENQUEUE:

> -		gsc_write(buf_info->base[EXYNOS_DRM_PLANAR_Y],

> -			GSC_OUT_BASE_ADDR_Y(buf_id));

> -		gsc_write(buf_info->base[EXYNOS_DRM_PLANAR_CB],

> -			GSC_OUT_BASE_ADDR_CB(buf_id));

> -		gsc_write(buf_info->base[EXYNOS_DRM_PLANAR_CR],

> -			GSC_OUT_BASE_ADDR_CR(buf_id));

> -		break;

> -	case IPP_BUF_DEQUEUE:

> -		gsc_write(0x0, GSC_OUT_BASE_ADDR_Y(buf_id));

> -		gsc_write(0x0, GSC_OUT_BASE_ADDR_CB(buf_id));

> -		gsc_write(0x0, GSC_OUT_BASE_ADDR_CR(buf_id));

> -		break;

> -	default:

> -		/* bypass */

> -		break;

> -	}

> -

> -	return gsc_dst_set_buf_seq(ctx, buf_id, buf_type);

> -}

> -

> -static struct exynos_drm_ipp_ops gsc_dst_ops = {

> -	.set_fmt = gsc_dst_set_fmt,

> -	.set_transf = gsc_dst_set_transf,

> -	.set_size = gsc_dst_set_size,

> -	.set_addr = gsc_dst_set_addr,

> -};

> -

> -static int gsc_clk_ctrl(struct gsc_context *ctx, bool enable)

> -{

> -	DRM_DEBUG_KMS("enable[%d]\n", enable);

> +	gsc_write(buf->dma_addr[0], GSC_OUT_BASE_ADDR_Y(buf_id));

> +	gsc_write(buf->dma_addr[1], GSC_OUT_BASE_ADDR_CB(buf_id));

> +	gsc_write(buf->dma_addr[2], GSC_OUT_BASE_ADDR_CR(buf_id));

>  

> -	if (enable) {

> -		clk_prepare_enable(ctx->gsc_clk);

> -		ctx->suspended = false;

> -	} else {

> -		clk_disable_unprepare(ctx->gsc_clk);

> -		ctx->suspended = true;

> -	}

> -

> -	return 0;

> +	return gsc_dst_set_buf_seq(ctx, buf_id, true);

>  }

>  

>  static int gsc_get_src_buf_index(struct gsc_context *ctx)

> @@ -1249,20 +990,20 @@ static int gsc_get_src_buf_index(struct gsc_context *ctx)

>  		}

>  	}

>  

> +	DRM_DEBUG_KMS("cfg[0x%x]curr_index[%d]buf_id[%d]\n", cfg,

> +		curr_index, buf_id);

> +

>  	if (buf_id == GSC_MAX_SRC) {

>  		DRM_ERROR("failed to get in buffer index.\n");

>  		return -EINVAL;

>  	}

>  

> -	ret = gsc_src_set_buf_seq(ctx, buf_id, IPP_BUF_DEQUEUE);

> +	ret = gsc_src_set_buf_seq(ctx, buf_id, false);

>  	if (ret < 0) {

>  		DRM_ERROR("failed to dequeue.\n");

>  		return ret;

>  	}

>  

> -	DRM_DEBUG_KMS("cfg[0x%x]curr_index[%d]buf_id[%d]\n", cfg,

> -		curr_index, buf_id);

> -

>  	return buf_id;

>  }

>  

> @@ -1289,7 +1030,7 @@ static int gsc_get_dst_buf_index(struct gsc_context *ctx)

>  		return -EINVAL;

>  	}

>  

> -	ret = gsc_dst_set_buf_seq(ctx, buf_id, IPP_BUF_DEQUEUE);

> +	ret = gsc_dst_set_buf_seq(ctx, buf_id, false);

>  	if (ret < 0) {

>  		DRM_ERROR("failed to dequeue.\n");

>  		return ret;

> @@ -1304,215 +1045,55 @@ static int gsc_get_dst_buf_index(struct gsc_context *ctx)

>  static irqreturn_t gsc_irq_handler(int irq, void *dev_id)

>  {

>  	struct gsc_context *ctx = dev_id;

> -	struct exynos_drm_ippdrv *ippdrv = &ctx->ippdrv;

> -	struct drm_exynos_ipp_cmd_node *c_node = ippdrv->c_node;

> -	struct drm_exynos_ipp_event_work *event_work =

> -		c_node->event_work;

>  	u32 status;

> -	int buf_id[EXYNOS_DRM_OPS_MAX];

> +	int err = 0;

>  

>  	DRM_DEBUG_KMS("gsc id[%d]\n", ctx->id);

>  

>  	status = gsc_read(GSC_IRQ);

>  	if (status & GSC_IRQ_STATUS_OR_IRQ) {

> -		dev_err(ippdrv->dev, "occurred overflow at %d, status 0x%x.\n",

> +		dev_err(ctx->dev, "occurred overflow at %d, status 0x%x.\n",

>  			ctx->id, status);

> -		return IRQ_NONE;

> +		err = -EINVAL;

>  	}

>  

>  	if (status & GSC_IRQ_STATUS_OR_FRM_DONE) {

> -		dev_dbg(ippdrv->dev, "occurred frame done at %d, status 0x%x.\n",

> -			ctx->id, status);

> -

> -		buf_id[EXYNOS_DRM_OPS_SRC] = gsc_get_src_buf_index(ctx);

> -		if (buf_id[EXYNOS_DRM_OPS_SRC] < 0)

> -			return IRQ_HANDLED;

> -

> -		buf_id[EXYNOS_DRM_OPS_DST] = gsc_get_dst_buf_index(ctx);

> -		if (buf_id[EXYNOS_DRM_OPS_DST] < 0)

> -			return IRQ_HANDLED;

> +		int src_buf_id, dst_buf_id;

>  

> -		DRM_DEBUG_KMS("buf_id_src[%d]buf_id_dst[%d]\n",

> -			buf_id[EXYNOS_DRM_OPS_SRC], buf_id[EXYNOS_DRM_OPS_DST]);

> -

> -		event_work->ippdrv = ippdrv;

> -		event_work->buf_id[EXYNOS_DRM_OPS_SRC] =

> -			buf_id[EXYNOS_DRM_OPS_SRC];

> -		event_work->buf_id[EXYNOS_DRM_OPS_DST] =

> -			buf_id[EXYNOS_DRM_OPS_DST];

> -		queue_work(ippdrv->event_workq, &event_work->work);

> -	}

> -

> -	return IRQ_HANDLED;

> -}

> -

> -static int gsc_init_prop_list(struct exynos_drm_ippdrv *ippdrv)

> -{

> -	struct drm_exynos_ipp_prop_list *prop_list = &ippdrv->prop_list;

> -

> -	prop_list->version = 1;

> -	prop_list->writeback = 1;

> -	prop_list->refresh_min = GSC_REFRESH_MIN;

> -	prop_list->refresh_max = GSC_REFRESH_MAX;

> -	prop_list->flip = (1 << EXYNOS_DRM_FLIP_VERTICAL) |

> -				(1 << EXYNOS_DRM_FLIP_HORIZONTAL);

> -	prop_list->degree = (1 << EXYNOS_DRM_DEGREE_0) |

> -				(1 << EXYNOS_DRM_DEGREE_90) |

> -				(1 << EXYNOS_DRM_DEGREE_180) |

> -				(1 << EXYNOS_DRM_DEGREE_270);

> -	prop_list->csc = 1;

> -	prop_list->crop = 1;

> -	prop_list->crop_max.hsize = GSC_CROP_MAX;

> -	prop_list->crop_max.vsize = GSC_CROP_MAX;

> -	prop_list->crop_min.hsize = GSC_CROP_MIN;

> -	prop_list->crop_min.vsize = GSC_CROP_MIN;

> -	prop_list->scale = 1;

> -	prop_list->scale_max.hsize = GSC_SCALE_MAX;

> -	prop_list->scale_max.vsize = GSC_SCALE_MAX;

> -	prop_list->scale_min.hsize = GSC_SCALE_MIN;

> -	prop_list->scale_min.vsize = GSC_SCALE_MIN;

> -

> -	return 0;

> -}

> -

> -static inline bool gsc_check_drm_flip(enum drm_exynos_flip flip)

> -{

> -	switch (flip) {

> -	case EXYNOS_DRM_FLIP_NONE:

> -	case EXYNOS_DRM_FLIP_VERTICAL:

> -	case EXYNOS_DRM_FLIP_HORIZONTAL:

> -	case EXYNOS_DRM_FLIP_BOTH:

> -		return true;

> -	default:

> -		DRM_DEBUG_KMS("invalid flip\n");

> -		return false;

> -	}

> -}

> -

> -static int gsc_ippdrv_check_property(struct device *dev,

> -		struct drm_exynos_ipp_property *property)

> -{

> -	struct gsc_context *ctx = get_gsc_context(dev);

> -	struct exynos_drm_ippdrv *ippdrv = &ctx->ippdrv;

> -	struct drm_exynos_ipp_prop_list *pp = &ippdrv->prop_list;

> -	struct drm_exynos_ipp_config *config;

> -	struct drm_exynos_pos *pos;

> -	struct drm_exynos_sz *sz;

> -	bool swap;

> -	int i;

> -

> -	for_each_ipp_ops(i) {

> -		if ((i == EXYNOS_DRM_OPS_SRC) &&

> -			(property->cmd == IPP_CMD_WB))

> -			continue;

> -

> -		config = &property->config[i];

> -		pos = &config->pos;

> -		sz = &config->sz;

> -

> -		/* check for flip */

> -		if (!gsc_check_drm_flip(config->flip)) {

> -			DRM_ERROR("invalid flip.\n");

> -			goto err_property;

> -		}

> -

> -		/* check for degree */

> -		switch (config->degree) {

> -		case EXYNOS_DRM_DEGREE_90:

> -		case EXYNOS_DRM_DEGREE_270:

> -			swap = true;

> -			break;

> -		case EXYNOS_DRM_DEGREE_0:

> -		case EXYNOS_DRM_DEGREE_180:

> -			swap = false;

> -			break;

> -		default:

> -			DRM_ERROR("invalid degree.\n");

> -			goto err_property;

> -		}

> +		dev_dbg(ctx->dev, "occurred frame done at %d, status 0x%x.\n",

> +			ctx->id, status);

>  

> -		/* check for buffer bound */

> -		if ((pos->x + pos->w > sz->hsize) ||

> -			(pos->y + pos->h > sz->vsize)) {

> -			DRM_ERROR("out of buf bound.\n");

> -			goto err_property;

> -		}

> +		src_buf_id = gsc_get_src_buf_index(ctx);

> +		dst_buf_id = gsc_get_dst_buf_index(ctx);

>  

> -		/* check for crop */

> -		if ((i == EXYNOS_DRM_OPS_SRC) && (pp->crop)) {

> -			if (swap) {

> -				if ((pos->h < pp->crop_min.hsize) ||

> -					(sz->vsize > pp->crop_max.hsize) ||

> -					(pos->w < pp->crop_min.vsize) ||

> -					(sz->hsize > pp->crop_max.vsize)) {

> -					DRM_ERROR("out of crop size.\n");

> -					goto err_property;

> -				}

> -			} else {

> -				if ((pos->w < pp->crop_min.hsize) ||

> -					(sz->hsize > pp->crop_max.hsize) ||

> -					(pos->h < pp->crop_min.vsize) ||

> -					(sz->vsize > pp->crop_max.vsize)) {

> -					DRM_ERROR("out of crop size.\n");

> -					goto err_property;

> -				}

> -			}

> -		}

> +		DRM_DEBUG_KMS("buf_id_src[%d]buf_id_dst[%d]\n",	src_buf_id,

> +			      dst_buf_id);

>  

> -		/* check for scale */

> -		if ((i == EXYNOS_DRM_OPS_DST) && (pp->scale)) {

> -			if (swap) {

> -				if ((pos->h < pp->scale_min.hsize) ||

> -					(sz->vsize > pp->scale_max.hsize) ||

> -					(pos->w < pp->scale_min.vsize) ||

> -					(sz->hsize > pp->scale_max.vsize)) {

> -					DRM_ERROR("out of scale size.\n");

> -					goto err_property;

> -				}

> -			} else {

> -				if ((pos->w < pp->scale_min.hsize) ||

> -					(sz->hsize > pp->scale_max.hsize) ||

> -					(pos->h < pp->scale_min.vsize) ||

> -					(sz->vsize > pp->scale_max.vsize)) {

> -					DRM_ERROR("out of scale size.\n");

> -					goto err_property;

> -				}

> -			}

> -		}

> +		if (src_buf_id < 0 || dst_buf_id < 0)

> +			err = -EINVAL;

>  	}

>  

> -	return 0;

> -

> -err_property:

> -	for_each_ipp_ops(i) {

> -		if ((i == EXYNOS_DRM_OPS_SRC) &&

> -			(property->cmd == IPP_CMD_WB))

> -			continue;

> +	if (ctx->task) {

> +		struct exynos_drm_ipp_task *task = ctx->task;

>  

> -		config = &property->config[i];

> -		pos = &config->pos;

> -		sz = &config->sz;

> -

> -		DRM_ERROR("[%s]f[%d]r[%d]pos[%d %d %d %d]sz[%d %d]\n",

> -			i ? "dst" : "src", config->flip, config->degree,

> -			pos->x, pos->y, pos->w, pos->h,

> -			sz->hsize, sz->vsize);

> +		ctx->task = NULL;

> +		pm_runtime_mark_last_busy(ctx->dev);

> +		pm_runtime_put_autosuspend(ctx->dev);

> +		exynos_drm_ipp_task_done(task, err);

>  	}

>  

> -	return -EINVAL;

> +	return IRQ_HANDLED;

>  }

>  

> -

> -static int gsc_ippdrv_reset(struct device *dev)

> +static int gsc_reset(struct gsc_context *ctx)

>  {

> -	struct gsc_context *ctx = get_gsc_context(dev);

>  	struct gsc_scaler *sc = &ctx->sc;

>  	int ret;

>  

>  	/* reset h/w block */

>  	ret = gsc_sw_reset(ctx);

>  	if (ret < 0) {

> -		dev_err(dev, "failed to reset hardware.\n");

> +		dev_err(ctx->dev, "failed to reset hardware.\n");

>  		return ret;

>  	}

>  

> @@ -1523,96 +1104,29 @@ static int gsc_ippdrv_reset(struct device *dev)

>  	return 0;

>  }

>  

> -static int gsc_ippdrv_start(struct device *dev, enum drm_exynos_ipp_cmd cmd)

> +static int gsc_start(struct gsc_context *ctx)

>  {

> -	struct gsc_context *ctx = get_gsc_context(dev);

> -	struct exynos_drm_ippdrv *ippdrv = &ctx->ippdrv;

> -	struct drm_exynos_ipp_cmd_node *c_node = ippdrv->c_node;

> -	struct drm_exynos_ipp_property *property;

> -	struct drm_exynos_ipp_config *config;

> -	struct drm_exynos_pos	img_pos[EXYNOS_DRM_OPS_MAX];

> -	struct drm_exynos_ipp_set_wb set_wb;

>  	u32 cfg;

> -	int ret, i;

> -

> -	DRM_DEBUG_KMS("cmd[%d]\n", cmd);

> -

> -	if (!c_node) {

> -		DRM_ERROR("failed to get c_node.\n");

> -		return -EINVAL;

> -	}

> -

> -	property = &c_node->property;

>  

>  	gsc_handle_irq(ctx, true, false, true);

>  

> -	for_each_ipp_ops(i) {

> -		config = &property->config[i];

> -		img_pos[i] = config->pos;

> -	}

> +	/* enable one shot */

> +	cfg = gsc_read(GSC_ENABLE);

> +	cfg &= ~(GSC_ENABLE_ON_CLEAR_MASK |

> +		GSC_ENABLE_CLK_GATE_MODE_MASK);

> +	cfg |= GSC_ENABLE_ON_CLEAR_ONESHOT;

> +	gsc_write(cfg, GSC_ENABLE);

>  

> -	switch (cmd) {

> -	case IPP_CMD_M2M:

> -		/* enable one shot */

> -		cfg = gsc_read(GSC_ENABLE);

> -		cfg &= ~(GSC_ENABLE_ON_CLEAR_MASK |

> -			GSC_ENABLE_CLK_GATE_MODE_MASK);

> -		cfg |= GSC_ENABLE_ON_CLEAR_ONESHOT;

> -		gsc_write(cfg, GSC_ENABLE);

> -

> -		/* src dma memory */

> -		cfg = gsc_read(GSC_IN_CON);

> -		cfg &= ~(GSC_IN_PATH_MASK | GSC_IN_LOCAL_SEL_MASK);

> -		cfg |= GSC_IN_PATH_MEMORY;

> -		gsc_write(cfg, GSC_IN_CON);

> -

> -		/* dst dma memory */

> -		cfg = gsc_read(GSC_OUT_CON);

> -		cfg |= GSC_OUT_PATH_MEMORY;

> -		gsc_write(cfg, GSC_OUT_CON);

> -		break;

> -	case IPP_CMD_WB:

> -		set_wb.enable = 1;

> -		set_wb.refresh = property->refresh_rate;

> -		gsc_set_gscblk_fimd_wb(ctx, set_wb.enable);

> -		exynos_drm_ippnb_send_event(IPP_SET_WRITEBACK, (void *)&set_wb);

> -

> -		/* src local path */

> -		cfg = gsc_read(GSC_IN_CON);

> -		cfg &= ~(GSC_IN_PATH_MASK | GSC_IN_LOCAL_SEL_MASK);

> -		cfg |= (GSC_IN_PATH_LOCAL | GSC_IN_LOCAL_FIMD_WB);

> -		gsc_write(cfg, GSC_IN_CON);

> -

> -		/* dst dma memory */

> -		cfg = gsc_read(GSC_OUT_CON);

> -		cfg |= GSC_OUT_PATH_MEMORY;

> -		gsc_write(cfg, GSC_OUT_CON);

> -		break;

> -	case IPP_CMD_OUTPUT:

> -		/* src dma memory */

> -		cfg = gsc_read(GSC_IN_CON);

> -		cfg &= ~(GSC_IN_PATH_MASK | GSC_IN_LOCAL_SEL_MASK);

> -		cfg |= GSC_IN_PATH_MEMORY;

> -		gsc_write(cfg, GSC_IN_CON);

> -

> -		/* dst local path */

> -		cfg = gsc_read(GSC_OUT_CON);

> -		cfg |= GSC_OUT_PATH_MEMORY;

> -		gsc_write(cfg, GSC_OUT_CON);

> -		break;

> -	default:

> -		ret = -EINVAL;

> -		dev_err(dev, "invalid operations.\n");

> -		return ret;

> -	}

> +	/* src dma memory */

> +	cfg = gsc_read(GSC_IN_CON);

> +	cfg &= ~(GSC_IN_PATH_MASK | GSC_IN_LOCAL_SEL_MASK);

> +	cfg |= GSC_IN_PATH_MEMORY;

> +	gsc_write(cfg, GSC_IN_CON);

>  

> -	ret = gsc_set_prescaler(ctx, &ctx->sc,

> -		&img_pos[EXYNOS_DRM_OPS_SRC],

> -		&img_pos[EXYNOS_DRM_OPS_DST]);

> -	if (ret) {

> -		dev_err(dev, "failed to set prescaler.\n");

> -		return ret;

> -	}

> +	/* dst dma memory */

> +	cfg = gsc_read(GSC_OUT_CON);

> +	cfg |= GSC_OUT_PATH_MEMORY;

> +	gsc_write(cfg, GSC_OUT_CON);

>  

>  	gsc_set_scaler(ctx, &ctx->sc);

>  

> @@ -1623,66 +1137,132 @@ static int gsc_ippdrv_start(struct device *dev, enum drm_exynos_ipp_cmd cmd)

>  	return 0;

>  }

>  

> -static void gsc_ippdrv_stop(struct device *dev, enum drm_exynos_ipp_cmd cmd)

> +static int gsc_commit(struct exynos_drm_ipp *ipp,

> +			  struct exynos_drm_ipp_task *task)

>  {

> -	struct gsc_context *ctx = get_gsc_context(dev);

> -	struct drm_exynos_ipp_set_wb set_wb = {0, 0};

> -	u32 cfg;

> +	struct gsc_context *ctx = container_of(ipp, struct gsc_context, ipp);

> +

> +	pm_runtime_get_sync(ctx->dev);

> +	ctx->task = task;

> +

> +	gsc_reset(ctx);

> +	gsc_src_set_fmt(ctx, task->src.buf.fourcc);

> +	gsc_src_set_transf(ctx, task->transform.rotation);

> +	gsc_src_set_size(ctx, &task->src);

> +	gsc_src_set_addr(ctx, 0, &task->src);

> +	gsc_dst_set_fmt(ctx, task->dst.buf.fourcc);

> +	gsc_dst_set_size(ctx, &task->dst);

> +	gsc_dst_set_addr(ctx, 0, &task->dst);

> +	gsc_set_prescaler(ctx, &ctx->sc, &task->src.rect, &task->dst.rect);

> +	gsc_start(ctx);

>  

> -	DRM_DEBUG_KMS("cmd[%d]\n", cmd);

> +	return 0;

> +}

>  

> -	switch (cmd) {

> -	case IPP_CMD_M2M:

> -		/* bypass */

> -		break;

> -	case IPP_CMD_WB:

> -		gsc_set_gscblk_fimd_wb(ctx, set_wb.enable);

> -		exynos_drm_ippnb_send_event(IPP_SET_WRITEBACK, (void *)&set_wb);

> -		break;

> -	case IPP_CMD_OUTPUT:

> -	default:

> -		dev_err(dev, "invalid operations.\n");

> -		break;

> +static void gsc_abort(struct exynos_drm_ipp *ipp,

> +			  struct exynos_drm_ipp_task *task)

> +{

> +	struct gsc_context *ctx =

> +			container_of(ipp, struct gsc_context, ipp);

> +

> +	gsc_reset(ctx);

> +	if (ctx->task) {

> +		struct exynos_drm_ipp_task *task = ctx->task;

> +

> +		ctx->task = NULL;

> +		pm_runtime_mark_last_busy(ctx->dev);

> +		pm_runtime_put_autosuspend(ctx->dev);

> +		exynos_drm_ipp_task_done(task, -EIO);

>  	}

> +}

>  

> -	gsc_handle_irq(ctx, false, false, true);

> +static struct exynos_drm_ipp_funcs ipp_funcs = {

> +	.commit = gsc_commit,

> +	.abort = gsc_abort,

> +};

>  

> -	/* reset sequence */

> -	gsc_write(0xff, GSC_OUT_BASE_ADDR_Y_MASK);

> -	gsc_write(0xff, GSC_OUT_BASE_ADDR_CB_MASK);

> -	gsc_write(0xff, GSC_OUT_BASE_ADDR_CR_MASK);

> +static int gsc_bind(struct device *dev, struct device *master, void *data)

> +{

> +	struct gsc_context *ctx = dev_get_drvdata(dev);

> +	struct drm_device *drm_dev = data;

> +	struct exynos_drm_ipp *ipp = &ctx->ipp;

>  

> -	cfg = gsc_read(GSC_ENABLE);

> -	cfg &= ~GSC_ENABLE_ON;

> -	gsc_write(cfg, GSC_ENABLE);

> +	ctx->drm_dev = drm_dev;

> +	drm_iommu_attach_device(drm_dev, dev);

> +

> +	exynos_drm_ipp_register(drm_dev, ipp, &ipp_funcs,

> +			   DRM_EXYNOS_IPP_CAP_CROP | DRM_EXYNOS_IPP_CAP_ROTATE |

> +			   DRM_EXYNOS_IPP_CAP_SCALE | DRM_EXYNOS_IPP_CAP_CONVERT,

> +			   ctx->formats, "gsc");

> +

> +	dev_info(dev, "The exynos gscaler is probed successfully\n");

> +

> +	return 0;

> +}

> +

> +static void gsc_unbind(struct device *dev, struct device *master,

> +			void *data)

> +{

> +	struct gsc_context *ctx = dev_get_drvdata(dev);

> +	struct drm_device *drm_dev = data;

> +	struct exynos_drm_ipp *ipp = &ctx->ipp;

> +

> +	exynos_drm_ipp_unregister(drm_dev, ipp);

> +	drm_iommu_detach_device(drm_dev, dev);

>  }

>  

> +static const struct component_ops gsc_component_ops = {

> +	.bind	= gsc_bind,

> +	.unbind = gsc_unbind,

> +};

> +

> +static const unsigned int gsc_formats[] = {

> +	DRM_FORMAT_XRGB8888, DRM_FORMAT_RGB565, DRM_FORMAT_BGRX8888,

> +	DRM_FORMAT_NV12, DRM_FORMAT_NV16, DRM_FORMAT_NV21, DRM_FORMAT_NV61,

> +	DRM_FORMAT_UYVY, DRM_FORMAT_VYUY, DRM_FORMAT_YUYV, DRM_FORMAT_YVYU,

> +	DRM_FORMAT_YUV420, DRM_FORMAT_YVU420, DRM_FORMAT_YUV422,

> +};

> +

>  static int gsc_probe(struct platform_device *pdev)

>  {

>  	struct device *dev = &pdev->dev;

> +	struct gsc_driverdata *driver_data;

> +	struct exynos_drm_ipp_formats *formats;

>  	struct gsc_context *ctx;

>  	struct resource *res;

> -	struct exynos_drm_ippdrv *ippdrv;

> -	int ret;

> +	int ret, i;

>  

>  	ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);

>  	if (!ctx)

>  		return -ENOMEM;

>  

> -	if (dev->of_node) {

> -		ctx->sysreg = syscon_regmap_lookup_by_phandle(dev->of_node,

> -							"samsung,sysreg");

> -		if (IS_ERR(ctx->sysreg)) {

> -			dev_warn(dev, "failed to get system register.\n");

> -			ctx->sysreg = NULL;

> -		}

> +	formats = devm_kzalloc(dev, sizeof(*formats) *

> +			       (ARRAY_SIZE(gsc_formats) + 1), GFP_KERNEL);

> +	if (!formats)

> +		return -ENOMEM;

> +

> +

> +	driver_data = (struct gsc_driverdata *)of_device_get_match_data(dev);

> +	ctx->dev = dev;

> +	ctx->num_clocks = driver_data->num_clocks;

> +	ctx->clk_names = driver_data->clk_names;

> +

> +	for (i = 0; i < ARRAY_SIZE(gsc_formats); i++) {

> +		formats[i].fourcc = gsc_formats[i];

> +		formats[i].type = DRM_EXYNOS_IPP_FORMAT_SOURCE |

> +				  DRM_EXYNOS_IPP_FORMAT_DESTINATION;

> +		formats[i].limits = driver_data->limits;

>  	}

> +	ctx->formats = formats;

>  

>  	/* clock control */

> -	ctx->gsc_clk = devm_clk_get(dev, "gscl");

> -	if (IS_ERR(ctx->gsc_clk)) {

> -		dev_err(dev, "failed to get gsc clock.\n");

> -		return PTR_ERR(ctx->gsc_clk);

> +	for (i = 0; i < ctx->num_clocks; i++) {

> +		ctx->clocks[i] = devm_clk_get(dev, ctx->clk_names[i]);

> +		if (IS_ERR(ctx->clocks[i])) {

> +			dev_err(dev, "failed to get clock: %s\n",

> +				ctx->clk_names[i]);

> +			return PTR_ERR(ctx->clocks[i]);

> +		}

>  	}

>  

>  	/* resource memory */

> @@ -1699,8 +1279,8 @@ static int gsc_probe(struct platform_device *pdev)

>  	}

>  

>  	ctx->irq = res->start;

> -	ret = devm_request_threaded_irq(dev, ctx->irq, NULL, gsc_irq_handler,

> -		IRQF_ONESHOT, "drm_gsc", ctx);

> +	ret = devm_request_irq(dev, ctx->irq, gsc_irq_handler, 0,

> +			       dev_name(dev), ctx);

>  	if (ret < 0) {

>  		dev_err(dev, "failed to request irq.\n");

>  		return ret;

> @@ -1709,38 +1289,22 @@ static int gsc_probe(struct platform_device *pdev)

>  	/* context initailization */

>  	ctx->id = pdev->id;

>  

> -	ippdrv = &ctx->ippdrv;

> -	ippdrv->dev = dev;

> -	ippdrv->ops[EXYNOS_DRM_OPS_SRC] = &gsc_src_ops;

> -	ippdrv->ops[EXYNOS_DRM_OPS_DST] = &gsc_dst_ops;

> -	ippdrv->check_property = gsc_ippdrv_check_property;

> -	ippdrv->reset = gsc_ippdrv_reset;

> -	ippdrv->start = gsc_ippdrv_start;

> -	ippdrv->stop = gsc_ippdrv_stop;

> -	ret = gsc_init_prop_list(ippdrv);

> -	if (ret < 0) {

> -		dev_err(dev, "failed to init property list.\n");

> -		return ret;

> -	}

> -

> -	DRM_DEBUG_KMS("id[%d]ippdrv[%pK]\n", ctx->id, ippdrv);

> -

> -	mutex_init(&ctx->lock);

>  	platform_set_drvdata(pdev, ctx);

>  

> +	pm_runtime_use_autosuspend(dev);

> +	pm_runtime_set_autosuspend_delay(dev, GSC_AUTOSUSPEND_DELAY);

>  	pm_runtime_enable(dev);

>  

> -	ret = exynos_drm_ippdrv_register(ippdrv);

> -	if (ret < 0) {

> -		dev_err(dev, "failed to register drm gsc device.\n");

> -		goto err_ippdrv_register;

> -	}

> +	ret = component_add(dev, &gsc_component_ops);

> +	if (ret)

> +		goto err_pm_dis;

>  

>  	dev_info(dev, "drm gsc registered successfully.\n");

>  

>  	return 0;

>  

> -err_ippdrv_register:

> +err_pm_dis:

> +	pm_runtime_dont_use_autosuspend(dev);

>  	pm_runtime_disable(dev);

>  	return ret;

>  }

> @@ -1748,13 +1312,8 @@ static int gsc_probe(struct platform_device *pdev)

>  static int gsc_remove(struct platform_device *pdev)

>  {

>  	struct device *dev = &pdev->dev;

> -	struct gsc_context *ctx = get_gsc_context(dev);

> -	struct exynos_drm_ippdrv *ippdrv = &ctx->ippdrv;

> -

> -	exynos_drm_ippdrv_unregister(ippdrv);

> -	mutex_destroy(&ctx->lock);

>  

> -	pm_runtime_set_suspended(dev);

> +	pm_runtime_dont_use_autosuspend(dev);

>  	pm_runtime_disable(dev);

>  

>  	return 0;

> @@ -1763,19 +1322,32 @@ static int gsc_remove(struct platform_device *pdev)

>  static int __maybe_unused gsc_runtime_suspend(struct device *dev)

>  {

>  	struct gsc_context *ctx = get_gsc_context(dev);

> +	int i;

>  

>  	DRM_DEBUG_KMS("id[%d]\n", ctx->id);

>  

> -	return  gsc_clk_ctrl(ctx, false);

> +	for (i = ctx->num_clocks - 1; i >= 0; i--)

> +		clk_disable_unprepare(ctx->clocks[i]);

> +

> +	return 0;

>  }

>  

>  static int __maybe_unused gsc_runtime_resume(struct device *dev)

>  {

>  	struct gsc_context *ctx = get_gsc_context(dev);

> +	int i;

>  

>  	DRM_DEBUG_KMS("id[%d]\n", ctx->id);

>  

> -	return  gsc_clk_ctrl(ctx, true);

> +	for (i = 0; i < ctx->num_clocks; i++) {

> +		int ret = clk_prepare_enable(ctx->clocks[i]);

> +		if (ret) {

> +			while (--i > 0)

> +				clk_disable_unprepare(ctx->clocks[i]);

> +			return ret;

> +		}

> +	}

> +	return 0;

>  }

>  

>  static const struct dev_pm_ops gsc_pm_ops = {

> @@ -1784,9 +1356,66 @@ static const struct dev_pm_ops gsc_pm_ops = {

>  	SET_RUNTIME_PM_OPS(gsc_runtime_suspend, gsc_runtime_resume, NULL)

>  };

>  

> +static const struct drm_exynos_ipp_limit gsc_5250_limits[] = {

> +	{ IPP_SIZE_LIMIT(BUFFER, .h = {32, 4800, 16}, .v = {16, 3344, 16}) },

> +	{ IPP_SIZE_LIMIT(AREA, .h = {16, 4800, 2}, .v = {8, 3344, 2}) },

> +	{ IPP_SIZE_LIMIT(ROTATED, .h = {32, 2048}, .v = {16, 2048}) },

> +	{ IPP_SCALE_LIMIT(.h = { (1 << 16) / 16, (1 << 16) * 8},

> +			  .v = { (1 << 16) / 16, (1 << 16) * 8}) },

> +	{ }

> +};

> +

> +static const struct drm_exynos_ipp_limit gsc_5420_limits[] = {

> +	{ IPP_SIZE_LIMIT(BUFFER, .h = {32, 4800, 16}, .v = {16, 3344, 16}) },

> +	{ IPP_SIZE_LIMIT(AREA, .h = {16, 4800, 2}, .v = {8, 3344, 2}) },

> +	{ IPP_SIZE_LIMIT(ROTATED, .h = {16, 2016}, .v = {8, 2016}) },

> +	{ IPP_SCALE_LIMIT(.h = { (1 << 16) / 16, (1 << 16) * 8},

> +			  .v = { (1 << 16) / 16, (1 << 16) * 8}) },

> +	{ }

> +};

> +

> +static const struct drm_exynos_ipp_limit gsc_5433_limits[] = {

> +	{ IPP_SIZE_LIMIT(BUFFER, .h = {32, 8191, 16}, .v = {16, 8191, 16}) },

> +	{ IPP_SIZE_LIMIT(AREA, .h = {16, 4800, 2}, .v = {8, 3344, 2}) },

> +	{ IPP_SIZE_LIMIT(ROTATED, .h = {16, 2047}, .v = {8, 2047}) },

> +	{ IPP_SCALE_LIMIT(.h = { (1 << 16) / 16, (1 << 16) * 8},

> +			  .v = { (1 << 16) / 16, (1 << 16) * 8}) },

> +	{ }

> +};

> +

> +static struct gsc_driverdata gsc_exynos5250_drvdata = {

> +	.clk_names = {"gscl"},

> +	.num_clocks = 1,

> +	.limits = gsc_5250_limits,

> +};

> +

> +static struct gsc_driverdata gsc_exynos5420_drvdata = {

> +	.clk_names = {"gscl"},

> +	.num_clocks = 1,

> +	.limits = gsc_5420_limits,

> +};

> +

> +static struct gsc_driverdata gsc_exynos5433_drvdata = {

> +	.clk_names = {"pclk", "aclk", "aclk_xiu", "aclk_gsclbend"},

> +	.num_clocks = 4,

> +	.limits = gsc_5433_limits,

> +};

> +

>  static const struct of_device_id exynos_drm_gsc_of_match[] = {

> -	{ .compatible = "samsung,exynos5-gsc" },

> -	{ },

> +	{

> +		.compatible = "samsung,exynos5-gsc",

> +		.data = &gsc_exynos5250_drvdata,

> +	}, {

> +		.compatible = "samsung,exynos5250-gsc",

> +		.data = &gsc_exynos5250_drvdata,

> +	}, {

> +		.compatible = "samsung,exynos5420-gsc",

> +		.data = &gsc_exynos5420_drvdata,

> +	}, {

> +		.compatible = "samsung,exynos5433-gsc",

> +		.data = &gsc_exynos5433_drvdata,

> +	}, {

> +	},

>  };

>  MODULE_DEVICE_TABLE(of, exynos_drm_gsc_of_match);

>  

> diff --git a/drivers/gpu/drm/exynos/exynos_drm_gsc.h b/drivers/gpu/drm/exynos/exynos_drm_gsc.h

> deleted file mode 100644

> index 29ec1c5efcf2..000000000000

> --- a/drivers/gpu/drm/exynos/exynos_drm_gsc.h

> +++ /dev/null

> @@ -1,24 +0,0 @@

> -/*

> - * Copyright (c) 2012 Samsung Electronics Co., Ltd.

> - *

> - * Authors:

> - *	Eunchul Kim <chulspro.kim@samsung.com>

> - *	Jinyoung Jeon <jy0.jeon@samsung.com>

> - *	Sangmin Lee <lsmin.lee@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.

> - */

> -

> -#ifndef _EXYNOS_DRM_GSC_H_

> -#define _EXYNOS_DRM_GSC_H_

> -

> -/*

> - * TODO

> - * FIMD output interface notifier callback.

> - * Mixer output interface notifier callback.

> - */

> -

> -#endif /* _EXYNOS_DRM_GSC_H_ */

> 


--
To unsubscribe from this list: send the line "unsubscribe linux-samsung-soc" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Rob Herring (Arm) Oct. 24, 2017, 12:39 a.m. UTC | #4
On Tue, Oct 17, 2017 at 01:07:50PM +0200, Marek Szyprowski wrote:
> From: Andrzej Pietrasiewicz <andrzej.p@samsung.com>

> 

> Exynos Scaler is a hardware module, which processes graphic data fetched

> from memory and transfers the resultant dato another memory buffer.

> Graphics data can be up/down-scaled, rotated, flipped and converted color

> space. Scaler hardware modules are a part of Exynos5420 and newer Exynos

> SoCs.

> 

> Signed-off-by: Andrzej Pietrasiewicz <andrzej.p@samsung.com>

> Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com>

> ---

>  .../devicetree/bindings/gpu/samsung-scaler.txt     |  26 +


In the future, please split bindings to separate patches.

Acked-by: Rob Herring <robh@kernel.org>


>  drivers/gpu/drm/exynos/Kconfig                     |   6 +

>  drivers/gpu/drm/exynos/Makefile                    |   1 +

>  drivers/gpu/drm/exynos/exynos_drm_drv.c            |   3 +

>  drivers/gpu/drm/exynos/exynos_drm_drv.h            |   1 +

>  drivers/gpu/drm/exynos/exynos_drm_ipp.h            |   4 +

>  drivers/gpu/drm/exynos/exynos_drm_scaler.c         | 717 +++++++++++++++++++++

>  drivers/gpu/drm/exynos/regs-scaler.h               | 426 ++++++++++++

>  8 files changed, 1184 insertions(+)

>  create mode 100644 Documentation/devicetree/bindings/gpu/samsung-scaler.txt

>  create mode 100644 drivers/gpu/drm/exynos/exynos_drm_scaler.c

>  create mode 100644 drivers/gpu/drm/exynos/regs-scaler.h

--
To unsubscribe from this list: send the line "unsubscribe linux-samsung-soc" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html