Commit d7f1642c authored by Joonyoung Shim's avatar Joonyoung Shim Committed by Inki Dae

drm/exynos: add G2D driver

Changelog v3:
- use __u64 instead of pointer in ioctl struct.

The G2D is a 2D graphic accelerator that supports Bit Block Transfer.
This G2D driver is exynos drm specific and supports only G2D(version
4.1) of later Exynos series from Exynos4X12 because supporting DMA.

The G2D is performed by two tasks simply.
1. Configures the rendering parameters, such as foreground color and
   coordinates data by setting the drawing context registers.
2. Start the rendering process by setting thre relevant command
   registers accordingly.

The G2D version 4.1 supports DMA mode as host interface. User can make
command list to reduce HOST(ARM) loads. The contents of The command list
is setted to relevant registers of G2D by DMA.

The command list is composed Header and command sets and Tail.
- Header: The number of command set(4Bytes)
- Command set: Register offset(4Bytes) + Register data(4Bytes)
- Tail: Pointer of base address of the other command list(4Bytes)

By Tail field, the G2D can process many command lists without halt at
one go.

The G2D has following the rendering pipeline.
--> Primitive Drawing --> Rotation --> Clipping --> Bilinear Sampling
--> Color Key --> ROP --> Mask Operation --> Alpha Blending -->
Dithering --> FrameBuffer

And supports various operations from the rendering pipeline.
- copy
- fast solid color fill
- window clipping
- rotation
- flip
- 4 operand raster operation(ROP4)
- masking operation
- alpha blending
- color key
- dithering
- etc

User should make the command list to data and registers needed by
operation to use. The Exynos G2D driver only manages the command lists
received from user. Some registers needs memory base address(physical
address) of image. User doesn't know its physical address, so fills the
gem handle of that memory than address to command sets, then G2D driver
converts it to memory base address.

We adds three ioctls and one event for Exynos G2D.

- ioctls
DRM_EXYNOS_G2D_GET_VER: get the G2D hardware version
DRM_EXYNOS_G2D_SET_CMDLIST: set the command list from user to driver
DRM_EXYNOS_G2D_EXEC: execute the command lists setted to driver

- event
DRM_EXYNOS_G2D_EVENT: event to give notification completion of the
		      command list to user
Signed-off-by: default avatarJoonyoung Shim <jy0922.shim@samsung.com>
Signed-off-by: default avatarInki Dae <inki.dae@samsung.com>
Signed-off-by: default avatarKyungmin Park <kyungmin.park@samsung.com>
parent 8dcb96b6
...@@ -33,3 +33,9 @@ config DRM_EXYNOS_VIDI ...@@ -33,3 +33,9 @@ config DRM_EXYNOS_VIDI
depends on DRM_EXYNOS depends on DRM_EXYNOS
help help
Choose this option if you want to use Exynos VIDI for DRM. Choose this option if you want to use Exynos VIDI for DRM.
config DRM_EXYNOS_G2D
bool "Exynos DRM G2D"
depends on DRM_EXYNOS
help
Choose this option if you want to use Exynos G2D for DRM.
...@@ -14,5 +14,6 @@ exynosdrm-$(CONFIG_DRM_EXYNOS_HDMI) += exynos_hdmi.o exynos_mixer.o \ ...@@ -14,5 +14,6 @@ exynosdrm-$(CONFIG_DRM_EXYNOS_HDMI) += exynos_hdmi.o exynos_mixer.o \
exynos_ddc.o exynos_hdmiphy.o \ exynos_ddc.o exynos_hdmiphy.o \
exynos_drm_hdmi.o exynos_drm_hdmi.o
exynosdrm-$(CONFIG_DRM_EXYNOS_VIDI) += exynos_drm_vidi.o exynosdrm-$(CONFIG_DRM_EXYNOS_VIDI) += exynos_drm_vidi.o
exynosdrm-$(CONFIG_DRM_EXYNOS_G2D) += exynos_drm_g2d.o
obj-$(CONFIG_DRM_EXYNOS) += exynosdrm.o obj-$(CONFIG_DRM_EXYNOS) += exynosdrm.o
...@@ -40,6 +40,7 @@ ...@@ -40,6 +40,7 @@
#include "exynos_drm_plane.h" #include "exynos_drm_plane.h"
#include "exynos_drm_vidi.h" #include "exynos_drm_vidi.h"
#include "exynos_drm_dmabuf.h" #include "exynos_drm_dmabuf.h"
#include "exynos_drm_g2d.h"
#define DRIVER_NAME "exynos" #define DRIVER_NAME "exynos"
#define DRIVER_DESC "Samsung SoC DRM" #define DRIVER_DESC "Samsung SoC DRM"
...@@ -148,9 +149,16 @@ static int exynos_drm_unload(struct drm_device *dev) ...@@ -148,9 +149,16 @@ static int exynos_drm_unload(struct drm_device *dev)
static int exynos_drm_open(struct drm_device *dev, struct drm_file *file) static int exynos_drm_open(struct drm_device *dev, struct drm_file *file)
{ {
struct drm_exynos_file_private *file_priv;
DRM_DEBUG_DRIVER("%s\n", __FILE__); DRM_DEBUG_DRIVER("%s\n", __FILE__);
file_priv = kzalloc(sizeof(*file_priv), GFP_KERNEL);
if (!file_priv)
return -ENOMEM;
drm_prime_init_file_private(&file->prime); drm_prime_init_file_private(&file->prime);
file->driver_priv = file_priv;
return exynos_drm_subdrv_open(dev, file); return exynos_drm_subdrv_open(dev, file);
} }
...@@ -217,6 +225,12 @@ static struct drm_ioctl_desc exynos_ioctls[] = { ...@@ -217,6 +225,12 @@ static struct drm_ioctl_desc exynos_ioctls[] = {
DRM_UNLOCKED | DRM_AUTH), DRM_UNLOCKED | DRM_AUTH),
DRM_IOCTL_DEF_DRV(EXYNOS_VIDI_CONNECTION, DRM_IOCTL_DEF_DRV(EXYNOS_VIDI_CONNECTION,
vidi_connection_ioctl, DRM_UNLOCKED | DRM_AUTH), vidi_connection_ioctl, DRM_UNLOCKED | DRM_AUTH),
DRM_IOCTL_DEF_DRV(EXYNOS_G2D_GET_VER,
exynos_g2d_get_ver_ioctl, DRM_UNLOCKED | DRM_AUTH),
DRM_IOCTL_DEF_DRV(EXYNOS_G2D_SET_CMDLIST,
exynos_g2d_set_cmdlist_ioctl, DRM_UNLOCKED | DRM_AUTH),
DRM_IOCTL_DEF_DRV(EXYNOS_G2D_EXEC,
exynos_g2d_exec_ioctl, DRM_UNLOCKED | DRM_AUTH),
}; };
static const struct file_operations exynos_drm_driver_fops = { static const struct file_operations exynos_drm_driver_fops = {
...@@ -317,6 +331,12 @@ static int __init exynos_drm_init(void) ...@@ -317,6 +331,12 @@ static int __init exynos_drm_init(void)
goto out_vidi; goto out_vidi;
#endif #endif
#ifdef CONFIG_DRM_EXYNOS_G2D
ret = platform_driver_register(&g2d_driver);
if (ret < 0)
goto out_g2d;
#endif
ret = platform_driver_register(&exynos_drm_platform_driver); ret = platform_driver_register(&exynos_drm_platform_driver);
if (ret < 0) if (ret < 0)
goto out; goto out;
...@@ -324,6 +344,11 @@ static int __init exynos_drm_init(void) ...@@ -324,6 +344,11 @@ static int __init exynos_drm_init(void)
return 0; return 0;
out: out:
#ifdef CONFIG_DRM_EXYNOS_G2D
platform_driver_unregister(&g2d_driver);
out_g2d:
#endif
#ifdef CONFIG_DRM_EXYNOS_VIDI #ifdef CONFIG_DRM_EXYNOS_VIDI
out_vidi: out_vidi:
platform_driver_unregister(&vidi_driver); platform_driver_unregister(&vidi_driver);
...@@ -351,6 +376,10 @@ static void __exit exynos_drm_exit(void) ...@@ -351,6 +376,10 @@ static void __exit exynos_drm_exit(void)
platform_driver_unregister(&exynos_drm_platform_driver); platform_driver_unregister(&exynos_drm_platform_driver);
#ifdef CONFIG_DRM_EXYNOS_G2D
platform_driver_unregister(&g2d_driver);
#endif
#ifdef CONFIG_DRM_EXYNOS_HDMI #ifdef CONFIG_DRM_EXYNOS_HDMI
platform_driver_unregister(&exynos_drm_common_hdmi_driver); platform_driver_unregister(&exynos_drm_common_hdmi_driver);
platform_driver_unregister(&mixer_driver); platform_driver_unregister(&mixer_driver);
......
...@@ -209,6 +209,18 @@ struct exynos_drm_manager { ...@@ -209,6 +209,18 @@ struct exynos_drm_manager {
struct exynos_drm_display_ops *display_ops; struct exynos_drm_display_ops *display_ops;
}; };
struct exynos_drm_g2d_private {
struct device *dev;
struct list_head inuse_cmdlist;
struct list_head event_list;
struct list_head gem_list;
unsigned int gem_nr;
};
struct drm_exynos_file_private {
struct exynos_drm_g2d_private *g2d_priv;
};
/* /*
* Exynos drm private structure. * Exynos drm private structure.
*/ */
...@@ -291,4 +303,5 @@ extern struct platform_driver hdmi_driver; ...@@ -291,4 +303,5 @@ extern struct platform_driver hdmi_driver;
extern struct platform_driver mixer_driver; extern struct platform_driver mixer_driver;
extern struct platform_driver exynos_drm_common_hdmi_driver; extern struct platform_driver exynos_drm_common_hdmi_driver;
extern struct platform_driver vidi_driver; extern struct platform_driver vidi_driver;
extern struct platform_driver g2d_driver;
#endif #endif
This diff is collapsed.
/*
* Copyright (C) 2012 Samsung Electronics Co.Ltd
* Authors: Joonyoung Shim <jy0922.shim@samsung.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundationr
*/
#ifdef CONFIG_DRM_EXYNOS_G2D
extern int exynos_g2d_get_ver_ioctl(struct drm_device *dev, void *data,
struct drm_file *file_priv);
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);
#else
static inline int exynos_g2d_get_ver_ioctl(struct drm_device *dev, void *data,
struct drm_file *file_priv)
{
return -ENODEV;
}
static inline int exynos_g2d_set_cmdlist_ioctl(struct drm_device *dev,
void *data,
struct drm_file *file_priv)
{
return -ENODEV;
}
static inline int exynos_g2d_exec_ioctl(struct drm_device *dev, void *data,
struct drm_file *file_priv)
{
return -ENODEV;
}
#endif
...@@ -29,6 +29,8 @@ ...@@ -29,6 +29,8 @@
#ifndef _EXYNOS_DRM_H_ #ifndef _EXYNOS_DRM_H_
#define _EXYNOS_DRM_H_ #define _EXYNOS_DRM_H_
#include "drm.h"
/** /**
* User-desired buffer creation information structure. * User-desired buffer creation information structure.
* *
...@@ -124,6 +126,37 @@ enum e_drm_exynos_gem_mem_type { ...@@ -124,6 +126,37 @@ enum e_drm_exynos_gem_mem_type {
EXYNOS_BO_WC EXYNOS_BO_WC
}; };
struct drm_exynos_g2d_get_ver {
__u32 major;
__u32 minor;
};
struct drm_exynos_g2d_cmd {
__u32 offset;
__u32 data;
};
enum drm_exynos_g2d_event_type {
G2D_EVENT_NOT,
G2D_EVENT_NONSTOP,
G2D_EVENT_STOP, /* not yet */
};
struct drm_exynos_g2d_set_cmdlist {
__u64 cmd;
__u64 cmd_gem;
__u32 cmd_nr;
__u32 cmd_gem_nr;
/* for g2d event */
__u64 event_type;
__u64 user_data;
};
struct drm_exynos_g2d_exec {
__u64 async;
};
#define DRM_EXYNOS_GEM_CREATE 0x00 #define DRM_EXYNOS_GEM_CREATE 0x00
#define DRM_EXYNOS_GEM_MAP_OFFSET 0x01 #define DRM_EXYNOS_GEM_MAP_OFFSET 0x01
#define DRM_EXYNOS_GEM_MMAP 0x02 #define DRM_EXYNOS_GEM_MMAP 0x02
...@@ -132,6 +165,11 @@ enum e_drm_exynos_gem_mem_type { ...@@ -132,6 +165,11 @@ enum e_drm_exynos_gem_mem_type {
#define DRM_EXYNOS_PLANE_SET_ZPOS 0x06 #define DRM_EXYNOS_PLANE_SET_ZPOS 0x06
#define DRM_EXYNOS_VIDI_CONNECTION 0x07 #define DRM_EXYNOS_VIDI_CONNECTION 0x07
/* G2D */
#define DRM_EXYNOS_G2D_GET_VER 0x20
#define DRM_EXYNOS_G2D_SET_CMDLIST 0x21
#define DRM_EXYNOS_G2D_EXEC 0x22
#define DRM_IOCTL_EXYNOS_GEM_CREATE DRM_IOWR(DRM_COMMAND_BASE + \ #define DRM_IOCTL_EXYNOS_GEM_CREATE DRM_IOWR(DRM_COMMAND_BASE + \
DRM_EXYNOS_GEM_CREATE, struct drm_exynos_gem_create) DRM_EXYNOS_GEM_CREATE, struct drm_exynos_gem_create)
...@@ -150,6 +188,25 @@ enum e_drm_exynos_gem_mem_type { ...@@ -150,6 +188,25 @@ enum e_drm_exynos_gem_mem_type {
#define DRM_IOCTL_EXYNOS_VIDI_CONNECTION DRM_IOWR(DRM_COMMAND_BASE + \ #define DRM_IOCTL_EXYNOS_VIDI_CONNECTION DRM_IOWR(DRM_COMMAND_BASE + \
DRM_EXYNOS_VIDI_CONNECTION, struct drm_exynos_vidi_connection) DRM_EXYNOS_VIDI_CONNECTION, struct drm_exynos_vidi_connection)
#define DRM_IOCTL_EXYNOS_G2D_GET_VER DRM_IOWR(DRM_COMMAND_BASE + \
DRM_EXYNOS_G2D_GET_VER, struct drm_exynos_g2d_get_ver)
#define DRM_IOCTL_EXYNOS_G2D_SET_CMDLIST DRM_IOWR(DRM_COMMAND_BASE + \
DRM_EXYNOS_G2D_SET_CMDLIST, struct drm_exynos_g2d_set_cmdlist)
#define DRM_IOCTL_EXYNOS_G2D_EXEC DRM_IOWR(DRM_COMMAND_BASE + \
DRM_EXYNOS_G2D_EXEC, struct drm_exynos_g2d_exec)
/* EXYNOS specific events */
#define DRM_EXYNOS_G2D_EVENT 0x80000000
struct drm_exynos_g2d_event {
struct drm_event base;
__u64 user_data;
__u32 tv_sec;
__u32 tv_usec;
__u32 cmdlist_no;
__u32 reserved;
};
#ifdef __KERNEL__ #ifdef __KERNEL__
/** /**
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment