aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDave Airlie <airlied@redhat.com>2012-01-03 04:25:18 -0500
committerDave Airlie <airlied@redhat.com>2012-01-03 04:25:26 -0500
commit863f78b5ff7f0e897f26973de882cfca04453f5d (patch)
tree864dbd5eb72fb7ac1865a7aa72dce3dd5f7a4c73
parent5c2a5ce689c99037771a6c110374461781a6f042 (diff)
parentd84083268bd707ebb8ed2f4fc26ebc7a0c453a83 (diff)
Merge branch 'exynos-drm-next' of git://git.infradead.org/users/kmpark/linux-samsung into drm-core-next
these patch sets include the following features: - add Samsung SoC Exynos based HDMI support. - add pm feature for fimd driver. - add multi buffer plane pixel formats to drm/drm_fourcc.h. multi buffer plane pixel format has seperated memory spaces for each plane. for exampme, NV12M has Y plane and CbCr plane and these are in non-continuous memory region. compared with NV12, NV12M's memory shape is like following. NV12 : ______(Y)(CbCr)_______ NV12M : __(Y)_ ..... _(CbCr)__ - bug fix to vblank. - code clean to exynos gem framework. * 'exynos-drm-next' of git://git.infradead.org/users/kmpark/linux-samsung: drm/exynos: added hdmi display support drm/exynos: added mutex lock and code clean. drm/exynos: extend vblank off delay time. drm/exynos: change driver name. drm/exynos: Support multi buffers drm: Add multi buffer plane pixel formats drm/exynos: added pm support. drm/exynos: remove buffer creation of fbdev from drm framebuffer creation drm/exynos: Split creation of gem object and gem handle drm/exynos: Fix a fake mmap offset creation drm/exynos: gem code cleanup
-rw-r--r--drivers/gpu/drm/exynos/Kconfig7
-rw-r--r--drivers/gpu/drm/exynos/Makefile2
-rw-r--r--drivers/gpu/drm/exynos/exynos_ddc.c58
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_buf.c5
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_buf.h3
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_crtc.c28
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_drv.c6
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_drv.h15
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_fb.c164
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_fb.h24
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_fbdev.c66
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_fimd.c92
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_gem.c227
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_gem.h53
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_hdmi.c439
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_hdmi.h73
-rw-r--r--drivers/gpu/drm/exynos/exynos_hdmi.c1176
-rw-r--r--drivers/gpu/drm/exynos/exynos_hdmi.h87
-rw-r--r--drivers/gpu/drm/exynos/exynos_hdmiphy.c58
-rw-r--r--drivers/gpu/drm/exynos/exynos_mixer.c1070
-rw-r--r--drivers/gpu/drm/exynos/exynos_mixer.h92
-rw-r--r--drivers/gpu/drm/exynos/regs-hdmi.h147
-rw-r--r--drivers/gpu/drm/exynos/regs-mixer.h141
-rw-r--r--drivers/gpu/drm/exynos/regs-vp.h91
-rw-r--r--include/drm/drm_fourcc.h7
-rw-r--r--include/drm/exynos_drm.h27
26 files changed, 3854 insertions, 304 deletions
diff --git a/drivers/gpu/drm/exynos/Kconfig b/drivers/gpu/drm/exynos/Kconfig
index 847466aab435..f9aaa56eae07 100644
--- a/drivers/gpu/drm/exynos/Kconfig
+++ b/drivers/gpu/drm/exynos/Kconfig
@@ -18,3 +18,10 @@ config DRM_EXYNOS_FIMD
18 help 18 help
19 Choose this option if you want to use Exynos FIMD for DRM. 19 Choose this option if you want to use Exynos FIMD for DRM.
20 If M is selected, the module will be called exynos_drm_fimd 20 If M is selected, the module will be called exynos_drm_fimd
21
22config DRM_EXYNOS_HDMI
23 tristate "Exynos DRM HDMI"
24 depends on DRM_EXYNOS
25 help
26 Choose this option if you want to use Exynos HDMI for DRM.
27 If M is selected, the module will be called exynos_drm_hdmi
diff --git a/drivers/gpu/drm/exynos/Makefile b/drivers/gpu/drm/exynos/Makefile
index c99127214f8e..395e69c9a96e 100644
--- a/drivers/gpu/drm/exynos/Makefile
+++ b/drivers/gpu/drm/exynos/Makefile
@@ -10,3 +10,5 @@ exynosdrm-y := exynos_drm_drv.o exynos_drm_encoder.o exynos_drm_connector.o \
10 10
11obj-$(CONFIG_DRM_EXYNOS) += exynosdrm.o 11obj-$(CONFIG_DRM_EXYNOS) += exynosdrm.o
12obj-$(CONFIG_DRM_EXYNOS_FIMD) += exynos_drm_fimd.o 12obj-$(CONFIG_DRM_EXYNOS_FIMD) += exynos_drm_fimd.o
13obj-$(CONFIG_DRM_EXYNOS_HDMI) += exynos_hdmi.o exynos_mixer.o exynos_ddc.o \
14 exynos_hdmiphy.o exynos_drm_hdmi.o
diff --git a/drivers/gpu/drm/exynos/exynos_ddc.c b/drivers/gpu/drm/exynos/exynos_ddc.c
new file mode 100644
index 000000000000..84b614fe26fd
--- /dev/null
+++ b/drivers/gpu/drm/exynos/exynos_ddc.c
@@ -0,0 +1,58 @@
1/*
2 * Copyright (C) 2011 Samsung Electronics Co.Ltd
3 * Authors:
4 * Seung-Woo Kim <sw0312.kim@samsung.com>
5 * Inki Dae <inki.dae@samsung.com>
6 *
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the
9 * Free Software Foundation; either version 2 of the License, or (at your
10 * option) any later version.
11 *
12 */
13
14#include "drmP.h"
15
16#include <linux/kernel.h>
17#include <linux/i2c.h>
18#include <linux/module.h>
19
20
21#include "exynos_drm_drv.h"
22#include "exynos_hdmi.h"
23
24static int s5p_ddc_probe(struct i2c_client *client,
25 const struct i2c_device_id *dev_id)
26{
27 hdmi_attach_ddc_client(client);
28
29 dev_info(&client->adapter->dev, "attached s5p_ddc "
30 "into i2c adapter successfully\n");
31
32 return 0;
33}
34
35static int s5p_ddc_remove(struct i2c_client *client)
36{
37 dev_info(&client->adapter->dev, "detached s5p_ddc "
38 "from i2c adapter successfully\n");
39
40 return 0;
41}
42
43static struct i2c_device_id ddc_idtable[] = {
44 {"s5p_ddc", 0},
45 { },
46};
47
48struct i2c_driver ddc_driver = {
49 .driver = {
50 .name = "s5p_ddc",
51 .owner = THIS_MODULE,
52 },
53 .id_table = ddc_idtable,
54 .probe = s5p_ddc_probe,
55 .remove = __devexit_p(s5p_ddc_remove),
56 .command = NULL,
57};
58EXPORT_SYMBOL(ddc_driver);
diff --git a/drivers/gpu/drm/exynos/exynos_drm_buf.c b/drivers/gpu/drm/exynos/exynos_drm_buf.c
index 2bb07bca511a..3cf785c58186 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_buf.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_buf.c
@@ -73,7 +73,7 @@ struct exynos_drm_gem_buf *exynos_drm_buf_create(struct drm_device *dev,
73 buffer = kzalloc(sizeof(*buffer), GFP_KERNEL); 73 buffer = kzalloc(sizeof(*buffer), GFP_KERNEL);
74 if (!buffer) { 74 if (!buffer) {
75 DRM_ERROR("failed to allocate exynos_drm_gem_buf.\n"); 75 DRM_ERROR("failed to allocate exynos_drm_gem_buf.\n");
76 return ERR_PTR(-ENOMEM); 76 return NULL;
77 } 77 }
78 78
79 buffer->size = size; 79 buffer->size = size;
@@ -84,8 +84,7 @@ struct exynos_drm_gem_buf *exynos_drm_buf_create(struct drm_device *dev,
84 */ 84 */
85 if (lowlevel_buffer_allocate(dev, buffer) < 0) { 85 if (lowlevel_buffer_allocate(dev, buffer) < 0) {
86 kfree(buffer); 86 kfree(buffer);
87 buffer = NULL; 87 return NULL;
88 return ERR_PTR(-ENOMEM);
89 } 88 }
90 89
91 return buffer; 90 return buffer;
diff --git a/drivers/gpu/drm/exynos/exynos_drm_buf.h b/drivers/gpu/drm/exynos/exynos_drm_buf.h
index 6e91f9caa5db..c913f2bad760 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_buf.h
+++ b/drivers/gpu/drm/exynos/exynos_drm_buf.h
@@ -30,9 +30,6 @@
30struct exynos_drm_gem_buf *exynos_drm_buf_create(struct drm_device *dev, 30struct exynos_drm_gem_buf *exynos_drm_buf_create(struct drm_device *dev,
31 unsigned int size); 31 unsigned int size);
32 32
33/* get memory information of a drm framebuffer. */
34struct exynos_drm_gem_buf *exynos_drm_fb_get_buf(struct drm_framebuffer *fb);
35
36/* remove allocated physical memory. */ 33/* remove allocated physical memory. */
37void exynos_drm_buf_destroy(struct drm_device *dev, 34void exynos_drm_buf_destroy(struct drm_device *dev,
38 struct exynos_drm_gem_buf *buffer); 35 struct exynos_drm_gem_buf *buffer);
diff --git a/drivers/gpu/drm/exynos/exynos_drm_crtc.c b/drivers/gpu/drm/exynos/exynos_drm_crtc.c
index e1ce9fd5a160..e3861ac49295 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_crtc.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_crtc.c
@@ -34,7 +34,6 @@
34#include "exynos_drm_fb.h" 34#include "exynos_drm_fb.h"
35#include "exynos_drm_encoder.h" 35#include "exynos_drm_encoder.h"
36#include "exynos_drm_gem.h" 36#include "exynos_drm_gem.h"
37#include "exynos_drm_buf.h"
38 37
39#define to_exynos_crtc(x) container_of(x, struct exynos_drm_crtc,\ 38#define to_exynos_crtc(x) container_of(x, struct exynos_drm_crtc,\
40 drm_crtc) 39 drm_crtc)
@@ -80,19 +79,23 @@ int exynos_drm_overlay_update(struct exynos_drm_overlay *overlay,
80 struct exynos_drm_gem_buf *buffer; 79 struct exynos_drm_gem_buf *buffer;
81 unsigned int actual_w; 80 unsigned int actual_w;
82 unsigned int actual_h; 81 unsigned int actual_h;
82 int nr = exynos_drm_format_num_buffers(fb->pixel_format);
83 int i;
84
85 for (i = 0; i < nr; i++) {
86 buffer = exynos_drm_fb_buffer(fb, i);
87 if (!buffer) {
88 DRM_LOG_KMS("buffer is null\n");
89 return -EFAULT;
90 }
83 91
84 buffer = exynos_drm_fb_get_buf(fb); 92 overlay->dma_addr[i] = buffer->dma_addr;
85 if (!buffer) { 93 overlay->vaddr[i] = buffer->kvaddr;
86 DRM_LOG_KMS("buffer is null.\n");
87 return -EFAULT;
88 }
89
90 overlay->dma_addr = buffer->dma_addr;
91 overlay->vaddr = buffer->kvaddr;
92 94
93 DRM_DEBUG_KMS("vaddr = 0x%lx, dma_addr = 0x%lx\n", 95 DRM_DEBUG_KMS("buffer: %d, vaddr = 0x%lx, dma_addr = 0x%lx\n",
94 (unsigned long)overlay->vaddr, 96 i, (unsigned long)overlay->vaddr[i],
95 (unsigned long)overlay->dma_addr); 97 (unsigned long)overlay->dma_addr[i]);
98 }
96 99
97 actual_w = min((mode->hdisplay - pos->crtc_x), pos->crtc_w); 100 actual_w = min((mode->hdisplay - pos->crtc_x), pos->crtc_w);
98 actual_h = min((mode->vdisplay - pos->crtc_y), pos->crtc_h); 101 actual_h = min((mode->vdisplay - pos->crtc_y), pos->crtc_h);
@@ -104,6 +107,7 @@ int exynos_drm_overlay_update(struct exynos_drm_overlay *overlay,
104 overlay->fb_height = fb->height; 107 overlay->fb_height = fb->height;
105 overlay->bpp = fb->bits_per_pixel; 108 overlay->bpp = fb->bits_per_pixel;
106 overlay->pitch = fb->pitches[0]; 109 overlay->pitch = fb->pitches[0];
110 overlay->pixel_format = fb->pixel_format;
107 111
108 /* set overlay range to be displayed. */ 112 /* set overlay range to be displayed. */
109 overlay->crtc_x = pos->crtc_x; 113 overlay->crtc_x = pos->crtc_x;
diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.c b/drivers/gpu/drm/exynos/exynos_drm_drv.c
index 050684ceab9d..35889ca255e9 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_drv.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_drv.c
@@ -38,12 +38,14 @@
38#include "exynos_drm_gem.h" 38#include "exynos_drm_gem.h"
39#include "exynos_drm_plane.h" 39#include "exynos_drm_plane.h"
40 40
41#define DRIVER_NAME "exynos-drm" 41#define DRIVER_NAME "exynos"
42#define DRIVER_DESC "Samsung SoC DRM" 42#define DRIVER_DESC "Samsung SoC DRM"
43#define DRIVER_DATE "20110530" 43#define DRIVER_DATE "20110530"
44#define DRIVER_MAJOR 1 44#define DRIVER_MAJOR 1
45#define DRIVER_MINOR 0 45#define DRIVER_MINOR 0
46 46
47#define VBLANK_OFF_DELAY 50000
48
47static int exynos_drm_load(struct drm_device *dev, unsigned long flags) 49static int exynos_drm_load(struct drm_device *dev, unsigned long flags)
48{ 50{
49 struct exynos_drm_private *private; 51 struct exynos_drm_private *private;
@@ -107,6 +109,8 @@ static int exynos_drm_load(struct drm_device *dev, unsigned long flags)
107 goto err_drm_device; 109 goto err_drm_device;
108 } 110 }
109 111
112 drm_vblank_offdelay = VBLANK_OFF_DELAY;
113
110 return 0; 114 return 0;
111 115
112err_drm_device: 116err_drm_device:
diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.h b/drivers/gpu/drm/exynos/exynos_drm_drv.h
index 8e8d8f0f8f33..e685e1e33055 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_drv.h
+++ b/drivers/gpu/drm/exynos/exynos_drm_drv.h
@@ -34,12 +34,15 @@
34 34
35#define MAX_CRTC 2 35#define MAX_CRTC 2
36#define MAX_PLANE 5 36#define MAX_PLANE 5
37#define MAX_FB_BUFFER 3
37#define DEFAULT_ZPOS -1 38#define DEFAULT_ZPOS -1
38 39
39struct drm_device; 40struct drm_device;
40struct exynos_drm_overlay; 41struct exynos_drm_overlay;
41struct drm_connector; 42struct drm_connector;
42 43
44extern unsigned int drm_vblank_offdelay;
45
43/* this enumerates display type. */ 46/* this enumerates display type. */
44enum exynos_drm_output_type { 47enum exynos_drm_output_type {
45 EXYNOS_DISPLAY_TYPE_NONE, 48 EXYNOS_DISPLAY_TYPE_NONE,
@@ -82,9 +85,10 @@ struct exynos_drm_overlay_ops {
82 * @scan_flag: interlace or progressive way. 85 * @scan_flag: interlace or progressive way.
83 * (it could be DRM_MODE_FLAG_*) 86 * (it could be DRM_MODE_FLAG_*)
84 * @bpp: pixel size.(in bit) 87 * @bpp: pixel size.(in bit)
85 * @dma_addr: bus(accessed by dma) address to the memory region allocated 88 * @pixel_format: fourcc pixel format of this overlay
86 * for a overlay. 89 * @dma_addr: array of bus(accessed by dma) address to the memory region
87 * @vaddr: virtual memory addresss to this overlay. 90 * allocated for a overlay.
91 * @vaddr: array of virtual memory addresss to this overlay.
88 * @zpos: order of overlay layer(z position). 92 * @zpos: order of overlay layer(z position).
89 * @default_win: a window to be enabled. 93 * @default_win: a window to be enabled.
90 * @color_key: color key on or off. 94 * @color_key: color key on or off.
@@ -112,8 +116,9 @@ struct exynos_drm_overlay {
112 unsigned int scan_flag; 116 unsigned int scan_flag;
113 unsigned int bpp; 117 unsigned int bpp;
114 unsigned int pitch; 118 unsigned int pitch;
115 dma_addr_t dma_addr; 119 uint32_t pixel_format;
116 void __iomem *vaddr; 120 dma_addr_t dma_addr[MAX_FB_BUFFER];
121 void __iomem *vaddr[MAX_FB_BUFFER];
117 int zpos; 122 int zpos;
118 123
119 bool default_win; 124 bool default_win;
diff --git a/drivers/gpu/drm/exynos/exynos_drm_fb.c b/drivers/gpu/drm/exynos/exynos_drm_fb.c
index df5eec6c1aba..3733fe6723d3 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_fb.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_fb.c
@@ -33,7 +33,6 @@
33 33
34#include "exynos_drm_drv.h" 34#include "exynos_drm_drv.h"
35#include "exynos_drm_fb.h" 35#include "exynos_drm_fb.h"
36#include "exynos_drm_buf.h"
37#include "exynos_drm_gem.h" 36#include "exynos_drm_gem.h"
38 37
39#define to_exynos_fb(x) container_of(x, struct exynos_drm_fb, fb) 38#define to_exynos_fb(x) container_of(x, struct exynos_drm_fb, fb)
@@ -42,15 +41,11 @@
42 * exynos specific framebuffer structure. 41 * exynos specific framebuffer structure.
43 * 42 *
44 * @fb: drm framebuffer obejct. 43 * @fb: drm framebuffer obejct.
45 * @exynos_gem_obj: exynos specific gem object containing a gem object. 44 * @exynos_gem_obj: array of exynos specific gem object containing a gem object.
46 * @buffer: pointer to exynos_drm_gem_buffer object.
47 * - contain the memory information to memory region allocated
48 * at default framebuffer creation.
49 */ 45 */
50struct exynos_drm_fb { 46struct exynos_drm_fb {
51 struct drm_framebuffer fb; 47 struct drm_framebuffer fb;
52 struct exynos_drm_gem_obj *exynos_gem_obj; 48 struct exynos_drm_gem_obj *exynos_gem_obj[MAX_FB_BUFFER];
53 struct exynos_drm_gem_buf *buffer;
54}; 49};
55 50
56static void exynos_drm_fb_destroy(struct drm_framebuffer *fb) 51static void exynos_drm_fb_destroy(struct drm_framebuffer *fb)
@@ -61,13 +56,6 @@ static void exynos_drm_fb_destroy(struct drm_framebuffer *fb)
61 56
62 drm_framebuffer_cleanup(fb); 57 drm_framebuffer_cleanup(fb);
63 58
64 /*
65 * default framebuffer has no gem object so
66 * a buffer of the default framebuffer should be released at here.
67 */
68 if (!exynos_fb->exynos_gem_obj && exynos_fb->buffer)
69 exynos_drm_buf_destroy(fb->dev, exynos_fb->buffer);
70
71 kfree(exynos_fb); 59 kfree(exynos_fb);
72 exynos_fb = NULL; 60 exynos_fb = NULL;
73} 61}
@@ -81,7 +69,7 @@ static int exynos_drm_fb_create_handle(struct drm_framebuffer *fb,
81 DRM_DEBUG_KMS("%s\n", __FILE__); 69 DRM_DEBUG_KMS("%s\n", __FILE__);
82 70
83 return drm_gem_handle_create(file_priv, 71 return drm_gem_handle_create(file_priv,
84 &exynos_fb->exynos_gem_obj->base, handle); 72 &exynos_fb->exynos_gem_obj[0]->base, handle);
85} 73}
86 74
87static int exynos_drm_fb_dirty(struct drm_framebuffer *fb, 75static int exynos_drm_fb_dirty(struct drm_framebuffer *fb,
@@ -102,132 +90,88 @@ static struct drm_framebuffer_funcs exynos_drm_fb_funcs = {
102 .dirty = exynos_drm_fb_dirty, 90 .dirty = exynos_drm_fb_dirty,
103}; 91};
104 92
105static struct drm_framebuffer * 93struct drm_framebuffer *
106exynos_drm_fb_init(struct drm_file *file_priv, struct drm_device *dev, 94exynos_drm_framebuffer_init(struct drm_device *dev,
107 struct drm_mode_fb_cmd2 *mode_cmd) 95 struct drm_mode_fb_cmd2 *mode_cmd,
96 struct drm_gem_object *obj)
108{ 97{
109 struct exynos_drm_fb *exynos_fb; 98 struct exynos_drm_fb *exynos_fb;
110 struct drm_framebuffer *fb;
111 struct exynos_drm_gem_obj *exynos_gem_obj = NULL;
112 struct drm_gem_object *obj;
113 unsigned int size;
114 int ret; 99 int ret;
115 100
116 DRM_DEBUG_KMS("%s\n", __FILE__);
117
118 DRM_LOG_KMS("drm fb create(%dx%d)\n",
119 mode_cmd->width, mode_cmd->height);
120
121 exynos_fb = kzalloc(sizeof(*exynos_fb), GFP_KERNEL); 101 exynos_fb = kzalloc(sizeof(*exynos_fb), GFP_KERNEL);
122 if (!exynos_fb) { 102 if (!exynos_fb) {
123 DRM_ERROR("failed to allocate exynos drm framebuffer.\n"); 103 DRM_ERROR("failed to allocate exynos drm framebuffer\n");
124 return ERR_PTR(-ENOMEM); 104 return ERR_PTR(-ENOMEM);
125 } 105 }
126 106
127 fb = &exynos_fb->fb; 107 ret = drm_framebuffer_init(dev, &exynos_fb->fb, &exynos_drm_fb_funcs);
128 ret = drm_framebuffer_init(dev, fb, &exynos_drm_fb_funcs);
129 if (ret) { 108 if (ret) {
130 DRM_ERROR("failed to initialize framebuffer.\n"); 109 DRM_ERROR("failed to initialize framebuffer\n");
131 goto err_init; 110 return ERR_PTR(ret);
132 } 111 }
133 112
134 DRM_LOG_KMS("create: fb id: %d\n", fb->base.id); 113 drm_helper_mode_fill_fb_struct(&exynos_fb->fb, mode_cmd);
114 exynos_fb->exynos_gem_obj[0] = to_exynos_gem_obj(obj);
135 115
136 size = mode_cmd->pitches[0] * mode_cmd->height; 116 return &exynos_fb->fb;
117}
137 118
138 /* 119static struct drm_framebuffer *
139 * mode_cmd->handles[0] could be NULL at booting time or 120exynos_user_fb_create(struct drm_device *dev, struct drm_file *file_priv,
140 * with user request. if NULL, a new buffer or a gem object 121 struct drm_mode_fb_cmd2 *mode_cmd)
141 * would be allocated. 122{
142 */ 123 struct drm_gem_object *obj;
143 if (!mode_cmd->handles[0]) { 124 struct drm_framebuffer *fb;
144 if (!file_priv) { 125 struct exynos_drm_fb *exynos_fb;
145 struct exynos_drm_gem_buf *buffer; 126 int nr;
146 127 int i;
147 /*
148 * in case that file_priv is NULL, it allocates
149 * only buffer and this buffer would be used
150 * for default framebuffer.
151 */
152 buffer = exynos_drm_buf_create(dev, size);
153 if (IS_ERR(buffer)) {
154 ret = PTR_ERR(buffer);
155 goto err_buffer;
156 }
157
158 exynos_fb->buffer = buffer;
159
160 DRM_LOG_KMS("default: dma_addr = 0x%lx, size = 0x%x\n",
161 (unsigned long)buffer->dma_addr, size);
162
163 goto out;
164 } else {
165 exynos_gem_obj = exynos_drm_gem_create(dev, file_priv,
166 &mode_cmd->handles[0],
167 size);
168 if (IS_ERR(exynos_gem_obj)) {
169 ret = PTR_ERR(exynos_gem_obj);
170 goto err_buffer;
171 }
172 }
173 } else {
174 obj = drm_gem_object_lookup(dev, file_priv,
175 mode_cmd->handles[0]);
176 if (!obj) {
177 DRM_ERROR("failed to lookup gem object.\n");
178 goto err_buffer;
179 }
180 128
181 exynos_gem_obj = to_exynos_gem_obj(obj); 129 DRM_DEBUG_KMS("%s\n", __FILE__);
182 130
183 drm_gem_object_unreference_unlocked(obj); 131 obj = drm_gem_object_lookup(dev, file_priv, mode_cmd->handles[0]);
132 if (!obj) {
133 DRM_ERROR("failed to lookup gem object\n");
134 return ERR_PTR(-ENOENT);
184 } 135 }
185 136
186 /* 137 drm_gem_object_unreference_unlocked(obj);
187 * if got a exynos_gem_obj from either a handle or
188 * a new creation then exynos_fb->exynos_gem_obj is NULL
189 * so that default framebuffer has no its own gem object,
190 * only its own buffer object.
191 */
192 exynos_fb->buffer = exynos_gem_obj->buffer;
193
194 DRM_LOG_KMS("dma_addr = 0x%lx, size = 0x%x, gem object = 0x%x\n",
195 (unsigned long)exynos_fb->buffer->dma_addr, size,
196 (unsigned int)&exynos_gem_obj->base);
197 138
198out: 139 fb = exynos_drm_framebuffer_init(dev, mode_cmd, obj);
199 exynos_fb->exynos_gem_obj = exynos_gem_obj; 140 if (IS_ERR(fb))
141 return fb;
200 142
201 drm_helper_mode_fill_fb_struct(fb, mode_cmd); 143 exynos_fb = to_exynos_fb(fb);
144 nr = exynos_drm_format_num_buffers(fb->pixel_format);
202 145
203 return fb; 146 for (i = 1; i < nr; i++) {
204 147 obj = drm_gem_object_lookup(dev, file_priv,
205err_buffer: 148 mode_cmd->handles[i]);
206 drm_framebuffer_cleanup(fb); 149 if (!obj) {
207 150 DRM_ERROR("failed to lookup gem object\n");
208err_init: 151 exynos_drm_fb_destroy(fb);
209 kfree(exynos_fb); 152 return ERR_PTR(-ENOENT);
153 }
210 154
211 return ERR_PTR(ret); 155 drm_gem_object_unreference_unlocked(obj);
212}
213 156
214struct drm_framebuffer *exynos_drm_fb_create(struct drm_device *dev, 157 exynos_fb->exynos_gem_obj[i] = to_exynos_gem_obj(obj);
215 struct drm_file *file_priv, 158 }
216 struct drm_mode_fb_cmd2 *mode_cmd)
217{
218 DRM_DEBUG_KMS("%s\n", __FILE__);
219 159
220 return exynos_drm_fb_init(file_priv, dev, mode_cmd); 160 return fb;
221} 161}
222 162
223struct exynos_drm_gem_buf *exynos_drm_fb_get_buf(struct drm_framebuffer *fb) 163struct exynos_drm_gem_buf *exynos_drm_fb_buffer(struct drm_framebuffer *fb,
164 int index)
224{ 165{
225 struct exynos_drm_fb *exynos_fb = to_exynos_fb(fb); 166 struct exynos_drm_fb *exynos_fb = to_exynos_fb(fb);
226 struct exynos_drm_gem_buf *buffer; 167 struct exynos_drm_gem_buf *buffer;
227 168
228 DRM_DEBUG_KMS("%s\n", __FILE__); 169 DRM_DEBUG_KMS("%s\n", __FILE__);
229 170
230 buffer = exynos_fb->buffer; 171 if (index >= MAX_FB_BUFFER)
172 return NULL;
173
174 buffer = exynos_fb->exynos_gem_obj[index]->buffer;
231 if (!buffer) 175 if (!buffer)
232 return NULL; 176 return NULL;
233 177
@@ -248,7 +192,7 @@ static void exynos_drm_output_poll_changed(struct drm_device *dev)
248} 192}
249 193
250static struct drm_mode_config_funcs exynos_drm_mode_config_funcs = { 194static struct drm_mode_config_funcs exynos_drm_mode_config_funcs = {
251 .fb_create = exynos_drm_fb_create, 195 .fb_create = exynos_user_fb_create,
252 .output_poll_changed = exynos_drm_output_poll_changed, 196 .output_poll_changed = exynos_drm_output_poll_changed,
253}; 197};
254 198
diff --git a/drivers/gpu/drm/exynos/exynos_drm_fb.h b/drivers/gpu/drm/exynos/exynos_drm_fb.h
index 52c5982bdbbc..3ecb30d93552 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_fb.h
+++ b/drivers/gpu/drm/exynos/exynos_drm_fb.h
@@ -28,9 +28,27 @@
28#ifndef _EXYNOS_DRM_FB_H_ 28#ifndef _EXYNOS_DRM_FB_H_
29#define _EXYNOS_DRM_FB_H 29#define _EXYNOS_DRM_FB_H
30 30
31struct drm_framebuffer *exynos_drm_fb_create(struct drm_device *dev, 31static inline int exynos_drm_format_num_buffers(uint32_t format)
32 struct drm_file *filp, 32{
33 struct drm_mode_fb_cmd2 *mode_cmd); 33 switch (format) {
34 case DRM_FORMAT_NV12M:
35 case DRM_FORMAT_NV12MT:
36 return 2;
37 case DRM_FORMAT_YUV420M:
38 return 3;
39 default:
40 return 1;
41 }
42}
43
44struct drm_framebuffer *
45exynos_drm_framebuffer_init(struct drm_device *dev,
46 struct drm_mode_fb_cmd2 *mode_cmd,
47 struct drm_gem_object *obj);
48
49/* get memory information of a drm framebuffer */
50struct exynos_drm_gem_buf *exynos_drm_fb_buffer(struct drm_framebuffer *fb,
51 int index);
34 52
35void exynos_drm_mode_config_init(struct drm_device *dev); 53void exynos_drm_mode_config_init(struct drm_device *dev);
36 54
diff --git a/drivers/gpu/drm/exynos/exynos_drm_fbdev.c b/drivers/gpu/drm/exynos/exynos_drm_fbdev.c
index c8b278447c4f..d7ae29d2f3d6 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_fbdev.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_fbdev.c
@@ -34,7 +34,6 @@
34#include "exynos_drm_drv.h" 34#include "exynos_drm_drv.h"
35#include "exynos_drm_fb.h" 35#include "exynos_drm_fb.h"
36#include "exynos_drm_gem.h" 36#include "exynos_drm_gem.h"
37#include "exynos_drm_buf.h"
38 37
39#define MAX_CONNECTOR 4 38#define MAX_CONNECTOR 4
40#define PREFERRED_BPP 32 39#define PREFERRED_BPP 32
@@ -43,8 +42,8 @@
43 drm_fb_helper) 42 drm_fb_helper)
44 43
45struct exynos_drm_fbdev { 44struct exynos_drm_fbdev {
46 struct drm_fb_helper drm_fb_helper; 45 struct drm_fb_helper drm_fb_helper;
47 struct drm_framebuffer *fb; 46 struct exynos_drm_gem_obj *exynos_gem_obj;
48}; 47};
49 48
50static int exynos_drm_fbdev_set_par(struct fb_info *info) 49static int exynos_drm_fbdev_set_par(struct fb_info *info)
@@ -90,19 +89,17 @@ static int exynos_drm_fbdev_update(struct drm_fb_helper *helper,
90{ 89{
91 struct fb_info *fbi = helper->fbdev; 90 struct fb_info *fbi = helper->fbdev;
92 struct drm_device *dev = helper->dev; 91 struct drm_device *dev = helper->dev;
93 struct exynos_drm_fbdev *exynos_fb = to_exynos_fbdev(helper);
94 struct exynos_drm_gem_buf *buffer; 92 struct exynos_drm_gem_buf *buffer;
95 unsigned int size = fb->width * fb->height * (fb->bits_per_pixel >> 3); 93 unsigned int size = fb->width * fb->height * (fb->bits_per_pixel >> 3);
96 unsigned long offset; 94 unsigned long offset;
97 95
98 DRM_DEBUG_KMS("%s\n", __FILE__); 96 DRM_DEBUG_KMS("%s\n", __FILE__);
99 97
100 exynos_fb->fb = fb;
101
102 drm_fb_helper_fill_fix(fbi, fb->pitches[0], fb->depth); 98 drm_fb_helper_fill_fix(fbi, fb->pitches[0], fb->depth);
103 drm_fb_helper_fill_var(fbi, helper, fb->width, fb->height); 99 drm_fb_helper_fill_var(fbi, helper, fb->width, fb->height);
104 100
105 buffer = exynos_drm_fb_get_buf(fb); 101 /* RGB formats use only one buffer */
102 buffer = exynos_drm_fb_buffer(fb, 0);
106 if (!buffer) { 103 if (!buffer) {
107 DRM_LOG_KMS("buffer is null.\n"); 104 DRM_LOG_KMS("buffer is null.\n");
108 return -EFAULT; 105 return -EFAULT;
@@ -124,10 +121,12 @@ static int exynos_drm_fbdev_create(struct drm_fb_helper *helper,
124 struct drm_fb_helper_surface_size *sizes) 121 struct drm_fb_helper_surface_size *sizes)
125{ 122{
126 struct exynos_drm_fbdev *exynos_fbdev = to_exynos_fbdev(helper); 123 struct exynos_drm_fbdev *exynos_fbdev = to_exynos_fbdev(helper);
124 struct exynos_drm_gem_obj *exynos_gem_obj;
127 struct drm_device *dev = helper->dev; 125 struct drm_device *dev = helper->dev;
128 struct fb_info *fbi; 126 struct fb_info *fbi;
129 struct drm_mode_fb_cmd2 mode_cmd = { 0 }; 127 struct drm_mode_fb_cmd2 mode_cmd = { 0 };
130 struct platform_device *pdev = dev->platformdev; 128 struct platform_device *pdev = dev->platformdev;
129 unsigned long size;
131 int ret; 130 int ret;
132 131
133 DRM_DEBUG_KMS("%s\n", __FILE__); 132 DRM_DEBUG_KMS("%s\n", __FILE__);
@@ -151,14 +150,23 @@ static int exynos_drm_fbdev_create(struct drm_fb_helper *helper,
151 goto out; 150 goto out;
152 } 151 }
153 152
154 exynos_fbdev->fb = exynos_drm_fb_create(dev, NULL, &mode_cmd); 153 size = mode_cmd.pitches[0] * mode_cmd.height;
155 if (IS_ERR_OR_NULL(exynos_fbdev->fb)) { 154 exynos_gem_obj = exynos_drm_gem_create(dev, size);
155 if (IS_ERR(exynos_gem_obj)) {
156 ret = PTR_ERR(exynos_gem_obj);
157 goto out;
158 }
159
160 exynos_fbdev->exynos_gem_obj = exynos_gem_obj;
161
162 helper->fb = exynos_drm_framebuffer_init(dev, &mode_cmd,
163 &exynos_gem_obj->base);
164 if (IS_ERR_OR_NULL(helper->fb)) {
156 DRM_ERROR("failed to create drm framebuffer.\n"); 165 DRM_ERROR("failed to create drm framebuffer.\n");
157 ret = PTR_ERR(exynos_fbdev->fb); 166 ret = PTR_ERR(helper->fb);
158 goto out; 167 goto out;
159 } 168 }
160 169
161 helper->fb = exynos_fbdev->fb;
162 helper->fbdev = fbi; 170 helper->fbdev = fbi;
163 171
164 fbi->par = helper; 172 fbi->par = helper;
@@ -172,8 +180,10 @@ static int exynos_drm_fbdev_create(struct drm_fb_helper *helper,
172 } 180 }
173 181
174 ret = exynos_drm_fbdev_update(helper, helper->fb); 182 ret = exynos_drm_fbdev_update(helper, helper->fb);
175 if (ret < 0) 183 if (ret < 0) {
176 fb_dealloc_cmap(&fbi->cmap); 184 fb_dealloc_cmap(&fbi->cmap);
185 goto out;
186 }
177 187
178/* 188/*
179 * if failed, all resources allocated above would be released by 189 * if failed, all resources allocated above would be released by
@@ -206,16 +216,13 @@ static int exynos_drm_fbdev_recreate(struct drm_fb_helper *helper,
206{ 216{
207 struct drm_device *dev = helper->dev; 217 struct drm_device *dev = helper->dev;
208 struct exynos_drm_fbdev *exynos_fbdev = to_exynos_fbdev(helper); 218 struct exynos_drm_fbdev *exynos_fbdev = to_exynos_fbdev(helper);
209 struct drm_framebuffer *fb = exynos_fbdev->fb; 219 struct exynos_drm_gem_obj *exynos_gem_obj;
220 struct drm_framebuffer *fb = helper->fb;
210 struct drm_mode_fb_cmd2 mode_cmd = { 0 }; 221 struct drm_mode_fb_cmd2 mode_cmd = { 0 };
222 unsigned long size;
211 223
212 DRM_DEBUG_KMS("%s\n", __FILE__); 224 DRM_DEBUG_KMS("%s\n", __FILE__);
213 225
214 if (helper->fb != fb) {
215 DRM_ERROR("drm framebuffer is different\n");
216 return -EINVAL;
217 }
218
219 if (exynos_drm_fbdev_is_samefb(fb, sizes)) 226 if (exynos_drm_fbdev_is_samefb(fb, sizes))
220 return 0; 227 return 0;
221 228
@@ -225,16 +232,26 @@ static int exynos_drm_fbdev_recreate(struct drm_fb_helper *helper,
225 mode_cmd.pixel_format = drm_mode_legacy_fb_format(sizes->surface_bpp, 232 mode_cmd.pixel_format = drm_mode_legacy_fb_format(sizes->surface_bpp,
226 sizes->surface_depth); 233 sizes->surface_depth);
227 234
235 if (exynos_fbdev->exynos_gem_obj)
236 exynos_drm_gem_destroy(exynos_fbdev->exynos_gem_obj);
237
228 if (fb->funcs->destroy) 238 if (fb->funcs->destroy)
229 fb->funcs->destroy(fb); 239 fb->funcs->destroy(fb);
230 240
231 exynos_fbdev->fb = exynos_drm_fb_create(dev, NULL, &mode_cmd); 241 size = mode_cmd.pitches[0] * mode_cmd.height;
232 if (IS_ERR(exynos_fbdev->fb)) { 242 exynos_gem_obj = exynos_drm_gem_create(dev, size);
233 DRM_ERROR("failed to allocate fb.\n"); 243 if (IS_ERR(exynos_gem_obj))
234 return PTR_ERR(exynos_fbdev->fb); 244 return PTR_ERR(exynos_gem_obj);
245
246 exynos_fbdev->exynos_gem_obj = exynos_gem_obj;
247
248 helper->fb = exynos_drm_framebuffer_init(dev, &mode_cmd,
249 &exynos_gem_obj->base);
250 if (IS_ERR_OR_NULL(helper->fb)) {
251 DRM_ERROR("failed to create drm framebuffer.\n");
252 return PTR_ERR(helper->fb);
235 } 253 }
236 254
237 helper->fb = exynos_fbdev->fb;
238 return exynos_drm_fbdev_update(helper, helper->fb); 255 return exynos_drm_fbdev_update(helper, helper->fb);
239} 256}
240 257
@@ -368,6 +385,9 @@ void exynos_drm_fbdev_fini(struct drm_device *dev)
368 385
369 fbdev = to_exynos_fbdev(private->fb_helper); 386 fbdev = to_exynos_fbdev(private->fb_helper);
370 387
388 if (fbdev->exynos_gem_obj)
389 exynos_drm_gem_destroy(fbdev->exynos_gem_obj);
390
371 exynos_drm_fbdev_destroy(dev, private->fb_helper); 391 exynos_drm_fbdev_destroy(dev, private->fb_helper);
372 kfree(fbdev); 392 kfree(fbdev);
373 private->fb_helper = NULL; 393 private->fb_helper = NULL;
diff --git a/drivers/gpu/drm/exynos/exynos_drm_fimd.c b/drivers/gpu/drm/exynos/exynos_drm_fimd.c
index fe4172e48ad2..ca83139cd309 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_fimd.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_fimd.c
@@ -87,6 +87,7 @@ struct fimd_context {
87 u32 vidcon0; 87 u32 vidcon0;
88 u32 vidcon1; 88 u32 vidcon1;
89 bool suspended; 89 bool suspended;
90 struct mutex lock;
90 91
91 struct fb_videomode *timing; 92 struct fb_videomode *timing;
92}; 93};
@@ -137,11 +138,22 @@ static struct exynos_drm_display_ops fimd_display_ops = {
137 138
138static void fimd_dpms(struct device *subdrv_dev, int mode) 139static void fimd_dpms(struct device *subdrv_dev, int mode)
139{ 140{
141 struct fimd_context *ctx = get_fimd_context(subdrv_dev);
142
140 DRM_DEBUG_KMS("%s, %d\n", __FILE__, mode); 143 DRM_DEBUG_KMS("%s, %d\n", __FILE__, mode);
141 144
145 mutex_lock(&ctx->lock);
146
142 switch (mode) { 147 switch (mode) {
143 case DRM_MODE_DPMS_ON: 148 case DRM_MODE_DPMS_ON:
144 pm_runtime_get_sync(subdrv_dev); 149 /*
150 * enable fimd hardware only if suspended status.
151 *
152 * P.S. fimd_dpms function would be called at booting time so
153 * clk_enable could be called double time.
154 */
155 if (ctx->suspended)
156 pm_runtime_get_sync(subdrv_dev);
145 break; 157 break;
146 case DRM_MODE_DPMS_STANDBY: 158 case DRM_MODE_DPMS_STANDBY:
147 case DRM_MODE_DPMS_SUSPEND: 159 case DRM_MODE_DPMS_SUSPEND:
@@ -152,6 +164,8 @@ static void fimd_dpms(struct device *subdrv_dev, int mode)
152 DRM_DEBUG_KMS("unspecified mode %d\n", mode); 164 DRM_DEBUG_KMS("unspecified mode %d\n", mode);
153 break; 165 break;
154 } 166 }
167
168 mutex_unlock(&ctx->lock);
155} 169}
156 170
157static void fimd_apply(struct device *subdrv_dev) 171static void fimd_apply(struct device *subdrv_dev)
@@ -181,6 +195,9 @@ static void fimd_commit(struct device *dev)
181 struct fb_videomode *timing = ctx->timing; 195 struct fb_videomode *timing = ctx->timing;
182 u32 val; 196 u32 val;
183 197
198 if (ctx->suspended)
199 return;
200
184 DRM_DEBUG_KMS("%s\n", __FILE__); 201 DRM_DEBUG_KMS("%s\n", __FILE__);
185 202
186 /* setup polarity values from machine code. */ 203 /* setup polarity values from machine code. */
@@ -310,8 +327,8 @@ static void fimd_win_mode_set(struct device *dev,
310 win_data->ovl_height = overlay->crtc_height; 327 win_data->ovl_height = overlay->crtc_height;
311 win_data->fb_width = overlay->fb_width; 328 win_data->fb_width = overlay->fb_width;
312 win_data->fb_height = overlay->fb_height; 329 win_data->fb_height = overlay->fb_height;
313 win_data->dma_addr = overlay->dma_addr + offset; 330 win_data->dma_addr = overlay->dma_addr[0] + offset;
314 win_data->vaddr = overlay->vaddr + offset; 331 win_data->vaddr = overlay->vaddr[0] + offset;
315 win_data->bpp = overlay->bpp; 332 win_data->bpp = overlay->bpp;
316 win_data->buf_offsize = (overlay->fb_width - overlay->crtc_width) * 333 win_data->buf_offsize = (overlay->fb_width - overlay->crtc_width) *
317 (overlay->bpp >> 3); 334 (overlay->bpp >> 3);
@@ -414,6 +431,9 @@ static void fimd_win_commit(struct device *dev, int zpos)
414 431
415 DRM_DEBUG_KMS("%s\n", __FILE__); 432 DRM_DEBUG_KMS("%s\n", __FILE__);
416 433
434 if (ctx->suspended)
435 return;
436
417 if (win == DEFAULT_ZPOS) 437 if (win == DEFAULT_ZPOS)
418 win = ctx->default_win; 438 win = ctx->default_win;
419 439
@@ -797,13 +817,6 @@ static int __devinit fimd_probe(struct platform_device *pdev)
797 goto err_req_irq; 817 goto err_req_irq;
798 } 818 }
799 819
800 pm_runtime_set_active(dev);
801 pm_runtime_enable(dev);
802 pm_runtime_get_sync(dev);
803
804 for (win = 0; win < WINDOWS_NR; win++)
805 fimd_clear_win(ctx, win);
806
807 ctx->clkdiv = fimd_calc_clkdiv(ctx, timing); 820 ctx->clkdiv = fimd_calc_clkdiv(ctx, timing);
808 ctx->vidcon0 = pdata->vidcon0; 821 ctx->vidcon0 = pdata->vidcon0;
809 ctx->vidcon1 = pdata->vidcon1; 822 ctx->vidcon1 = pdata->vidcon1;
@@ -825,7 +838,17 @@ static int __devinit fimd_probe(struct platform_device *pdev)
825 subdrv->manager.display_ops = &fimd_display_ops; 838 subdrv->manager.display_ops = &fimd_display_ops;
826 subdrv->manager.dev = dev; 839 subdrv->manager.dev = dev;
827 840
841 mutex_init(&ctx->lock);
842
828 platform_set_drvdata(pdev, ctx); 843 platform_set_drvdata(pdev, ctx);
844
845 pm_runtime_set_active(dev);
846 pm_runtime_enable(dev);
847 pm_runtime_get_sync(dev);
848
849 for (win = 0; win < WINDOWS_NR; win++)
850 fimd_clear_win(ctx, win);
851
829 exynos_drm_subdrv_register(subdrv); 852 exynos_drm_subdrv_register(subdrv);
830 853
831 return 0; 854 return 0;
@@ -885,6 +908,47 @@ out:
885 return 0; 908 return 0;
886} 909}
887 910
911#ifdef CONFIG_PM_SLEEP
912static int fimd_suspend(struct device *dev)
913{
914 int ret;
915
916 if (pm_runtime_suspended(dev))
917 return 0;
918
919 ret = pm_runtime_suspend(dev);
920 if (ret < 0)
921 return ret;
922
923 return 0;
924}
925
926static int fimd_resume(struct device *dev)
927{
928 int ret;
929
930 ret = pm_runtime_resume(dev);
931 if (ret < 0) {
932 DRM_ERROR("failed to resume runtime pm.\n");
933 return ret;
934 }
935
936 pm_runtime_disable(dev);
937
938 ret = pm_runtime_set_active(dev);
939 if (ret < 0) {
940 DRM_ERROR("failed to active runtime pm.\n");
941 pm_runtime_enable(dev);
942 pm_runtime_suspend(dev);
943 return ret;
944 }
945
946 pm_runtime_enable(dev);
947
948 return 0;
949}
950#endif
951
888#ifdef CONFIG_PM_RUNTIME 952#ifdef CONFIG_PM_RUNTIME
889static int fimd_runtime_suspend(struct device *dev) 953static int fimd_runtime_suspend(struct device *dev)
890{ 954{
@@ -917,11 +981,19 @@ static int fimd_runtime_resume(struct device *dev)
917 } 981 }
918 982
919 ctx->suspended = false; 983 ctx->suspended = false;
984
985 /* if vblank was enabled status, enable it again. */
986 if (test_and_clear_bit(0, &ctx->irq_flags))
987 fimd_enable_vblank(dev);
988
989 fimd_apply(dev);
990
920 return 0; 991 return 0;
921} 992}
922#endif 993#endif
923 994
924static const struct dev_pm_ops fimd_pm_ops = { 995static const struct dev_pm_ops fimd_pm_ops = {
996 SET_SYSTEM_SLEEP_PM_OPS(fimd_suspend, fimd_resume)
925 SET_RUNTIME_PM_OPS(fimd_runtime_suspend, fimd_runtime_resume, NULL) 997 SET_RUNTIME_PM_OPS(fimd_runtime_suspend, fimd_runtime_resume, NULL)
926}; 998};
927 999
diff --git a/drivers/gpu/drm/exynos/exynos_drm_gem.c b/drivers/gpu/drm/exynos/exynos_drm_gem.c
index aba0fe47f7ea..025abb3e3b67 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_gem.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_gem.c
@@ -55,17 +55,54 @@ static unsigned int convert_to_vm_err_msg(int msg)
55 return out_msg; 55 return out_msg;
56} 56}
57 57
58static unsigned int get_gem_mmap_offset(struct drm_gem_object *obj) 58static int exynos_drm_gem_handle_create(struct drm_gem_object *obj,
59 struct drm_file *file_priv,
60 unsigned int *handle)
59{ 61{
62 int ret;
63
64 /*
65 * allocate a id of idr table where the obj is registered
66 * and handle has the id what user can see.
67 */
68 ret = drm_gem_handle_create(file_priv, obj, handle);
69 if (ret)
70 return ret;
71
72 DRM_DEBUG_KMS("gem handle = 0x%x\n", *handle);
73
74 /* drop reference from allocate - handle holds it now. */
75 drm_gem_object_unreference_unlocked(obj);
76
77 return 0;
78}
79
80void exynos_drm_gem_destroy(struct exynos_drm_gem_obj *exynos_gem_obj)
81{
82 struct drm_gem_object *obj;
83
60 DRM_DEBUG_KMS("%s\n", __FILE__); 84 DRM_DEBUG_KMS("%s\n", __FILE__);
61 85
62 return (unsigned int)obj->map_list.hash.key << PAGE_SHIFT; 86 if (!exynos_gem_obj)
87 return;
88
89 obj = &exynos_gem_obj->base;
90
91 DRM_DEBUG_KMS("handle count = %d\n", atomic_read(&obj->handle_count));
92
93 exynos_drm_buf_destroy(obj->dev, exynos_gem_obj->buffer);
94
95 if (obj->map_list.map)
96 drm_gem_free_mmap_offset(obj);
97
98 /* release file pointer to gem object. */
99 drm_gem_object_release(obj);
100
101 kfree(exynos_gem_obj);
63} 102}
64 103
65static struct exynos_drm_gem_obj 104static struct exynos_drm_gem_obj *exynos_drm_gem_init(struct drm_device *dev,
66 *exynos_drm_gem_init(struct drm_device *drm_dev, 105 unsigned long size)
67 struct drm_file *file_priv, unsigned int *handle,
68 unsigned int size)
69{ 106{
70 struct exynos_drm_gem_obj *exynos_gem_obj; 107 struct exynos_drm_gem_obj *exynos_gem_obj;
71 struct drm_gem_object *obj; 108 struct drm_gem_object *obj;
@@ -73,75 +110,41 @@ static struct exynos_drm_gem_obj
73 110
74 exynos_gem_obj = kzalloc(sizeof(*exynos_gem_obj), GFP_KERNEL); 111 exynos_gem_obj = kzalloc(sizeof(*exynos_gem_obj), GFP_KERNEL);
75 if (!exynos_gem_obj) { 112 if (!exynos_gem_obj) {
76 DRM_ERROR("failed to allocate exynos gem object.\n"); 113 DRM_ERROR("failed to allocate exynos gem object\n");
77 return ERR_PTR(-ENOMEM); 114 return NULL;
78 } 115 }
79 116
80 obj = &exynos_gem_obj->base; 117 obj = &exynos_gem_obj->base;
81 118
82 ret = drm_gem_object_init(drm_dev, obj, size); 119 ret = drm_gem_object_init(dev, obj, size);
83 if (ret < 0) { 120 if (ret < 0) {
84 DRM_ERROR("failed to initialize gem object.\n"); 121 DRM_ERROR("failed to initialize gem object\n");
85 ret = -EINVAL; 122 kfree(exynos_gem_obj);
86 goto err_object_init; 123 return NULL;
87 } 124 }
88 125
89 DRM_DEBUG_KMS("created file object = 0x%x\n", (unsigned int)obj->filp); 126 DRM_DEBUG_KMS("created file object = 0x%x\n", (unsigned int)obj->filp);
90 127
91 ret = drm_gem_create_mmap_offset(obj);
92 if (ret < 0) {
93 DRM_ERROR("failed to allocate mmap offset.\n");
94 goto err_create_mmap_offset;
95 }
96
97 /*
98 * allocate a id of idr table where the obj is registered
99 * and handle has the id what user can see.
100 */
101 ret = drm_gem_handle_create(file_priv, obj, handle);
102 if (ret)
103 goto err_handle_create;
104
105 DRM_DEBUG_KMS("gem handle = 0x%x\n", *handle);
106
107 /* drop reference from allocate - handle holds it now. */
108 drm_gem_object_unreference_unlocked(obj);
109
110 return exynos_gem_obj; 128 return exynos_gem_obj;
111
112err_handle_create:
113 drm_gem_free_mmap_offset(obj);
114
115err_create_mmap_offset:
116 drm_gem_object_release(obj);
117
118err_object_init:
119 kfree(exynos_gem_obj);
120
121 return ERR_PTR(ret);
122} 129}
123 130
124struct exynos_drm_gem_obj *exynos_drm_gem_create(struct drm_device *dev, 131struct exynos_drm_gem_obj *exynos_drm_gem_create(struct drm_device *dev,
125 struct drm_file *file_priv, 132 unsigned long size)
126 unsigned int *handle, unsigned long size)
127{ 133{
128
129 struct exynos_drm_gem_obj *exynos_gem_obj = NULL;
130 struct exynos_drm_gem_buf *buffer; 134 struct exynos_drm_gem_buf *buffer;
135 struct exynos_drm_gem_obj *exynos_gem_obj;
131 136
132 size = roundup(size, PAGE_SIZE); 137 size = roundup(size, PAGE_SIZE);
133
134 DRM_DEBUG_KMS("%s: size = 0x%lx\n", __FILE__, size); 138 DRM_DEBUG_KMS("%s: size = 0x%lx\n", __FILE__, size);
135 139
136 buffer = exynos_drm_buf_create(dev, size); 140 buffer = exynos_drm_buf_create(dev, size);
137 if (IS_ERR(buffer)) { 141 if (!buffer)
138 return ERR_CAST(buffer); 142 return ERR_PTR(-ENOMEM);
139 }
140 143
141 exynos_gem_obj = exynos_drm_gem_init(dev, file_priv, handle, size); 144 exynos_gem_obj = exynos_drm_gem_init(dev, size);
142 if (IS_ERR(exynos_gem_obj)) { 145 if (!exynos_gem_obj) {
143 exynos_drm_buf_destroy(dev, buffer); 146 exynos_drm_buf_destroy(dev, buffer);
144 return exynos_gem_obj; 147 return ERR_PTR(-ENOMEM);
145 } 148 }
146 149
147 exynos_gem_obj->buffer = buffer; 150 exynos_gem_obj->buffer = buffer;
@@ -150,23 +153,30 @@ struct exynos_drm_gem_obj *exynos_drm_gem_create(struct drm_device *dev,
150} 153}
151 154
152int exynos_drm_gem_create_ioctl(struct drm_device *dev, void *data, 155int exynos_drm_gem_create_ioctl(struct drm_device *dev, void *data,
153 struct drm_file *file_priv) 156 struct drm_file *file_priv)
154{ 157{
155 struct drm_exynos_gem_create *args = data; 158 struct drm_exynos_gem_create *args = data;
156 struct exynos_drm_gem_obj *exynos_gem_obj = NULL; 159 struct exynos_drm_gem_obj *exynos_gem_obj;
160 int ret;
157 161
158 DRM_DEBUG_KMS("%s\n", __FILE__); 162 DRM_DEBUG_KMS("%s\n", __FILE__);
159 163
160 exynos_gem_obj = exynos_drm_gem_create(dev, file_priv, 164 exynos_gem_obj = exynos_drm_gem_create(dev, args->size);
161 &args->handle, args->size);
162 if (IS_ERR(exynos_gem_obj)) 165 if (IS_ERR(exynos_gem_obj))
163 return PTR_ERR(exynos_gem_obj); 166 return PTR_ERR(exynos_gem_obj);
164 167
168 ret = exynos_drm_gem_handle_create(&exynos_gem_obj->base, file_priv,
169 &args->handle);
170 if (ret) {
171 exynos_drm_gem_destroy(exynos_gem_obj);
172 return ret;
173 }
174
165 return 0; 175 return 0;
166} 176}
167 177
168int exynos_drm_gem_map_offset_ioctl(struct drm_device *dev, void *data, 178int exynos_drm_gem_map_offset_ioctl(struct drm_device *dev, void *data,
169 struct drm_file *file_priv) 179 struct drm_file *file_priv)
170{ 180{
171 struct drm_exynos_gem_map_off *args = data; 181 struct drm_exynos_gem_map_off *args = data;
172 182
@@ -185,7 +195,7 @@ int exynos_drm_gem_map_offset_ioctl(struct drm_device *dev, void *data,
185} 195}
186 196
187static int exynos_drm_gem_mmap_buffer(struct file *filp, 197static int exynos_drm_gem_mmap_buffer(struct file *filp,
188 struct vm_area_struct *vma) 198 struct vm_area_struct *vma)
189{ 199{
190 struct drm_gem_object *obj = filp->private_data; 200 struct drm_gem_object *obj = filp->private_data;
191 struct exynos_drm_gem_obj *exynos_gem_obj = to_exynos_gem_obj(obj); 201 struct exynos_drm_gem_obj *exynos_gem_obj = to_exynos_gem_obj(obj);
@@ -196,6 +206,7 @@ static int exynos_drm_gem_mmap_buffer(struct file *filp,
196 206
197 vma->vm_flags |= (VM_IO | VM_RESERVED); 207 vma->vm_flags |= (VM_IO | VM_RESERVED);
198 208
209 /* in case of direct mapping, always having non-cachable attribute */
199 vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); 210 vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
200 vma->vm_file = filp; 211 vma->vm_file = filp;
201 212
@@ -232,7 +243,7 @@ static const struct file_operations exynos_drm_gem_fops = {
232}; 243};
233 244
234int exynos_drm_gem_mmap_ioctl(struct drm_device *dev, void *data, 245int exynos_drm_gem_mmap_ioctl(struct drm_device *dev, void *data,
235 struct drm_file *file_priv) 246 struct drm_file *file_priv)
236{ 247{
237 struct drm_exynos_gem_mmap *args = data; 248 struct drm_exynos_gem_mmap *args = data;
238 struct drm_gem_object *obj; 249 struct drm_gem_object *obj;
@@ -278,32 +289,19 @@ int exynos_drm_gem_init_object(struct drm_gem_object *obj)
278 return 0; 289 return 0;
279} 290}
280 291
281void exynos_drm_gem_free_object(struct drm_gem_object *gem_obj) 292void exynos_drm_gem_free_object(struct drm_gem_object *obj)
282{ 293{
283 struct exynos_drm_gem_obj *exynos_gem_obj;
284
285 DRM_DEBUG_KMS("%s\n", __FILE__); 294 DRM_DEBUG_KMS("%s\n", __FILE__);
286 295
287 DRM_DEBUG_KMS("handle count = %d\n", 296 exynos_drm_gem_destroy(to_exynos_gem_obj(obj));
288 atomic_read(&gem_obj->handle_count));
289
290 if (gem_obj->map_list.map)
291 drm_gem_free_mmap_offset(gem_obj);
292
293 /* release file pointer to gem object. */
294 drm_gem_object_release(gem_obj);
295
296 exynos_gem_obj = to_exynos_gem_obj(gem_obj);
297
298 exynos_drm_buf_destroy(gem_obj->dev, exynos_gem_obj->buffer);
299
300 kfree(exynos_gem_obj);
301} 297}
302 298
303int exynos_drm_gem_dumb_create(struct drm_file *file_priv, 299int exynos_drm_gem_dumb_create(struct drm_file *file_priv,
304 struct drm_device *dev, struct drm_mode_create_dumb *args) 300 struct drm_device *dev,
301 struct drm_mode_create_dumb *args)
305{ 302{
306 struct exynos_drm_gem_obj *exynos_gem_obj; 303 struct exynos_drm_gem_obj *exynos_gem_obj;
304 int ret;
307 305
308 DRM_DEBUG_KMS("%s\n", __FILE__); 306 DRM_DEBUG_KMS("%s\n", __FILE__);
309 307
@@ -316,19 +314,27 @@ int exynos_drm_gem_dumb_create(struct drm_file *file_priv,
316 args->pitch = args->width * args->bpp >> 3; 314 args->pitch = args->width * args->bpp >> 3;
317 args->size = args->pitch * args->height; 315 args->size = args->pitch * args->height;
318 316
319 exynos_gem_obj = exynos_drm_gem_create(dev, file_priv, &args->handle, 317 exynos_gem_obj = exynos_drm_gem_create(dev, args->size);
320 args->size);
321 if (IS_ERR(exynos_gem_obj)) 318 if (IS_ERR(exynos_gem_obj))
322 return PTR_ERR(exynos_gem_obj); 319 return PTR_ERR(exynos_gem_obj);
323 320
321 ret = exynos_drm_gem_handle_create(&exynos_gem_obj->base, file_priv,
322 &args->handle);
323 if (ret) {
324 exynos_drm_gem_destroy(exynos_gem_obj);
325 return ret;
326 }
327
324 return 0; 328 return 0;
325} 329}
326 330
327int exynos_drm_gem_dumb_map_offset(struct drm_file *file_priv, 331int exynos_drm_gem_dumb_map_offset(struct drm_file *file_priv,
328 struct drm_device *dev, uint32_t handle, uint64_t *offset) 332 struct drm_device *dev, uint32_t handle,
333 uint64_t *offset)
329{ 334{
330 struct exynos_drm_gem_obj *exynos_gem_obj; 335 struct exynos_drm_gem_obj *exynos_gem_obj;
331 struct drm_gem_object *obj; 336 struct drm_gem_object *obj;
337 int ret = 0;
332 338
333 DRM_DEBUG_KMS("%s\n", __FILE__); 339 DRM_DEBUG_KMS("%s\n", __FILE__);
334 340
@@ -343,19 +349,46 @@ int exynos_drm_gem_dumb_map_offset(struct drm_file *file_priv,
343 obj = drm_gem_object_lookup(dev, file_priv, handle); 349 obj = drm_gem_object_lookup(dev, file_priv, handle);
344 if (!obj) { 350 if (!obj) {
345 DRM_ERROR("failed to lookup gem object.\n"); 351 DRM_ERROR("failed to lookup gem object.\n");
346 mutex_unlock(&dev->struct_mutex); 352 ret = -EINVAL;
347 return -EINVAL; 353 goto unlock;
348 } 354 }
349 355
350 exynos_gem_obj = to_exynos_gem_obj(obj); 356 exynos_gem_obj = to_exynos_gem_obj(obj);
351 357
352 *offset = get_gem_mmap_offset(&exynos_gem_obj->base); 358 if (!exynos_gem_obj->base.map_list.map) {
353 359 ret = drm_gem_create_mmap_offset(&exynos_gem_obj->base);
354 drm_gem_object_unreference(obj); 360 if (ret)
361 goto out;
362 }
355 363
364 *offset = (u64)exynos_gem_obj->base.map_list.hash.key << PAGE_SHIFT;
356 DRM_DEBUG_KMS("offset = 0x%lx\n", (unsigned long)*offset); 365 DRM_DEBUG_KMS("offset = 0x%lx\n", (unsigned long)*offset);
357 366
367out:
368 drm_gem_object_unreference(obj);
369unlock:
358 mutex_unlock(&dev->struct_mutex); 370 mutex_unlock(&dev->struct_mutex);
371 return ret;
372}
373
374int exynos_drm_gem_dumb_destroy(struct drm_file *file_priv,
375 struct drm_device *dev,
376 unsigned int handle)
377{
378 int ret;
379
380 DRM_DEBUG_KMS("%s\n", __FILE__);
381
382 /*
383 * obj->refcount and obj->handle_count are decreased and
384 * if both them are 0 then exynos_drm_gem_free_object()
385 * would be called by callback to release resources.
386 */
387 ret = drm_gem_handle_delete(file_priv, handle);
388 if (ret < 0) {
389 DRM_ERROR("failed to delete drm_gem_handle.\n");
390 return ret;
391 }
359 392
360 return 0; 393 return 0;
361} 394}
@@ -403,28 +436,6 @@ int exynos_drm_gem_mmap(struct file *filp, struct vm_area_struct *vma)
403 return ret; 436 return ret;
404} 437}
405 438
406
407int exynos_drm_gem_dumb_destroy(struct drm_file *file_priv,
408 struct drm_device *dev, unsigned int handle)
409{
410 int ret;
411
412 DRM_DEBUG_KMS("%s\n", __FILE__);
413
414 /*
415 * obj->refcount and obj->handle_count are decreased and
416 * if both them are 0 then exynos_drm_gem_free_object()
417 * would be called by callback to release resources.
418 */
419 ret = drm_gem_handle_delete(file_priv, handle);
420 if (ret < 0) {
421 DRM_ERROR("failed to delete drm_gem_handle.\n");
422 return ret;
423 }
424
425 return 0;
426}
427
428MODULE_AUTHOR("Inki Dae <inki.dae@samsung.com>"); 439MODULE_AUTHOR("Inki Dae <inki.dae@samsung.com>");
429MODULE_DESCRIPTION("Samsung SoC DRM GEM Module"); 440MODULE_DESCRIPTION("Samsung SoC DRM GEM Module");
430MODULE_LICENSE("GPL"); 441MODULE_LICENSE("GPL");
diff --git a/drivers/gpu/drm/exynos/exynos_drm_gem.h b/drivers/gpu/drm/exynos/exynos_drm_gem.h
index ef8797334e6d..67cdc9168708 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_gem.h
+++ b/drivers/gpu/drm/exynos/exynos_drm_gem.h
@@ -60,14 +60,16 @@ struct exynos_drm_gem_buf {
60 * user can access the buffer through kms_bo.handle. 60 * user can access the buffer through kms_bo.handle.
61 */ 61 */
62struct exynos_drm_gem_obj { 62struct exynos_drm_gem_obj {
63 struct drm_gem_object base; 63 struct drm_gem_object base;
64 struct exynos_drm_gem_buf *buffer; 64 struct exynos_drm_gem_buf *buffer;
65}; 65};
66 66
67/* create a new buffer and get a new gem handle. */ 67/* destroy a buffer with gem object */
68void exynos_drm_gem_destroy(struct exynos_drm_gem_obj *exynos_gem_obj);
69
70/* create a new buffer with gem object */
68struct exynos_drm_gem_obj *exynos_drm_gem_create(struct drm_device *dev, 71struct exynos_drm_gem_obj *exynos_drm_gem_create(struct drm_device *dev,
69 struct drm_file *file_priv, 72 unsigned long size);
70 unsigned int *handle, unsigned long size);
71 73
72/* 74/*
73 * request gem object creation and buffer allocation as the size 75 * request gem object creation and buffer allocation as the size
@@ -75,15 +77,18 @@ struct exynos_drm_gem_obj *exynos_drm_gem_create(struct drm_device *dev,
75 * height and bpp. 77 * height and bpp.
76 */ 78 */
77int exynos_drm_gem_create_ioctl(struct drm_device *dev, void *data, 79int exynos_drm_gem_create_ioctl(struct drm_device *dev, void *data,
78 struct drm_file *file_priv); 80 struct drm_file *file_priv);
79 81
80/* get buffer offset to map to user space. */ 82/* get buffer offset to map to user space. */
81int exynos_drm_gem_map_offset_ioctl(struct drm_device *dev, void *data, 83int exynos_drm_gem_map_offset_ioctl(struct drm_device *dev, void *data,
82 struct drm_file *file_priv); 84 struct drm_file *file_priv);
83 85
84/* unmap a buffer from user space. */ 86/*
85int exynos_drm_gem_munmap_ioctl(struct drm_device *dev, void *data, 87 * mmap the physically continuous memory that a gem object contains
86 struct drm_file *file_priv); 88 * to user space.
89 */
90int exynos_drm_gem_mmap_ioctl(struct drm_device *dev, void *data,
91 struct drm_file *file_priv);
87 92
88/* initialize gem object. */ 93/* initialize gem object. */
89int exynos_drm_gem_init_object(struct drm_gem_object *obj); 94int exynos_drm_gem_init_object(struct drm_gem_object *obj);
@@ -93,24 +98,13 @@ void exynos_drm_gem_free_object(struct drm_gem_object *gem_obj);
93 98
94/* create memory region for drm framebuffer. */ 99/* create memory region for drm framebuffer. */
95int exynos_drm_gem_dumb_create(struct drm_file *file_priv, 100int exynos_drm_gem_dumb_create(struct drm_file *file_priv,
96 struct drm_device *dev, struct drm_mode_create_dumb *args); 101 struct drm_device *dev,
102 struct drm_mode_create_dumb *args);
97 103
98/* map memory region for drm framebuffer to user space. */ 104/* map memory region for drm framebuffer to user space. */
99int exynos_drm_gem_dumb_map_offset(struct drm_file *file_priv, 105int exynos_drm_gem_dumb_map_offset(struct drm_file *file_priv,
100 struct drm_device *dev, uint32_t handle, uint64_t *offset); 106 struct drm_device *dev, uint32_t handle,
101 107 uint64_t *offset);
102/* page fault handler and mmap fault address(virtual) to physical memory. */
103int exynos_drm_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf);
104
105/*
106 * mmap the physically continuous memory that a gem object contains
107 * to user space.
108 */
109int exynos_drm_gem_mmap_ioctl(struct drm_device *dev, void *data,
110 struct drm_file *file_priv);
111
112/* set vm_flags and we can change the vm attribute to other one at here. */
113int exynos_drm_gem_mmap(struct file *filp, struct vm_area_struct *vma);
114 108
115/* 109/*
116 * destroy memory region allocated. 110 * destroy memory region allocated.
@@ -118,6 +112,13 @@ int exynos_drm_gem_mmap(struct file *filp, struct vm_area_struct *vma);
118 * would be released by drm_gem_handle_delete(). 112 * would be released by drm_gem_handle_delete().
119 */ 113 */
120int exynos_drm_gem_dumb_destroy(struct drm_file *file_priv, 114int exynos_drm_gem_dumb_destroy(struct drm_file *file_priv,
121 struct drm_device *dev, unsigned int handle); 115 struct drm_device *dev,
116 unsigned int handle);
117
118/* page fault handler and mmap fault address(virtual) to physical memory. */
119int exynos_drm_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf);
120
121/* set vm_flags and we can change the vm attribute to other one at here. */
122int exynos_drm_gem_mmap(struct file *filp, struct vm_area_struct *vma);
122 123
123#endif 124#endif
diff --git a/drivers/gpu/drm/exynos/exynos_drm_hdmi.c b/drivers/gpu/drm/exynos/exynos_drm_hdmi.c
new file mode 100644
index 000000000000..ed8a319ed84b
--- /dev/null
+++ b/drivers/gpu/drm/exynos/exynos_drm_hdmi.c
@@ -0,0 +1,439 @@
1/*
2 * Copyright (C) 2011 Samsung Electronics Co.Ltd
3 * Authors:
4 * Inki Dae <inki.dae@samsung.com>
5 * Seung-Woo Kim <sw0312.kim@samsung.com>
6 *
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the
9 * Free Software Foundation; either version 2 of the License, or (at your
10 * option) any later version.
11 *
12 */
13
14#include "drmP.h"
15
16#include <linux/kernel.h>
17#include <linux/wait.h>
18#include <linux/module.h>
19#include <linux/platform_device.h>
20#include <linux/pm_runtime.h>
21
22#include <drm/exynos_drm.h>
23
24#include "exynos_drm_drv.h"
25#include "exynos_drm_hdmi.h"
26
27#define to_context(dev) platform_get_drvdata(to_platform_device(dev))
28#define to_subdrv(dev) to_context(dev)
29#define get_ctx_from_subdrv(subdrv) container_of(subdrv,\
30 struct drm_hdmi_context, subdrv);
31
32/* these callback points shoud be set by specific drivers. */
33static struct exynos_hdmi_display_ops *hdmi_display_ops;
34static struct exynos_hdmi_manager_ops *hdmi_manager_ops;
35static struct exynos_hdmi_overlay_ops *hdmi_overlay_ops;
36
37struct drm_hdmi_context {
38 struct exynos_drm_subdrv subdrv;
39 struct exynos_drm_hdmi_context *hdmi_ctx;
40 struct exynos_drm_hdmi_context *mixer_ctx;
41 struct work_struct work;
42};
43
44void exynos_drm_display_ops_register(struct exynos_hdmi_display_ops
45 *display_ops)
46{
47 DRM_DEBUG_KMS("%s\n", __FILE__);
48
49 if (display_ops)
50 hdmi_display_ops = display_ops;
51}
52EXPORT_SYMBOL(exynos_drm_display_ops_register);
53
54void exynos_drm_manager_ops_register(struct exynos_hdmi_manager_ops
55 *manager_ops)
56{
57 DRM_DEBUG_KMS("%s\n", __FILE__);
58
59 if (manager_ops)
60 hdmi_manager_ops = manager_ops;
61}
62EXPORT_SYMBOL(exynos_drm_manager_ops_register);
63
64void exynos_drm_overlay_ops_register(struct exynos_hdmi_overlay_ops
65 *overlay_ops)
66{
67 DRM_DEBUG_KMS("%s\n", __FILE__);
68
69 if (overlay_ops)
70 hdmi_overlay_ops = overlay_ops;
71}
72EXPORT_SYMBOL(exynos_drm_overlay_ops_register);
73
74static bool drm_hdmi_is_connected(struct device *dev)
75{
76 struct drm_hdmi_context *ctx = to_context(dev);
77
78 DRM_DEBUG_KMS("%s\n", __FILE__);
79
80 if (hdmi_display_ops && hdmi_display_ops->is_connected)
81 return hdmi_display_ops->is_connected(ctx->hdmi_ctx->ctx);
82
83 return false;
84}
85
86static int drm_hdmi_get_edid(struct device *dev,
87 struct drm_connector *connector, u8 *edid, int len)
88{
89 struct drm_hdmi_context *ctx = to_context(dev);
90
91 DRM_DEBUG_KMS("%s\n", __FILE__);
92
93 if (hdmi_display_ops && hdmi_display_ops->get_edid)
94 return hdmi_display_ops->get_edid(ctx->hdmi_ctx->ctx,
95 connector, edid, len);
96
97 return 0;
98}
99
100static int drm_hdmi_check_timing(struct device *dev, void *timing)
101{
102 struct drm_hdmi_context *ctx = to_context(dev);
103
104 DRM_DEBUG_KMS("%s\n", __FILE__);
105
106 if (hdmi_display_ops && hdmi_display_ops->check_timing)
107 return hdmi_display_ops->check_timing(ctx->hdmi_ctx->ctx,
108 timing);
109
110 return 0;
111}
112
113static int drm_hdmi_power_on(struct device *dev, int mode)
114{
115 struct drm_hdmi_context *ctx = to_context(dev);
116
117 DRM_DEBUG_KMS("%s\n", __FILE__);
118
119 if (hdmi_display_ops && hdmi_display_ops->power_on)
120 return hdmi_display_ops->power_on(ctx->hdmi_ctx->ctx, mode);
121
122 return 0;
123}
124
125static struct exynos_drm_display_ops drm_hdmi_display_ops = {
126 .type = EXYNOS_DISPLAY_TYPE_HDMI,
127 .is_connected = drm_hdmi_is_connected,
128 .get_edid = drm_hdmi_get_edid,
129 .check_timing = drm_hdmi_check_timing,
130 .power_on = drm_hdmi_power_on,
131};
132
133static int drm_hdmi_enable_vblank(struct device *subdrv_dev)
134{
135 struct drm_hdmi_context *ctx = to_context(subdrv_dev);
136 struct exynos_drm_subdrv *subdrv = &ctx->subdrv;
137 struct exynos_drm_manager *manager = &subdrv->manager;
138
139 DRM_DEBUG_KMS("%s\n", __FILE__);
140
141 if (hdmi_overlay_ops && hdmi_overlay_ops->enable_vblank)
142 return hdmi_overlay_ops->enable_vblank(ctx->mixer_ctx->ctx,
143 manager->pipe);
144
145 return 0;
146}
147
148static void drm_hdmi_disable_vblank(struct device *subdrv_dev)
149{
150 struct drm_hdmi_context *ctx = to_context(subdrv_dev);
151
152 DRM_DEBUG_KMS("%s\n", __FILE__);
153
154 if (hdmi_overlay_ops && hdmi_overlay_ops->disable_vblank)
155 return hdmi_overlay_ops->disable_vblank(ctx->mixer_ctx->ctx);
156}
157
158static void drm_hdmi_mode_set(struct device *subdrv_dev, void *mode)
159{
160 struct drm_hdmi_context *ctx = to_context(subdrv_dev);
161
162 DRM_DEBUG_KMS("%s\n", __FILE__);
163
164 if (hdmi_manager_ops && hdmi_manager_ops->mode_set)
165 hdmi_manager_ops->mode_set(ctx->hdmi_ctx->ctx, mode);
166}
167
168static void drm_hdmi_commit(struct device *subdrv_dev)
169{
170 struct drm_hdmi_context *ctx = to_context(subdrv_dev);
171
172 DRM_DEBUG_KMS("%s\n", __FILE__);
173
174 if (hdmi_manager_ops && hdmi_manager_ops->commit)
175 hdmi_manager_ops->commit(ctx->hdmi_ctx->ctx);
176}
177
178static void drm_hdmi_dpms(struct device *subdrv_dev, int mode)
179{
180 struct drm_hdmi_context *ctx = to_context(subdrv_dev);
181
182 DRM_DEBUG_KMS("%s\n", __FILE__);
183
184 switch (mode) {
185 case DRM_MODE_DPMS_ON:
186 break;
187 case DRM_MODE_DPMS_STANDBY:
188 case DRM_MODE_DPMS_SUSPEND:
189 case DRM_MODE_DPMS_OFF:
190 if (hdmi_manager_ops && hdmi_manager_ops->disable)
191 hdmi_manager_ops->disable(ctx->hdmi_ctx->ctx);
192 break;
193 default:
194 DRM_DEBUG_KMS("unkown dps mode: %d\n", mode);
195 break;
196 }
197}
198
199static struct exynos_drm_manager_ops drm_hdmi_manager_ops = {
200 .dpms = drm_hdmi_dpms,
201 .enable_vblank = drm_hdmi_enable_vblank,
202 .disable_vblank = drm_hdmi_disable_vblank,
203 .mode_set = drm_hdmi_mode_set,
204 .commit = drm_hdmi_commit,
205};
206
207static void drm_mixer_mode_set(struct device *subdrv_dev,
208 struct exynos_drm_overlay *overlay)
209{
210 struct drm_hdmi_context *ctx = to_context(subdrv_dev);
211
212 DRM_DEBUG_KMS("%s\n", __FILE__);
213
214 if (hdmi_overlay_ops && hdmi_overlay_ops->win_mode_set)
215 hdmi_overlay_ops->win_mode_set(ctx->mixer_ctx->ctx, overlay);
216}
217
218static void drm_mixer_commit(struct device *subdrv_dev, int zpos)
219{
220 struct drm_hdmi_context *ctx = to_context(subdrv_dev);
221
222 DRM_DEBUG_KMS("%s\n", __FILE__);
223
224 if (hdmi_overlay_ops && hdmi_overlay_ops->win_commit)
225 hdmi_overlay_ops->win_commit(ctx->mixer_ctx->ctx, zpos);
226}
227
228static void drm_mixer_disable(struct device *subdrv_dev, int zpos)
229{
230 struct drm_hdmi_context *ctx = to_context(subdrv_dev);
231
232 DRM_DEBUG_KMS("%s\n", __FILE__);
233
234 if (hdmi_overlay_ops && hdmi_overlay_ops->win_disable)
235 hdmi_overlay_ops->win_disable(ctx->mixer_ctx->ctx, zpos);
236}
237
238static struct exynos_drm_overlay_ops drm_hdmi_overlay_ops = {
239 .mode_set = drm_mixer_mode_set,
240 .commit = drm_mixer_commit,
241 .disable = drm_mixer_disable,
242};
243
244
245static int hdmi_subdrv_probe(struct drm_device *drm_dev,
246 struct device *dev)
247{
248 struct exynos_drm_subdrv *subdrv = to_subdrv(dev);
249 struct drm_hdmi_context *ctx;
250 struct platform_device *pdev = to_platform_device(dev);
251 struct exynos_drm_common_hdmi_pd *pd;
252 int ret;
253
254 DRM_DEBUG_KMS("%s\n", __FILE__);
255
256 pd = pdev->dev.platform_data;
257
258 if (!pd) {
259 DRM_DEBUG_KMS("platform data is null.\n");
260 return -EFAULT;
261 }
262
263 if (!pd->hdmi_dev) {
264 DRM_DEBUG_KMS("hdmi device is null.\n");
265 return -EFAULT;
266 }
267
268 if (!pd->mixer_dev) {
269 DRM_DEBUG_KMS("mixer device is null.\n");
270 return -EFAULT;
271 }
272
273 ret = platform_driver_register(&hdmi_driver);
274 if (ret) {
275 DRM_DEBUG_KMS("failed to register hdmi driver.\n");
276 return ret;
277 }
278
279 ret = platform_driver_register(&mixer_driver);
280 if (ret) {
281 DRM_DEBUG_KMS("failed to register mixer driver.\n");
282 goto err_hdmidrv;
283 }
284
285 ctx = get_ctx_from_subdrv(subdrv);
286
287 ctx->hdmi_ctx = (struct exynos_drm_hdmi_context *)
288 to_context(pd->hdmi_dev);
289 if (!ctx->hdmi_ctx) {
290 DRM_DEBUG_KMS("hdmi context is null.\n");
291 ret = -EFAULT;
292 goto err_mixerdrv;
293 }
294
295 ctx->hdmi_ctx->drm_dev = drm_dev;
296
297 ctx->mixer_ctx = (struct exynos_drm_hdmi_context *)
298 to_context(pd->mixer_dev);
299 if (!ctx->mixer_ctx) {
300 DRM_DEBUG_KMS("mixer context is null.\n");
301 ret = -EFAULT;
302 goto err_mixerdrv;
303 }
304
305 ctx->mixer_ctx->drm_dev = drm_dev;
306
307 return 0;
308
309err_mixerdrv:
310 platform_driver_unregister(&mixer_driver);
311err_hdmidrv:
312 platform_driver_unregister(&hdmi_driver);
313 return ret;
314}
315
316static void hdmi_subdrv_remove(struct drm_device *drm_dev)
317{
318 DRM_DEBUG_KMS("%s\n", __FILE__);
319
320 platform_driver_unregister(&hdmi_driver);
321 platform_driver_unregister(&mixer_driver);
322}
323
324static void exynos_drm_hdmi_late_probe(struct work_struct *work)
325{
326 struct drm_hdmi_context *ctx = container_of(work,
327 struct drm_hdmi_context, work);
328
329 /*
330 * this function calls subdrv->probe() so this must be called
331 * after probe context.
332 *
333 * PS. subdrv->probe() will call platform_driver_register() to probe
334 * hdmi and mixer driver.
335 */
336 exynos_drm_subdrv_register(&ctx->subdrv);
337}
338
339static int __devinit exynos_drm_hdmi_probe(struct platform_device *pdev)
340{
341 struct device *dev = &pdev->dev;
342 struct exynos_drm_subdrv *subdrv;
343 struct drm_hdmi_context *ctx;
344
345 DRM_DEBUG_KMS("%s\n", __FILE__);
346
347 ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
348 if (!ctx) {
349 DRM_LOG_KMS("failed to alloc common hdmi context.\n");
350 return -ENOMEM;
351 }
352
353 subdrv = &ctx->subdrv;
354
355 subdrv->probe = hdmi_subdrv_probe;
356 subdrv->remove = hdmi_subdrv_remove;
357 subdrv->manager.pipe = -1;
358 subdrv->manager.ops = &drm_hdmi_manager_ops;
359 subdrv->manager.overlay_ops = &drm_hdmi_overlay_ops;
360 subdrv->manager.display_ops = &drm_hdmi_display_ops;
361 subdrv->manager.dev = dev;
362
363 platform_set_drvdata(pdev, subdrv);
364
365 INIT_WORK(&ctx->work, exynos_drm_hdmi_late_probe);
366
367 schedule_work(&ctx->work);
368
369 return 0;
370}
371
372static int hdmi_runtime_suspend(struct device *dev)
373{
374 DRM_DEBUG_KMS("%s\n", __FILE__);
375
376 return 0;
377}
378
379static int hdmi_runtime_resume(struct device *dev)
380{
381 DRM_DEBUG_KMS("%s\n", __FILE__);
382
383 return 0;
384}
385
386static const struct dev_pm_ops hdmi_pm_ops = {
387 .runtime_suspend = hdmi_runtime_suspend,
388 .runtime_resume = hdmi_runtime_resume,
389};
390
391static int __devexit exynos_drm_hdmi_remove(struct platform_device *pdev)
392{
393 struct drm_hdmi_context *ctx = platform_get_drvdata(pdev);
394
395 DRM_DEBUG_KMS("%s\n", __FILE__);
396
397 exynos_drm_subdrv_unregister(&ctx->subdrv);
398 kfree(ctx);
399
400 return 0;
401}
402
403static struct platform_driver exynos_drm_common_hdmi_driver = {
404 .probe = exynos_drm_hdmi_probe,
405 .remove = __devexit_p(exynos_drm_hdmi_remove),
406 .driver = {
407 .name = "exynos-drm-hdmi",
408 .owner = THIS_MODULE,
409 .pm = &hdmi_pm_ops,
410 },
411};
412
413static int __init exynos_drm_hdmi_init(void)
414{
415 int ret;
416
417 DRM_DEBUG_KMS("%s\n", __FILE__);
418
419 ret = platform_driver_register(&exynos_drm_common_hdmi_driver);
420 if (ret) {
421 DRM_DEBUG_KMS("failed to register hdmi common driver.\n");
422 return ret;
423 }
424
425 return ret;
426}
427
428static void __exit exynos_drm_hdmi_exit(void)
429{
430 platform_driver_unregister(&exynos_drm_common_hdmi_driver);
431}
432
433module_init(exynos_drm_hdmi_init);
434module_exit(exynos_drm_hdmi_exit);
435
436MODULE_AUTHOR("Inki Dae <inki.dae@samsung.com>");
437MODULE_AUTHOR("Seung-Woo Kim, <sw0312.kim@samsung.com>");
438MODULE_DESCRIPTION("Samsung SoC DRM HDMI Driver");
439MODULE_LICENSE("GPL");
diff --git a/drivers/gpu/drm/exynos/exynos_drm_hdmi.h b/drivers/gpu/drm/exynos/exynos_drm_hdmi.h
new file mode 100644
index 000000000000..3c29f790ee45
--- /dev/null
+++ b/drivers/gpu/drm/exynos/exynos_drm_hdmi.h
@@ -0,0 +1,73 @@
1/* exynos_drm_hdmi.h
2 *
3 * Copyright (c) 2011 Samsung Electronics Co., Ltd.
4 * Authoer: Inki Dae <inki.dae@samsung.com>
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the "Software"),
8 * to deal in the Software without restriction, including without limitation
9 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10 * and/or sell copies of the Software, and to permit persons to whom the
11 * Software is furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice (including the next
14 * paragraph) shall be included in all copies or substantial portions of the
15 * Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20 * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
21 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
22 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
23 * OTHER DEALINGS IN THE SOFTWARE.
24 */
25
26#ifndef _EXYNOS_DRM_HDMI_H_
27#define _EXYNOS_DRM_HDMI_H_
28
29/*
30 * exynos hdmi common context structure.
31 *
32 * @drm_dev: pointer to drm_device.
33 * @ctx: pointer to the context of specific device driver.
34 * this context should be hdmi_context or mixer_context.
35 */
36struct exynos_drm_hdmi_context {
37 struct drm_device *drm_dev;
38 void *ctx;
39};
40
41struct exynos_hdmi_display_ops {
42 bool (*is_connected)(void *ctx);
43 int (*get_edid)(void *ctx, struct drm_connector *connector,
44 u8 *edid, int len);
45 int (*check_timing)(void *ctx, void *timing);
46 int (*power_on)(void *ctx, int mode);
47};
48
49struct exynos_hdmi_manager_ops {
50 void (*mode_set)(void *ctx, void *mode);
51 void (*commit)(void *ctx);
52 void (*disable)(void *ctx);
53};
54
55struct exynos_hdmi_overlay_ops {
56 int (*enable_vblank)(void *ctx, int pipe);
57 void (*disable_vblank)(void *ctx);
58 void (*win_mode_set)(void *ctx, struct exynos_drm_overlay *overlay);
59 void (*win_commit)(void *ctx, int zpos);
60 void (*win_disable)(void *ctx, int zpos);
61};
62
63extern struct platform_driver hdmi_driver;
64extern struct platform_driver mixer_driver;
65
66void exynos_drm_display_ops_register(struct exynos_hdmi_display_ops
67 *display_ops);
68void exynos_drm_manager_ops_register(struct exynos_hdmi_manager_ops
69 *manager_ops);
70void exynos_drm_overlay_ops_register(struct exynos_hdmi_overlay_ops
71 *overlay_ops);
72
73#endif
diff --git a/drivers/gpu/drm/exynos/exynos_hdmi.c b/drivers/gpu/drm/exynos/exynos_hdmi.c
new file mode 100644
index 000000000000..f48f7ce92f5f
--- /dev/null
+++ b/drivers/gpu/drm/exynos/exynos_hdmi.c
@@ -0,0 +1,1176 @@
1/*
2 * Copyright (C) 2011 Samsung Electronics Co.Ltd
3 * Authors:
4 * Seung-Woo Kim <sw0312.kim@samsung.com>
5 * Inki Dae <inki.dae@samsung.com>
6 * Joonyoung Shim <jy0922.shim@samsung.com>
7 *
8 * Based on drivers/media/video/s5p-tv/hdmi_drv.c
9 *
10 * This program is free software; you can redistribute it and/or modify it
11 * under the terms of the GNU General Public License as published by the
12 * Free Software Foundation; either version 2 of the License, or (at your
13 * option) any later version.
14 *
15 */
16
17#include "drmP.h"
18#include "drm_edid.h"
19#include "drm_crtc_helper.h"
20
21#include "regs-hdmi.h"
22
23#include <linux/kernel.h>
24#include <linux/spinlock.h>
25#include <linux/wait.h>
26#include <linux/i2c.h>
27#include <linux/module.h>
28#include <linux/platform_device.h>
29#include <linux/interrupt.h>
30#include <linux/irq.h>
31#include <linux/delay.h>
32#include <linux/pm_runtime.h>
33#include <linux/clk.h>
34#include <linux/regulator/consumer.h>
35
36#include <drm/exynos_drm.h>
37
38#include "exynos_drm_drv.h"
39#include "exynos_drm_hdmi.h"
40
41#include "exynos_hdmi.h"
42
43#define HDMI_OVERLAY_NUMBER 3
44#define get_hdmi_context(dev) platform_get_drvdata(to_platform_device(dev))
45
46static const u8 hdmiphy_conf27[32] = {
47 0x01, 0x05, 0x00, 0xD8, 0x10, 0x1C, 0x30, 0x40,
48 0x6B, 0x10, 0x02, 0x51, 0xDF, 0xF2, 0x54, 0x87,
49 0x84, 0x00, 0x30, 0x38, 0x00, 0x08, 0x10, 0xE0,
50 0x22, 0x40, 0xE3, 0x26, 0x00, 0x00, 0x00, 0x00,
51};
52
53static const u8 hdmiphy_conf27_027[32] = {
54 0x01, 0x05, 0x00, 0xD4, 0x10, 0x9C, 0x09, 0x64,
55 0x6B, 0x10, 0x02, 0x51, 0xDF, 0xF2, 0x54, 0x87,
56 0x84, 0x00, 0x30, 0x38, 0x00, 0x08, 0x10, 0xE0,
57 0x22, 0x40, 0xE3, 0x26, 0x00, 0x00, 0x00, 0x00,
58};
59
60static const u8 hdmiphy_conf74_175[32] = {
61 0x01, 0x05, 0x00, 0xD8, 0x10, 0x9C, 0xef, 0x5B,
62 0x6D, 0x10, 0x01, 0x51, 0xef, 0xF3, 0x54, 0xb9,
63 0x84, 0x00, 0x30, 0x38, 0x00, 0x08, 0x10, 0xE0,
64 0x22, 0x40, 0xa5, 0x26, 0x01, 0x00, 0x00, 0x00,
65};
66
67static const u8 hdmiphy_conf74_25[32] = {
68 0x01, 0x05, 0x00, 0xd8, 0x10, 0x9c, 0xf8, 0x40,
69 0x6a, 0x10, 0x01, 0x51, 0xff, 0xf1, 0x54, 0xba,
70 0x84, 0x00, 0x10, 0x38, 0x00, 0x08, 0x10, 0xe0,
71 0x22, 0x40, 0xa4, 0x26, 0x01, 0x00, 0x00, 0x00,
72};
73
74static const u8 hdmiphy_conf148_5[32] = {
75 0x01, 0x05, 0x00, 0xD8, 0x10, 0x9C, 0xf8, 0x40,
76 0x6A, 0x18, 0x00, 0x51, 0xff, 0xF1, 0x54, 0xba,
77 0x84, 0x00, 0x10, 0x38, 0x00, 0x08, 0x10, 0xE0,
78 0x22, 0x40, 0xa4, 0x26, 0x02, 0x00, 0x00, 0x00,
79};
80
81struct hdmi_tg_regs {
82 u8 cmd;
83 u8 h_fsz_l;
84 u8 h_fsz_h;
85 u8 hact_st_l;
86 u8 hact_st_h;
87 u8 hact_sz_l;
88 u8 hact_sz_h;
89 u8 v_fsz_l;
90 u8 v_fsz_h;
91 u8 vsync_l;
92 u8 vsync_h;
93 u8 vsync2_l;
94 u8 vsync2_h;
95 u8 vact_st_l;
96 u8 vact_st_h;
97 u8 vact_sz_l;
98 u8 vact_sz_h;
99 u8 field_chg_l;
100 u8 field_chg_h;
101 u8 vact_st2_l;
102 u8 vact_st2_h;
103 u8 vsync_top_hdmi_l;
104 u8 vsync_top_hdmi_h;
105 u8 vsync_bot_hdmi_l;
106 u8 vsync_bot_hdmi_h;
107 u8 field_top_hdmi_l;
108 u8 field_top_hdmi_h;
109 u8 field_bot_hdmi_l;
110 u8 field_bot_hdmi_h;
111};
112
113struct hdmi_core_regs {
114 u8 h_blank[2];
115 u8 v_blank[3];
116 u8 h_v_line[3];
117 u8 vsync_pol[1];
118 u8 int_pro_mode[1];
119 u8 v_blank_f[3];
120 u8 h_sync_gen[3];
121 u8 v_sync_gen1[3];
122 u8 v_sync_gen2[3];
123 u8 v_sync_gen3[3];
124};
125
126struct hdmi_preset_conf {
127 struct hdmi_core_regs core;
128 struct hdmi_tg_regs tg;
129};
130
131static const struct hdmi_preset_conf hdmi_conf_480p = {
132 .core = {
133 .h_blank = {0x8a, 0x00},
134 .v_blank = {0x0d, 0x6a, 0x01},
135 .h_v_line = {0x0d, 0xa2, 0x35},
136 .vsync_pol = {0x01},
137 .int_pro_mode = {0x00},
138 .v_blank_f = {0x00, 0x00, 0x00},
139 .h_sync_gen = {0x0e, 0x30, 0x11},
140 .v_sync_gen1 = {0x0f, 0x90, 0x00},
141 /* other don't care */
142 },
143 .tg = {
144 0x00, /* cmd */
145 0x5a, 0x03, /* h_fsz */
146 0x8a, 0x00, 0xd0, 0x02, /* hact */
147 0x0d, 0x02, /* v_fsz */
148 0x01, 0x00, 0x33, 0x02, /* vsync */
149 0x2d, 0x00, 0xe0, 0x01, /* vact */
150 0x33, 0x02, /* field_chg */
151 0x49, 0x02, /* vact_st2 */
152 0x01, 0x00, 0x33, 0x02, /* vsync top/bot */
153 0x01, 0x00, 0x33, 0x02, /* field top/bot */
154 },
155};
156
157static const struct hdmi_preset_conf hdmi_conf_720p60 = {
158 .core = {
159 .h_blank = {0x72, 0x01},
160 .v_blank = {0xee, 0xf2, 0x00},
161 .h_v_line = {0xee, 0x22, 0x67},
162 .vsync_pol = {0x00},
163 .int_pro_mode = {0x00},
164 .v_blank_f = {0x00, 0x00, 0x00}, /* don't care */
165 .h_sync_gen = {0x6c, 0x50, 0x02},
166 .v_sync_gen1 = {0x0a, 0x50, 0x00},
167 .v_sync_gen2 = {0x01, 0x10, 0x00},
168 .v_sync_gen3 = {0x01, 0x10, 0x00},
169 /* other don't care */
170 },
171 .tg = {
172 0x00, /* cmd */
173 0x72, 0x06, /* h_fsz */
174 0x71, 0x01, 0x01, 0x05, /* hact */
175 0xee, 0x02, /* v_fsz */
176 0x01, 0x00, 0x33, 0x02, /* vsync */
177 0x1e, 0x00, 0xd0, 0x02, /* vact */
178 0x33, 0x02, /* field_chg */
179 0x49, 0x02, /* vact_st2 */
180 0x01, 0x00, 0x01, 0x00, /* vsync top/bot */
181 0x01, 0x00, 0x33, 0x02, /* field top/bot */
182 },
183};
184
185static const struct hdmi_preset_conf hdmi_conf_1080i50 = {
186 .core = {
187 .h_blank = {0xd0, 0x02},
188 .v_blank = {0x32, 0xB2, 0x00},
189 .h_v_line = {0x65, 0x04, 0xa5},
190 .vsync_pol = {0x00},
191 .int_pro_mode = {0x01},
192 .v_blank_f = {0x49, 0x2A, 0x23},
193 .h_sync_gen = {0x0E, 0xEA, 0x08},
194 .v_sync_gen1 = {0x07, 0x20, 0x00},
195 .v_sync_gen2 = {0x39, 0x42, 0x23},
196 .v_sync_gen3 = {0x38, 0x87, 0x73},
197 /* other don't care */
198 },
199 .tg = {
200 0x00, /* cmd */
201 0x50, 0x0A, /* h_fsz */
202 0xCF, 0x02, 0x81, 0x07, /* hact */
203 0x65, 0x04, /* v_fsz */
204 0x01, 0x00, 0x33, 0x02, /* vsync */
205 0x16, 0x00, 0x1c, 0x02, /* vact */
206 0x33, 0x02, /* field_chg */
207 0x49, 0x02, /* vact_st2 */
208 0x01, 0x00, 0x33, 0x02, /* vsync top/bot */
209 0x01, 0x00, 0x33, 0x02, /* field top/bot */
210 },
211};
212
213static const struct hdmi_preset_conf hdmi_conf_1080p50 = {
214 .core = {
215 .h_blank = {0xd0, 0x02},
216 .v_blank = {0x65, 0x6c, 0x01},
217 .h_v_line = {0x65, 0x04, 0xa5},
218 .vsync_pol = {0x00},
219 .int_pro_mode = {0x00},
220 .v_blank_f = {0x00, 0x00, 0x00}, /* don't care */
221 .h_sync_gen = {0x0e, 0xea, 0x08},
222 .v_sync_gen1 = {0x09, 0x40, 0x00},
223 .v_sync_gen2 = {0x01, 0x10, 0x00},
224 .v_sync_gen3 = {0x01, 0x10, 0x00},
225 /* other don't care */
226 },
227 .tg = {
228 0x00, /* cmd */
229 0x50, 0x0A, /* h_fsz */
230 0xCF, 0x02, 0x81, 0x07, /* hact */
231 0x65, 0x04, /* v_fsz */
232 0x01, 0x00, 0x33, 0x02, /* vsync */
233 0x2d, 0x00, 0x38, 0x04, /* vact */
234 0x33, 0x02, /* field_chg */
235 0x48, 0x02, /* vact_st2 */
236 0x01, 0x00, 0x01, 0x00, /* vsync top/bot */
237 0x01, 0x00, 0x33, 0x02, /* field top/bot */
238 },
239};
240
241static const struct hdmi_preset_conf hdmi_conf_1080i60 = {
242 .core = {
243 .h_blank = {0x18, 0x01},
244 .v_blank = {0x32, 0xB2, 0x00},
245 .h_v_line = {0x65, 0x84, 0x89},
246 .vsync_pol = {0x00},
247 .int_pro_mode = {0x01},
248 .v_blank_f = {0x49, 0x2A, 0x23},
249 .h_sync_gen = {0x56, 0x08, 0x02},
250 .v_sync_gen1 = {0x07, 0x20, 0x00},
251 .v_sync_gen2 = {0x39, 0x42, 0x23},
252 .v_sync_gen3 = {0xa4, 0x44, 0x4a},
253 /* other don't care */
254 },
255 .tg = {
256 0x00, /* cmd */
257 0x98, 0x08, /* h_fsz */
258 0x17, 0x01, 0x81, 0x07, /* hact */
259 0x65, 0x04, /* v_fsz */
260 0x01, 0x00, 0x33, 0x02, /* vsync */
261 0x16, 0x00, 0x1c, 0x02, /* vact */
262 0x33, 0x02, /* field_chg */
263 0x49, 0x02, /* vact_st2 */
264 0x01, 0x00, 0x33, 0x02, /* vsync top/bot */
265 0x01, 0x00, 0x33, 0x02, /* field top/bot */
266 },
267};
268
269static const struct hdmi_preset_conf hdmi_conf_1080p60 = {
270 .core = {
271 .h_blank = {0x18, 0x01},
272 .v_blank = {0x65, 0x6c, 0x01},
273 .h_v_line = {0x65, 0x84, 0x89},
274 .vsync_pol = {0x00},
275 .int_pro_mode = {0x00},
276 .v_blank_f = {0x00, 0x00, 0x00}, /* don't care */
277 .h_sync_gen = {0x56, 0x08, 0x02},
278 .v_sync_gen1 = {0x09, 0x40, 0x00},
279 .v_sync_gen2 = {0x01, 0x10, 0x00},
280 .v_sync_gen3 = {0x01, 0x10, 0x00},
281 /* other don't care */
282 },
283 .tg = {
284 0x00, /* cmd */
285 0x98, 0x08, /* h_fsz */
286 0x17, 0x01, 0x81, 0x07, /* hact */
287 0x65, 0x04, /* v_fsz */
288 0x01, 0x00, 0x33, 0x02, /* vsync */
289 0x2d, 0x00, 0x38, 0x04, /* vact */
290 0x33, 0x02, /* field_chg */
291 0x48, 0x02, /* vact_st2 */
292 0x01, 0x00, 0x01, 0x00, /* vsync top/bot */
293 0x01, 0x00, 0x33, 0x02, /* field top/bot */
294 },
295};
296
297static const struct hdmi_conf hdmi_confs[] = {
298 { 1280, 720, 60, false, hdmiphy_conf74_25, &hdmi_conf_720p60 },
299 { 1280, 720, 50, false, hdmiphy_conf74_25, &hdmi_conf_720p60 },
300 { 720, 480, 60, false, hdmiphy_conf27_027, &hdmi_conf_480p },
301 { 1920, 1080, 50, true, hdmiphy_conf74_25, &hdmi_conf_1080i50 },
302 { 1920, 1080, 50, false, hdmiphy_conf148_5, &hdmi_conf_1080p50 },
303 { 1920, 1080, 60, true, hdmiphy_conf74_25, &hdmi_conf_1080i60 },
304 { 1920, 1080, 60, false, hdmiphy_conf148_5, &hdmi_conf_1080p60 },
305};
306
307
308static inline u32 hdmi_reg_read(struct hdmi_context *hdata, u32 reg_id)
309{
310 return readl(hdata->regs + reg_id);
311}
312
313static inline void hdmi_reg_writeb(struct hdmi_context *hdata,
314 u32 reg_id, u8 value)
315{
316 writeb(value, hdata->regs + reg_id);
317}
318
319static inline void hdmi_reg_writemask(struct hdmi_context *hdata,
320 u32 reg_id, u32 value, u32 mask)
321{
322 u32 old = readl(hdata->regs + reg_id);
323 value = (value & mask) | (old & ~mask);
324 writel(value, hdata->regs + reg_id);
325}
326
327static void hdmi_regs_dump(struct hdmi_context *hdata, char *prefix)
328{
329#define DUMPREG(reg_id) \
330 DRM_DEBUG_KMS("%s:" #reg_id " = %08x\n", prefix, \
331 readl(hdata->regs + reg_id))
332 DRM_DEBUG_KMS("%s: ---- CONTROL REGISTERS ----\n", prefix);
333 DUMPREG(HDMI_INTC_FLAG);
334 DUMPREG(HDMI_INTC_CON);
335 DUMPREG(HDMI_HPD_STATUS);
336 DUMPREG(HDMI_PHY_RSTOUT);
337 DUMPREG(HDMI_PHY_VPLL);
338 DUMPREG(HDMI_PHY_CMU);
339 DUMPREG(HDMI_CORE_RSTOUT);
340
341 DRM_DEBUG_KMS("%s: ---- CORE REGISTERS ----\n", prefix);
342 DUMPREG(HDMI_CON_0);
343 DUMPREG(HDMI_CON_1);
344 DUMPREG(HDMI_CON_2);
345 DUMPREG(HDMI_SYS_STATUS);
346 DUMPREG(HDMI_PHY_STATUS);
347 DUMPREG(HDMI_STATUS_EN);
348 DUMPREG(HDMI_HPD);
349 DUMPREG(HDMI_MODE_SEL);
350 DUMPREG(HDMI_HPD_GEN);
351 DUMPREG(HDMI_DC_CONTROL);
352 DUMPREG(HDMI_VIDEO_PATTERN_GEN);
353
354 DRM_DEBUG_KMS("%s: ---- CORE SYNC REGISTERS ----\n", prefix);
355 DUMPREG(HDMI_H_BLANK_0);
356 DUMPREG(HDMI_H_BLANK_1);
357 DUMPREG(HDMI_V_BLANK_0);
358 DUMPREG(HDMI_V_BLANK_1);
359 DUMPREG(HDMI_V_BLANK_2);
360 DUMPREG(HDMI_H_V_LINE_0);
361 DUMPREG(HDMI_H_V_LINE_1);
362 DUMPREG(HDMI_H_V_LINE_2);
363 DUMPREG(HDMI_VSYNC_POL);
364 DUMPREG(HDMI_INT_PRO_MODE);
365 DUMPREG(HDMI_V_BLANK_F_0);
366 DUMPREG(HDMI_V_BLANK_F_1);
367 DUMPREG(HDMI_V_BLANK_F_2);
368 DUMPREG(HDMI_H_SYNC_GEN_0);
369 DUMPREG(HDMI_H_SYNC_GEN_1);
370 DUMPREG(HDMI_H_SYNC_GEN_2);
371 DUMPREG(HDMI_V_SYNC_GEN_1_0);
372 DUMPREG(HDMI_V_SYNC_GEN_1_1);
373 DUMPREG(HDMI_V_SYNC_GEN_1_2);
374 DUMPREG(HDMI_V_SYNC_GEN_2_0);
375 DUMPREG(HDMI_V_SYNC_GEN_2_1);
376 DUMPREG(HDMI_V_SYNC_GEN_2_2);
377 DUMPREG(HDMI_V_SYNC_GEN_3_0);
378 DUMPREG(HDMI_V_SYNC_GEN_3_1);
379 DUMPREG(HDMI_V_SYNC_GEN_3_2);
380
381 DRM_DEBUG_KMS("%s: ---- TG REGISTERS ----\n", prefix);
382 DUMPREG(HDMI_TG_CMD);
383 DUMPREG(HDMI_TG_H_FSZ_L);
384 DUMPREG(HDMI_TG_H_FSZ_H);
385 DUMPREG(HDMI_TG_HACT_ST_L);
386 DUMPREG(HDMI_TG_HACT_ST_H);
387 DUMPREG(HDMI_TG_HACT_SZ_L);
388 DUMPREG(HDMI_TG_HACT_SZ_H);
389 DUMPREG(HDMI_TG_V_FSZ_L);
390 DUMPREG(HDMI_TG_V_FSZ_H);
391 DUMPREG(HDMI_TG_VSYNC_L);
392 DUMPREG(HDMI_TG_VSYNC_H);
393 DUMPREG(HDMI_TG_VSYNC2_L);
394 DUMPREG(HDMI_TG_VSYNC2_H);
395 DUMPREG(HDMI_TG_VACT_ST_L);
396 DUMPREG(HDMI_TG_VACT_ST_H);
397 DUMPREG(HDMI_TG_VACT_SZ_L);
398 DUMPREG(HDMI_TG_VACT_SZ_H);
399 DUMPREG(HDMI_TG_FIELD_CHG_L);
400 DUMPREG(HDMI_TG_FIELD_CHG_H);
401 DUMPREG(HDMI_TG_VACT_ST2_L);
402 DUMPREG(HDMI_TG_VACT_ST2_H);
403 DUMPREG(HDMI_TG_VSYNC_TOP_HDMI_L);
404 DUMPREG(HDMI_TG_VSYNC_TOP_HDMI_H);
405 DUMPREG(HDMI_TG_VSYNC_BOT_HDMI_L);
406 DUMPREG(HDMI_TG_VSYNC_BOT_HDMI_H);
407 DUMPREG(HDMI_TG_FIELD_TOP_HDMI_L);
408 DUMPREG(HDMI_TG_FIELD_TOP_HDMI_H);
409 DUMPREG(HDMI_TG_FIELD_BOT_HDMI_L);
410 DUMPREG(HDMI_TG_FIELD_BOT_HDMI_H);
411#undef DUMPREG
412}
413
414static int hdmi_conf_index(struct drm_display_mode *mode)
415{
416 int i;
417
418 for (i = 0; i < ARRAY_SIZE(hdmi_confs); ++i)
419 if (hdmi_confs[i].width == mode->hdisplay &&
420 hdmi_confs[i].height == mode->vdisplay &&
421 hdmi_confs[i].vrefresh == mode->vrefresh &&
422 hdmi_confs[i].interlace ==
423 ((mode->flags & DRM_MODE_FLAG_INTERLACE) ?
424 true : false))
425 return i;
426
427 return -1;
428}
429
430static bool hdmi_is_connected(void *ctx)
431{
432 struct hdmi_context *hdata = (struct hdmi_context *)ctx;
433 u32 val = hdmi_reg_read(hdata, HDMI_HPD_STATUS);
434
435 if (val)
436 return true;
437
438 return false;
439}
440
441static int hdmi_get_edid(void *ctx, struct drm_connector *connector,
442 u8 *edid, int len)
443{
444 struct edid *raw_edid;
445 struct hdmi_context *hdata = (struct hdmi_context *)ctx;
446
447 DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
448
449 if (!hdata->ddc_port)
450 return -ENODEV;
451
452 raw_edid = drm_get_edid(connector, hdata->ddc_port->adapter);
453 if (raw_edid) {
454 memcpy(edid, raw_edid, min((1 + raw_edid->extensions)
455 * EDID_LENGTH, len));
456 DRM_DEBUG_KMS("width[%d] x height[%d]\n",
457 raw_edid->width_cm, raw_edid->height_cm);
458 } else {
459 return -ENODEV;
460 }
461
462 return 0;
463}
464
465static int hdmi_check_timing(void *ctx, void *timing)
466{
467 struct fb_videomode *check_timing = timing;
468 int i;
469
470 DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
471
472 DRM_DEBUG_KMS("[%d]x[%d] [%d]Hz [%x]\n", check_timing->xres,
473 check_timing->yres, check_timing->refresh,
474 check_timing->vmode);
475
476 for (i = 0; i < ARRAY_SIZE(hdmi_confs); ++i)
477 if (hdmi_confs[i].width == check_timing->xres &&
478 hdmi_confs[i].height == check_timing->yres &&
479 hdmi_confs[i].vrefresh == check_timing->refresh &&
480 hdmi_confs[i].interlace ==
481 ((check_timing->vmode & FB_VMODE_INTERLACED) ?
482 true : false))
483 return 0;
484
485 return -EINVAL;
486}
487
488static int hdmi_display_power_on(void *ctx, int mode)
489{
490 DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
491
492 switch (mode) {
493 case DRM_MODE_DPMS_ON:
494 DRM_DEBUG_KMS("hdmi [on]\n");
495 break;
496 case DRM_MODE_DPMS_STANDBY:
497 break;
498 case DRM_MODE_DPMS_SUSPEND:
499 break;
500 case DRM_MODE_DPMS_OFF:
501 DRM_DEBUG_KMS("hdmi [off]\n");
502 break;
503 default:
504 break;
505 }
506
507 return 0;
508}
509
510static struct exynos_hdmi_display_ops display_ops = {
511 .is_connected = hdmi_is_connected,
512 .get_edid = hdmi_get_edid,
513 .check_timing = hdmi_check_timing,
514 .power_on = hdmi_display_power_on,
515};
516
517static void hdmi_conf_reset(struct hdmi_context *hdata)
518{
519 /* disable hpd handle for drm */
520 hdata->hpd_handle = false;
521
522 /* resetting HDMI core */
523 hdmi_reg_writemask(hdata, HDMI_CORE_RSTOUT, 0, HDMI_CORE_SW_RSTOUT);
524 mdelay(10);
525 hdmi_reg_writemask(hdata, HDMI_CORE_RSTOUT, ~0, HDMI_CORE_SW_RSTOUT);
526 mdelay(10);
527
528 /* enable hpd handle for drm */
529 hdata->hpd_handle = true;
530}
531
532static void hdmi_conf_init(struct hdmi_context *hdata)
533{
534 /* disable hpd handle for drm */
535 hdata->hpd_handle = false;
536
537 /* enable HPD interrupts */
538 hdmi_reg_writemask(hdata, HDMI_INTC_CON, 0, HDMI_INTC_EN_GLOBAL |
539 HDMI_INTC_EN_HPD_PLUG | HDMI_INTC_EN_HPD_UNPLUG);
540 mdelay(10);
541 hdmi_reg_writemask(hdata, HDMI_INTC_CON, ~0, HDMI_INTC_EN_GLOBAL |
542 HDMI_INTC_EN_HPD_PLUG | HDMI_INTC_EN_HPD_UNPLUG);
543
544 /* choose HDMI mode */
545 hdmi_reg_writemask(hdata, HDMI_MODE_SEL,
546 HDMI_MODE_HDMI_EN, HDMI_MODE_MASK);
547 /* disable bluescreen */
548 hdmi_reg_writemask(hdata, HDMI_CON_0, 0, HDMI_BLUE_SCR_EN);
549 /* choose bluescreen (fecal) color */
550 hdmi_reg_writeb(hdata, HDMI_BLUE_SCREEN_0, 0x12);
551 hdmi_reg_writeb(hdata, HDMI_BLUE_SCREEN_1, 0x34);
552 hdmi_reg_writeb(hdata, HDMI_BLUE_SCREEN_2, 0x56);
553 /* enable AVI packet every vsync, fixes purple line problem */
554 hdmi_reg_writeb(hdata, HDMI_AVI_CON, 0x02);
555 /* force RGB, look to CEA-861-D, table 7 for more detail */
556 hdmi_reg_writeb(hdata, HDMI_AVI_BYTE(0), 0 << 5);
557 hdmi_reg_writemask(hdata, HDMI_CON_1, 0x10 << 5, 0x11 << 5);
558
559 hdmi_reg_writeb(hdata, HDMI_SPD_CON, 0x02);
560 hdmi_reg_writeb(hdata, HDMI_AUI_CON, 0x02);
561 hdmi_reg_writeb(hdata, HDMI_ACR_CON, 0x04);
562
563 /* enable hpd handle for drm */
564 hdata->hpd_handle = true;
565}
566
567static void hdmi_timing_apply(struct hdmi_context *hdata,
568 const struct hdmi_preset_conf *conf)
569{
570 const struct hdmi_core_regs *core = &conf->core;
571 const struct hdmi_tg_regs *tg = &conf->tg;
572 int tries;
573
574 /* setting core registers */
575 hdmi_reg_writeb(hdata, HDMI_H_BLANK_0, core->h_blank[0]);
576 hdmi_reg_writeb(hdata, HDMI_H_BLANK_1, core->h_blank[1]);
577 hdmi_reg_writeb(hdata, HDMI_V_BLANK_0, core->v_blank[0]);
578 hdmi_reg_writeb(hdata, HDMI_V_BLANK_1, core->v_blank[1]);
579 hdmi_reg_writeb(hdata, HDMI_V_BLANK_2, core->v_blank[2]);
580 hdmi_reg_writeb(hdata, HDMI_H_V_LINE_0, core->h_v_line[0]);
581 hdmi_reg_writeb(hdata, HDMI_H_V_LINE_1, core->h_v_line[1]);
582 hdmi_reg_writeb(hdata, HDMI_H_V_LINE_2, core->h_v_line[2]);
583 hdmi_reg_writeb(hdata, HDMI_VSYNC_POL, core->vsync_pol[0]);
584 hdmi_reg_writeb(hdata, HDMI_INT_PRO_MODE, core->int_pro_mode[0]);
585 hdmi_reg_writeb(hdata, HDMI_V_BLANK_F_0, core->v_blank_f[0]);
586 hdmi_reg_writeb(hdata, HDMI_V_BLANK_F_1, core->v_blank_f[1]);
587 hdmi_reg_writeb(hdata, HDMI_V_BLANK_F_2, core->v_blank_f[2]);
588 hdmi_reg_writeb(hdata, HDMI_H_SYNC_GEN_0, core->h_sync_gen[0]);
589 hdmi_reg_writeb(hdata, HDMI_H_SYNC_GEN_1, core->h_sync_gen[1]);
590 hdmi_reg_writeb(hdata, HDMI_H_SYNC_GEN_2, core->h_sync_gen[2]);
591 hdmi_reg_writeb(hdata, HDMI_V_SYNC_GEN_1_0, core->v_sync_gen1[0]);
592 hdmi_reg_writeb(hdata, HDMI_V_SYNC_GEN_1_1, core->v_sync_gen1[1]);
593 hdmi_reg_writeb(hdata, HDMI_V_SYNC_GEN_1_2, core->v_sync_gen1[2]);
594 hdmi_reg_writeb(hdata, HDMI_V_SYNC_GEN_2_0, core->v_sync_gen2[0]);
595 hdmi_reg_writeb(hdata, HDMI_V_SYNC_GEN_2_1, core->v_sync_gen2[1]);
596 hdmi_reg_writeb(hdata, HDMI_V_SYNC_GEN_2_2, core->v_sync_gen2[2]);
597 hdmi_reg_writeb(hdata, HDMI_V_SYNC_GEN_3_0, core->v_sync_gen3[0]);
598 hdmi_reg_writeb(hdata, HDMI_V_SYNC_GEN_3_1, core->v_sync_gen3[1]);
599 hdmi_reg_writeb(hdata, HDMI_V_SYNC_GEN_3_2, core->v_sync_gen3[2]);
600 /* Timing generator registers */
601 hdmi_reg_writeb(hdata, HDMI_TG_H_FSZ_L, tg->h_fsz_l);
602 hdmi_reg_writeb(hdata, HDMI_TG_H_FSZ_H, tg->h_fsz_h);
603 hdmi_reg_writeb(hdata, HDMI_TG_HACT_ST_L, tg->hact_st_l);
604 hdmi_reg_writeb(hdata, HDMI_TG_HACT_ST_H, tg->hact_st_h);
605 hdmi_reg_writeb(hdata, HDMI_TG_HACT_SZ_L, tg->hact_sz_l);
606 hdmi_reg_writeb(hdata, HDMI_TG_HACT_SZ_H, tg->hact_sz_h);
607 hdmi_reg_writeb(hdata, HDMI_TG_V_FSZ_L, tg->v_fsz_l);
608 hdmi_reg_writeb(hdata, HDMI_TG_V_FSZ_H, tg->v_fsz_h);
609 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_L, tg->vsync_l);
610 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_H, tg->vsync_h);
611 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC2_L, tg->vsync2_l);
612 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC2_H, tg->vsync2_h);
613 hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST_L, tg->vact_st_l);
614 hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST_H, tg->vact_st_h);
615 hdmi_reg_writeb(hdata, HDMI_TG_VACT_SZ_L, tg->vact_sz_l);
616 hdmi_reg_writeb(hdata, HDMI_TG_VACT_SZ_H, tg->vact_sz_h);
617 hdmi_reg_writeb(hdata, HDMI_TG_FIELD_CHG_L, tg->field_chg_l);
618 hdmi_reg_writeb(hdata, HDMI_TG_FIELD_CHG_H, tg->field_chg_h);
619 hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST2_L, tg->vact_st2_l);
620 hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST2_H, tg->vact_st2_h);
621 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_TOP_HDMI_L, tg->vsync_top_hdmi_l);
622 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_TOP_HDMI_H, tg->vsync_top_hdmi_h);
623 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_BOT_HDMI_L, tg->vsync_bot_hdmi_l);
624 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_BOT_HDMI_H, tg->vsync_bot_hdmi_h);
625 hdmi_reg_writeb(hdata, HDMI_TG_FIELD_TOP_HDMI_L, tg->field_top_hdmi_l);
626 hdmi_reg_writeb(hdata, HDMI_TG_FIELD_TOP_HDMI_H, tg->field_top_hdmi_h);
627 hdmi_reg_writeb(hdata, HDMI_TG_FIELD_BOT_HDMI_L, tg->field_bot_hdmi_l);
628 hdmi_reg_writeb(hdata, HDMI_TG_FIELD_BOT_HDMI_H, tg->field_bot_hdmi_h);
629
630 /* waiting for HDMIPHY's PLL to get to steady state */
631 for (tries = 100; tries; --tries) {
632 u32 val = hdmi_reg_read(hdata, HDMI_PHY_STATUS);
633 if (val & HDMI_PHY_STATUS_READY)
634 break;
635 mdelay(1);
636 }
637 /* steady state not achieved */
638 if (tries == 0) {
639 DRM_ERROR("hdmiphy's pll could not reach steady state.\n");
640 hdmi_regs_dump(hdata, "timing apply");
641 }
642
643 clk_disable(hdata->res.sclk_hdmi);
644 clk_set_parent(hdata->res.sclk_hdmi, hdata->res.sclk_hdmiphy);
645 clk_enable(hdata->res.sclk_hdmi);
646
647 /* enable HDMI and timing generator */
648 hdmi_reg_writemask(hdata, HDMI_CON_0, ~0, HDMI_EN);
649 if (core->int_pro_mode[0])
650 hdmi_reg_writemask(hdata, HDMI_TG_CMD, ~0, HDMI_TG_EN |
651 HDMI_FIELD_EN);
652 else
653 hdmi_reg_writemask(hdata, HDMI_TG_CMD, ~0, HDMI_TG_EN);
654}
655
656static void hdmiphy_conf_reset(struct hdmi_context *hdata)
657{
658 u8 buffer[2];
659
660 clk_disable(hdata->res.sclk_hdmi);
661 clk_set_parent(hdata->res.sclk_hdmi, hdata->res.sclk_pixel);
662 clk_enable(hdata->res.sclk_hdmi);
663
664 /* operation mode */
665 buffer[0] = 0x1f;
666 buffer[1] = 0x00;
667
668 if (hdata->hdmiphy_port)
669 i2c_master_send(hdata->hdmiphy_port, buffer, 2);
670
671 /* reset hdmiphy */
672 hdmi_reg_writemask(hdata, HDMI_PHY_RSTOUT, ~0, HDMI_PHY_SW_RSTOUT);
673 mdelay(10);
674 hdmi_reg_writemask(hdata, HDMI_PHY_RSTOUT, 0, HDMI_PHY_SW_RSTOUT);
675 mdelay(10);
676}
677
678static void hdmiphy_conf_apply(struct hdmi_context *hdata)
679{
680 u8 buffer[32];
681 u8 operation[2];
682 u8 read_buffer[32] = {0, };
683 int ret;
684 int i;
685
686 if (!hdata->hdmiphy_port) {
687 DRM_ERROR("hdmiphy is not attached\n");
688 return;
689 }
690
691 /* pixel clock */
692 memcpy(buffer, hdmi_confs[hdata->cur_conf].hdmiphy_data, 32);
693 ret = i2c_master_send(hdata->hdmiphy_port, buffer, 32);
694 if (ret != 32) {
695 DRM_ERROR("failed to configure HDMIPHY via I2C\n");
696 return;
697 }
698
699 mdelay(10);
700
701 /* operation mode */
702 operation[0] = 0x1f;
703 operation[1] = 0x80;
704
705 ret = i2c_master_send(hdata->hdmiphy_port, operation, 2);
706 if (ret != 2) {
707 DRM_ERROR("failed to enable hdmiphy\n");
708 return;
709 }
710
711 ret = i2c_master_recv(hdata->hdmiphy_port, read_buffer, 32);
712 if (ret < 0) {
713 DRM_ERROR("failed to read hdmiphy config\n");
714 return;
715 }
716
717 for (i = 0; i < ret; i++)
718 DRM_DEBUG_KMS("hdmiphy[0x%02x] write[0x%02x] - "
719 "recv [0x%02x]\n", i, buffer[i], read_buffer[i]);
720}
721
722static void hdmi_conf_apply(struct hdmi_context *hdata)
723{
724 const struct hdmi_preset_conf *conf =
725 hdmi_confs[hdata->cur_conf].conf;
726
727 DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
728
729 hdmiphy_conf_reset(hdata);
730 hdmiphy_conf_apply(hdata);
731
732 hdmi_conf_reset(hdata);
733 hdmi_conf_init(hdata);
734
735 /* setting core registers */
736 hdmi_timing_apply(hdata, conf);
737
738 hdmi_regs_dump(hdata, "start");
739}
740
741static void hdmi_mode_set(void *ctx, void *mode)
742{
743 struct hdmi_context *hdata = (struct hdmi_context *)ctx;
744 int conf_idx;
745
746 DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
747
748 conf_idx = hdmi_conf_index(mode);
749 if (conf_idx >= 0 && conf_idx < ARRAY_SIZE(hdmi_confs))
750 hdata->cur_conf = conf_idx;
751 else
752 DRM_DEBUG_KMS("not supported mode\n");
753}
754
755static void hdmi_commit(void *ctx)
756{
757 struct hdmi_context *hdata = (struct hdmi_context *)ctx;
758
759 DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
760
761 hdmi_conf_apply(hdata);
762
763 hdata->enabled = true;
764}
765
766static void hdmi_disable(void *ctx)
767{
768 struct hdmi_context *hdata = (struct hdmi_context *)ctx;
769
770 DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
771
772 if (hdata->enabled) {
773 hdmiphy_conf_reset(hdata);
774 hdmi_conf_reset(hdata);
775 }
776}
777
778static struct exynos_hdmi_manager_ops manager_ops = {
779 .mode_set = hdmi_mode_set,
780 .commit = hdmi_commit,
781 .disable = hdmi_disable,
782};
783
784/*
785 * Handle hotplug events outside the interrupt handler proper.
786 */
787static void hdmi_hotplug_func(struct work_struct *work)
788{
789 struct hdmi_context *hdata =
790 container_of(work, struct hdmi_context, hotplug_work);
791 struct exynos_drm_hdmi_context *ctx =
792 (struct exynos_drm_hdmi_context *)hdata->parent_ctx;
793
794 drm_helper_hpd_irq_event(ctx->drm_dev);
795}
796
797static irqreturn_t hdmi_irq_handler(int irq, void *arg)
798{
799 struct exynos_drm_hdmi_context *ctx = arg;
800 struct hdmi_context *hdata = (struct hdmi_context *)ctx->ctx;
801 u32 intc_flag;
802
803 intc_flag = hdmi_reg_read(hdata, HDMI_INTC_FLAG);
804 /* clearing flags for HPD plug/unplug */
805 if (intc_flag & HDMI_INTC_FLAG_HPD_UNPLUG) {
806 DRM_DEBUG_KMS("unplugged, handling:%d\n", hdata->hpd_handle);
807 hdmi_reg_writemask(hdata, HDMI_INTC_FLAG, ~0,
808 HDMI_INTC_FLAG_HPD_UNPLUG);
809 }
810 if (intc_flag & HDMI_INTC_FLAG_HPD_PLUG) {
811 DRM_DEBUG_KMS("plugged, handling:%d\n", hdata->hpd_handle);
812 hdmi_reg_writemask(hdata, HDMI_INTC_FLAG, ~0,
813 HDMI_INTC_FLAG_HPD_PLUG);
814 }
815
816 if (ctx->drm_dev && hdata->hpd_handle)
817 queue_work(hdata->wq, &hdata->hotplug_work);
818
819 return IRQ_HANDLED;
820}
821
822static int __devinit hdmi_resources_init(struct hdmi_context *hdata)
823{
824 struct device *dev = hdata->dev;
825 struct hdmi_resources *res = &hdata->res;
826 static char *supply[] = {
827 "hdmi-en",
828 "vdd",
829 "vdd_osc",
830 "vdd_pll",
831 };
832 int i, ret;
833
834 DRM_DEBUG_KMS("HDMI resource init\n");
835
836 memset(res, 0, sizeof *res);
837
838 /* get clocks, power */
839 res->hdmi = clk_get(dev, "hdmi");
840 if (IS_ERR_OR_NULL(res->hdmi)) {
841 DRM_ERROR("failed to get clock 'hdmi'\n");
842 goto fail;
843 }
844 res->sclk_hdmi = clk_get(dev, "sclk_hdmi");
845 if (IS_ERR_OR_NULL(res->sclk_hdmi)) {
846 DRM_ERROR("failed to get clock 'sclk_hdmi'\n");
847 goto fail;
848 }
849 res->sclk_pixel = clk_get(dev, "sclk_pixel");
850 if (IS_ERR_OR_NULL(res->sclk_pixel)) {
851 DRM_ERROR("failed to get clock 'sclk_pixel'\n");
852 goto fail;
853 }
854 res->sclk_hdmiphy = clk_get(dev, "sclk_hdmiphy");
855 if (IS_ERR_OR_NULL(res->sclk_hdmiphy)) {
856 DRM_ERROR("failed to get clock 'sclk_hdmiphy'\n");
857 goto fail;
858 }
859 res->hdmiphy = clk_get(dev, "hdmiphy");
860 if (IS_ERR_OR_NULL(res->hdmiphy)) {
861 DRM_ERROR("failed to get clock 'hdmiphy'\n");
862 goto fail;
863 }
864
865 clk_set_parent(res->sclk_hdmi, res->sclk_pixel);
866
867 res->regul_bulk = kzalloc(ARRAY_SIZE(supply) *
868 sizeof res->regul_bulk[0], GFP_KERNEL);
869 if (!res->regul_bulk) {
870 DRM_ERROR("failed to get memory for regulators\n");
871 goto fail;
872 }
873 for (i = 0; i < ARRAY_SIZE(supply); ++i) {
874 res->regul_bulk[i].supply = supply[i];
875 res->regul_bulk[i].consumer = NULL;
876 }
877 ret = regulator_bulk_get(dev, ARRAY_SIZE(supply), res->regul_bulk);
878 if (ret) {
879 DRM_ERROR("failed to get regulators\n");
880 goto fail;
881 }
882 res->regul_count = ARRAY_SIZE(supply);
883
884 return 0;
885fail:
886 DRM_ERROR("HDMI resource init - failed\n");
887 return -ENODEV;
888}
889
890static int hdmi_resources_cleanup(struct hdmi_context *hdata)
891{
892 struct hdmi_resources *res = &hdata->res;
893
894 regulator_bulk_free(res->regul_count, res->regul_bulk);
895 /* kfree is NULL-safe */
896 kfree(res->regul_bulk);
897 if (!IS_ERR_OR_NULL(res->hdmiphy))
898 clk_put(res->hdmiphy);
899 if (!IS_ERR_OR_NULL(res->sclk_hdmiphy))
900 clk_put(res->sclk_hdmiphy);
901 if (!IS_ERR_OR_NULL(res->sclk_pixel))
902 clk_put(res->sclk_pixel);
903 if (!IS_ERR_OR_NULL(res->sclk_hdmi))
904 clk_put(res->sclk_hdmi);
905 if (!IS_ERR_OR_NULL(res->hdmi))
906 clk_put(res->hdmi);
907 memset(res, 0, sizeof *res);
908
909 return 0;
910}
911
912static void hdmi_resource_poweron(struct hdmi_context *hdata)
913{
914 struct hdmi_resources *res = &hdata->res;
915
916 DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
917
918 /* turn HDMI power on */
919 regulator_bulk_enable(res->regul_count, res->regul_bulk);
920 /* power-on hdmi physical interface */
921 clk_enable(res->hdmiphy);
922 /* turn clocks on */
923 clk_enable(res->hdmi);
924 clk_enable(res->sclk_hdmi);
925
926 hdmiphy_conf_reset(hdata);
927 hdmi_conf_reset(hdata);
928 hdmi_conf_init(hdata);
929
930}
931
932static void hdmi_resource_poweroff(struct hdmi_context *hdata)
933{
934 struct hdmi_resources *res = &hdata->res;
935
936 DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
937
938 /* turn clocks off */
939 clk_disable(res->sclk_hdmi);
940 clk_disable(res->hdmi);
941 /* power-off hdmiphy */
942 clk_disable(res->hdmiphy);
943 /* turn HDMI power off */
944 regulator_bulk_disable(res->regul_count, res->regul_bulk);
945}
946
947static int hdmi_runtime_suspend(struct device *dev)
948{
949 struct exynos_drm_hdmi_context *ctx = get_hdmi_context(dev);
950
951 DRM_DEBUG_KMS("%s\n", __func__);
952
953 hdmi_resource_poweroff((struct hdmi_context *)ctx->ctx);
954
955 return 0;
956}
957
958static int hdmi_runtime_resume(struct device *dev)
959{
960 struct exynos_drm_hdmi_context *ctx = get_hdmi_context(dev);
961
962 DRM_DEBUG_KMS("%s\n", __func__);
963
964 hdmi_resource_poweron((struct hdmi_context *)ctx->ctx);
965
966 return 0;
967}
968
969static const struct dev_pm_ops hdmi_pm_ops = {
970 .runtime_suspend = hdmi_runtime_suspend,
971 .runtime_resume = hdmi_runtime_resume,
972};
973
974static struct i2c_client *hdmi_ddc, *hdmi_hdmiphy;
975
976void hdmi_attach_ddc_client(struct i2c_client *ddc)
977{
978 if (ddc)
979 hdmi_ddc = ddc;
980}
981EXPORT_SYMBOL(hdmi_attach_ddc_client);
982
983void hdmi_attach_hdmiphy_client(struct i2c_client *hdmiphy)
984{
985 if (hdmiphy)
986 hdmi_hdmiphy = hdmiphy;
987}
988EXPORT_SYMBOL(hdmi_attach_hdmiphy_client);
989
990static int __devinit hdmi_probe(struct platform_device *pdev)
991{
992 struct device *dev = &pdev->dev;
993 struct exynos_drm_hdmi_context *drm_hdmi_ctx;
994 struct hdmi_context *hdata;
995 struct exynos_drm_hdmi_pdata *pdata;
996 struct resource *res;
997 int ret;
998
999 DRM_DEBUG_KMS("[%d]\n", __LINE__);
1000
1001 pdata = pdev->dev.platform_data;
1002 if (!pdata) {
1003 DRM_ERROR("no platform data specified\n");
1004 return -EINVAL;
1005 }
1006
1007 drm_hdmi_ctx = kzalloc(sizeof(*drm_hdmi_ctx), GFP_KERNEL);
1008 if (!drm_hdmi_ctx) {
1009 DRM_ERROR("failed to allocate common hdmi context.\n");
1010 return -ENOMEM;
1011 }
1012
1013 hdata = kzalloc(sizeof(struct hdmi_context), GFP_KERNEL);
1014 if (!hdata) {
1015 DRM_ERROR("out of memory\n");
1016 kfree(drm_hdmi_ctx);
1017 return -ENOMEM;
1018 }
1019
1020 drm_hdmi_ctx->ctx = (void *)hdata;
1021 hdata->parent_ctx = (void *)drm_hdmi_ctx;
1022
1023 platform_set_drvdata(pdev, drm_hdmi_ctx);
1024
1025 hdata->default_win = pdata->default_win;
1026 hdata->default_timing = &pdata->timing;
1027 hdata->default_bpp = pdata->bpp;
1028 hdata->dev = dev;
1029
1030 ret = hdmi_resources_init(hdata);
1031 if (ret) {
1032 ret = -EINVAL;
1033 goto err_data;
1034 }
1035
1036 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
1037 if (!res) {
1038 DRM_ERROR("failed to find registers\n");
1039 ret = -ENOENT;
1040 goto err_resource;
1041 }
1042
1043 hdata->regs_res = request_mem_region(res->start, resource_size(res),
1044 dev_name(dev));
1045 if (!hdata->regs_res) {
1046 DRM_ERROR("failed to claim register region\n");
1047 ret = -ENOENT;
1048 goto err_resource;
1049 }
1050
1051 hdata->regs = ioremap(res->start, resource_size(res));
1052 if (!hdata->regs) {
1053 DRM_ERROR("failed to map registers\n");
1054 ret = -ENXIO;
1055 goto err_req_region;
1056 }
1057
1058 /* DDC i2c driver */
1059 if (i2c_add_driver(&ddc_driver)) {
1060 DRM_ERROR("failed to register ddc i2c driver\n");
1061 ret = -ENOENT;
1062 goto err_iomap;
1063 }
1064
1065 hdata->ddc_port = hdmi_ddc;
1066
1067 /* hdmiphy i2c driver */
1068 if (i2c_add_driver(&hdmiphy_driver)) {
1069 DRM_ERROR("failed to register hdmiphy i2c driver\n");
1070 ret = -ENOENT;
1071 goto err_ddc;
1072 }
1073
1074 hdata->hdmiphy_port = hdmi_hdmiphy;
1075
1076 res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
1077 if (res == NULL) {
1078 DRM_ERROR("get interrupt resource failed.\n");
1079 ret = -ENXIO;
1080 goto err_hdmiphy;
1081 }
1082
1083 /* create workqueue and hotplug work */
1084 hdata->wq = alloc_workqueue("exynos-drm-hdmi",
1085 WQ_UNBOUND | WQ_NON_REENTRANT, 1);
1086 if (hdata->wq == NULL) {
1087 DRM_ERROR("Failed to create workqueue.\n");
1088 ret = -ENOMEM;
1089 goto err_hdmiphy;
1090 }
1091 INIT_WORK(&hdata->hotplug_work, hdmi_hotplug_func);
1092
1093 /* register hpd interrupt */
1094 ret = request_irq(res->start, hdmi_irq_handler, 0, "drm_hdmi",
1095 drm_hdmi_ctx);
1096 if (ret) {
1097 DRM_ERROR("request interrupt failed.\n");
1098 goto err_workqueue;
1099 }
1100 hdata->irq = res->start;
1101
1102 /* register specific callbacks to common hdmi. */
1103 exynos_drm_display_ops_register(&display_ops);
1104 exynos_drm_manager_ops_register(&manager_ops);
1105
1106 hdmi_resource_poweron(hdata);
1107
1108 return 0;
1109
1110err_workqueue:
1111 destroy_workqueue(hdata->wq);
1112err_hdmiphy:
1113 i2c_del_driver(&hdmiphy_driver);
1114err_ddc:
1115 i2c_del_driver(&ddc_driver);
1116err_iomap:
1117 iounmap(hdata->regs);
1118err_req_region:
1119 release_resource(hdata->regs_res);
1120 kfree(hdata->regs_res);
1121err_resource:
1122 hdmi_resources_cleanup(hdata);
1123err_data:
1124 kfree(hdata);
1125 kfree(drm_hdmi_ctx);
1126 return ret;
1127}
1128
1129static int __devexit hdmi_remove(struct platform_device *pdev)
1130{
1131 struct exynos_drm_hdmi_context *ctx = platform_get_drvdata(pdev);
1132 struct hdmi_context *hdata = (struct hdmi_context *)ctx->ctx;
1133
1134 DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
1135
1136 hdmi_resource_poweroff(hdata);
1137
1138 disable_irq(hdata->irq);
1139 free_irq(hdata->irq, hdata);
1140
1141 cancel_work_sync(&hdata->hotplug_work);
1142 destroy_workqueue(hdata->wq);
1143
1144 hdmi_resources_cleanup(hdata);
1145
1146 iounmap(hdata->regs);
1147
1148 release_resource(hdata->regs_res);
1149 kfree(hdata->regs_res);
1150
1151 /* hdmiphy i2c driver */
1152 i2c_del_driver(&hdmiphy_driver);
1153 /* DDC i2c driver */
1154 i2c_del_driver(&ddc_driver);
1155
1156 kfree(hdata);
1157
1158 return 0;
1159}
1160
1161struct platform_driver hdmi_driver = {
1162 .probe = hdmi_probe,
1163 .remove = __devexit_p(hdmi_remove),
1164 .driver = {
1165 .name = "exynos4-hdmi",
1166 .owner = THIS_MODULE,
1167 .pm = &hdmi_pm_ops,
1168 },
1169};
1170EXPORT_SYMBOL(hdmi_driver);
1171
1172MODULE_AUTHOR("Seung-Woo Kim, <sw0312.kim@samsung.com>");
1173MODULE_AUTHOR("Inki Dae <inki.dae@samsung.com>");
1174MODULE_AUTHOR("Joonyoung Shim <jy0922.shim@samsung.com>");
1175MODULE_DESCRIPTION("Samsung DRM HDMI core Driver");
1176MODULE_LICENSE("GPL");
diff --git a/drivers/gpu/drm/exynos/exynos_hdmi.h b/drivers/gpu/drm/exynos/exynos_hdmi.h
new file mode 100644
index 000000000000..31d6cf84c1aa
--- /dev/null
+++ b/drivers/gpu/drm/exynos/exynos_hdmi.h
@@ -0,0 +1,87 @@
1/*
2 *
3 * Copyright (c) 2011 Samsung Electronics Co., Ltd.
4 * Authors:
5 * Inki Dae <inki.dae@samsung.com>
6 * Seung-Woo Kim <sw0312.kim@samsung.com>
7 *
8 * Permission is hereby granted, free of charge, to any person obtaining a
9 * copy of this software and associated documentation files (the "Software"),
10 * to deal in the Software without restriction, including without limitation
11 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
12 * and/or sell copies of the Software, and to permit persons to whom the
13 * Software is furnished to do so, subject to the following conditions:
14 *
15 * The above copyright notice and this permission notice (including the next
16 * paragraph) shall be included in all copies or substantial portions of the
17 * Software.
18 *
19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
22 * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
23 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
24 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
25 * OTHER DEALINGS IN THE SOFTWARE.
26 */
27
28#ifndef _EXYNOS_HDMI_H_
29#define _EXYNOS_HDMI_H_
30
31struct hdmi_conf {
32 int width;
33 int height;
34 int vrefresh;
35 bool interlace;
36 const u8 *hdmiphy_data;
37 const struct hdmi_preset_conf *conf;
38};
39
40struct hdmi_resources {
41 struct clk *hdmi;
42 struct clk *sclk_hdmi;
43 struct clk *sclk_pixel;
44 struct clk *sclk_hdmiphy;
45 struct clk *hdmiphy;
46 struct regulator_bulk_data *regul_bulk;
47 int regul_count;
48};
49
50struct hdmi_context {
51 struct device *dev;
52 struct drm_device *drm_dev;
53 struct fb_videomode *default_timing;
54 unsigned int default_win;
55 unsigned int default_bpp;
56 bool hpd_handle;
57 bool enabled;
58
59 struct resource *regs_res;
60 /** base address of HDMI registers */
61 void __iomem *regs;
62 /** HDMI hotplug interrupt */
63 unsigned int irq;
64 /** workqueue for delayed work */
65 struct workqueue_struct *wq;
66 /** hotplug handling work */
67 struct work_struct hotplug_work;
68
69 struct i2c_client *ddc_port;
70 struct i2c_client *hdmiphy_port;
71
72 /** current hdmiphy conf index */
73 int cur_conf;
74 /** other resources */
75 struct hdmi_resources res;
76
77 void *parent_ctx;
78};
79
80
81void hdmi_attach_ddc_client(struct i2c_client *ddc);
82void hdmi_attach_hdmiphy_client(struct i2c_client *hdmiphy);
83
84extern struct i2c_driver hdmiphy_driver;
85extern struct i2c_driver ddc_driver;
86
87#endif
diff --git a/drivers/gpu/drm/exynos/exynos_hdmiphy.c b/drivers/gpu/drm/exynos/exynos_hdmiphy.c
new file mode 100644
index 000000000000..9fe2995ab9f9
--- /dev/null
+++ b/drivers/gpu/drm/exynos/exynos_hdmiphy.c
@@ -0,0 +1,58 @@
1/*
2 * Copyright (C) 2011 Samsung Electronics Co.Ltd
3 * Authors:
4 * Seung-Woo Kim <sw0312.kim@samsung.com>
5 * Inki Dae <inki.dae@samsung.com>
6 *
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the
9 * Free Software Foundation; either version 2 of the License, or (at your
10 * option) any later version.
11 *
12 */
13
14#include "drmP.h"
15
16#include <linux/kernel.h>
17#include <linux/i2c.h>
18#include <linux/module.h>
19
20#include "exynos_drm_drv.h"
21#include "exynos_hdmi.h"
22
23
24static int hdmiphy_probe(struct i2c_client *client,
25 const struct i2c_device_id *id)
26{
27 hdmi_attach_hdmiphy_client(client);
28
29 dev_info(&client->adapter->dev, "attached s5p_hdmiphy "
30 "into i2c adapter successfully\n");
31
32 return 0;
33}
34
35static int hdmiphy_remove(struct i2c_client *client)
36{
37 dev_info(&client->adapter->dev, "detached s5p_hdmiphy "
38 "from i2c adapter successfully\n");
39
40 return 0;
41}
42
43static const struct i2c_device_id hdmiphy_id[] = {
44 { "s5p_hdmiphy", 0 },
45 { },
46};
47
48struct i2c_driver hdmiphy_driver = {
49 .driver = {
50 .name = "s5p-hdmiphy",
51 .owner = THIS_MODULE,
52 },
53 .id_table = hdmiphy_id,
54 .probe = hdmiphy_probe,
55 .remove = __devexit_p(hdmiphy_remove),
56 .command = NULL,
57};
58EXPORT_SYMBOL(hdmiphy_driver);
diff --git a/drivers/gpu/drm/exynos/exynos_mixer.c b/drivers/gpu/drm/exynos/exynos_mixer.c
new file mode 100644
index 000000000000..ac24cff39775
--- /dev/null
+++ b/drivers/gpu/drm/exynos/exynos_mixer.c
@@ -0,0 +1,1070 @@
1/*
2 * Copyright (C) 2011 Samsung Electronics Co.Ltd
3 * Authors:
4 * Seung-Woo Kim <sw0312.kim@samsung.com>
5 * Inki Dae <inki.dae@samsung.com>
6 * Joonyoung Shim <jy0922.shim@samsung.com>
7 *
8 * Based on drivers/media/video/s5p-tv/mixer_reg.c
9 *
10 * This program is free software; you can redistribute it and/or modify it
11 * under the terms of the GNU General Public License as published by the
12 * Free Software Foundation; either version 2 of the License, or (at your
13 * option) any later version.
14 *
15 */
16
17#include "drmP.h"
18
19#include "regs-mixer.h"
20#include "regs-vp.h"
21
22#include <linux/kernel.h>
23#include <linux/spinlock.h>
24#include <linux/wait.h>
25#include <linux/i2c.h>
26#include <linux/module.h>
27#include <linux/platform_device.h>
28#include <linux/interrupt.h>
29#include <linux/irq.h>
30#include <linux/delay.h>
31#include <linux/pm_runtime.h>
32#include <linux/clk.h>
33#include <linux/regulator/consumer.h>
34
35#include <drm/exynos_drm.h>
36
37#include "exynos_drm_drv.h"
38#include "exynos_drm_hdmi.h"
39#include "exynos_hdmi.h"
40#include "exynos_mixer.h"
41
42#define get_mixer_context(dev) platform_get_drvdata(to_platform_device(dev))
43
44static const u8 filter_y_horiz_tap8[] = {
45 0, -1, -1, -1, -1, -1, -1, -1,
46 -1, -1, -1, -1, -1, 0, 0, 0,
47 0, 2, 4, 5, 6, 6, 6, 6,
48 6, 5, 5, 4, 3, 2, 1, 1,
49 0, -6, -12, -16, -18, -20, -21, -20,
50 -20, -18, -16, -13, -10, -8, -5, -2,
51 127, 126, 125, 121, 114, 107, 99, 89,
52 79, 68, 57, 46, 35, 25, 16, 8,
53};
54
55static const u8 filter_y_vert_tap4[] = {
56 0, -3, -6, -8, -8, -8, -8, -7,
57 -6, -5, -4, -3, -2, -1, -1, 0,
58 127, 126, 124, 118, 111, 102, 92, 81,
59 70, 59, 48, 37, 27, 19, 11, 5,
60 0, 5, 11, 19, 27, 37, 48, 59,
61 70, 81, 92, 102, 111, 118, 124, 126,
62 0, 0, -1, -1, -2, -3, -4, -5,
63 -6, -7, -8, -8, -8, -8, -6, -3,
64};
65
66static const u8 filter_cr_horiz_tap4[] = {
67 0, -3, -6, -8, -8, -8, -8, -7,
68 -6, -5, -4, -3, -2, -1, -1, 0,
69 127, 126, 124, 118, 111, 102, 92, 81,
70 70, 59, 48, 37, 27, 19, 11, 5,
71};
72
73static inline u32 vp_reg_read(struct mixer_resources *res, u32 reg_id)
74{
75 return readl(res->vp_regs + reg_id);
76}
77
78static inline void vp_reg_write(struct mixer_resources *res, u32 reg_id,
79 u32 val)
80{
81 writel(val, res->vp_regs + reg_id);
82}
83
84static inline void vp_reg_writemask(struct mixer_resources *res, u32 reg_id,
85 u32 val, u32 mask)
86{
87 u32 old = vp_reg_read(res, reg_id);
88
89 val = (val & mask) | (old & ~mask);
90 writel(val, res->vp_regs + reg_id);
91}
92
93static inline u32 mixer_reg_read(struct mixer_resources *res, u32 reg_id)
94{
95 return readl(res->mixer_regs + reg_id);
96}
97
98static inline void mixer_reg_write(struct mixer_resources *res, u32 reg_id,
99 u32 val)
100{
101 writel(val, res->mixer_regs + reg_id);
102}
103
104static inline void mixer_reg_writemask(struct mixer_resources *res,
105 u32 reg_id, u32 val, u32 mask)
106{
107 u32 old = mixer_reg_read(res, reg_id);
108
109 val = (val & mask) | (old & ~mask);
110 writel(val, res->mixer_regs + reg_id);
111}
112
113static void mixer_regs_dump(struct mixer_context *ctx)
114{
115#define DUMPREG(reg_id) \
116do { \
117 DRM_DEBUG_KMS(#reg_id " = %08x\n", \
118 (u32)readl(ctx->mixer_res.mixer_regs + reg_id)); \
119} while (0)
120
121 DUMPREG(MXR_STATUS);
122 DUMPREG(MXR_CFG);
123 DUMPREG(MXR_INT_EN);
124 DUMPREG(MXR_INT_STATUS);
125
126 DUMPREG(MXR_LAYER_CFG);
127 DUMPREG(MXR_VIDEO_CFG);
128
129 DUMPREG(MXR_GRAPHIC0_CFG);
130 DUMPREG(MXR_GRAPHIC0_BASE);
131 DUMPREG(MXR_GRAPHIC0_SPAN);
132 DUMPREG(MXR_GRAPHIC0_WH);
133 DUMPREG(MXR_GRAPHIC0_SXY);
134 DUMPREG(MXR_GRAPHIC0_DXY);
135
136 DUMPREG(MXR_GRAPHIC1_CFG);
137 DUMPREG(MXR_GRAPHIC1_BASE);
138 DUMPREG(MXR_GRAPHIC1_SPAN);
139 DUMPREG(MXR_GRAPHIC1_WH);
140 DUMPREG(MXR_GRAPHIC1_SXY);
141 DUMPREG(MXR_GRAPHIC1_DXY);
142#undef DUMPREG
143}
144
145static void vp_regs_dump(struct mixer_context *ctx)
146{
147#define DUMPREG(reg_id) \
148do { \
149 DRM_DEBUG_KMS(#reg_id " = %08x\n", \
150 (u32) readl(ctx->mixer_res.vp_regs + reg_id)); \
151} while (0)
152
153 DUMPREG(VP_ENABLE);
154 DUMPREG(VP_SRESET);
155 DUMPREG(VP_SHADOW_UPDATE);
156 DUMPREG(VP_FIELD_ID);
157 DUMPREG(VP_MODE);
158 DUMPREG(VP_IMG_SIZE_Y);
159 DUMPREG(VP_IMG_SIZE_C);
160 DUMPREG(VP_PER_RATE_CTRL);
161 DUMPREG(VP_TOP_Y_PTR);
162 DUMPREG(VP_BOT_Y_PTR);
163 DUMPREG(VP_TOP_C_PTR);
164 DUMPREG(VP_BOT_C_PTR);
165 DUMPREG(VP_ENDIAN_MODE);
166 DUMPREG(VP_SRC_H_POSITION);
167 DUMPREG(VP_SRC_V_POSITION);
168 DUMPREG(VP_SRC_WIDTH);
169 DUMPREG(VP_SRC_HEIGHT);
170 DUMPREG(VP_DST_H_POSITION);
171 DUMPREG(VP_DST_V_POSITION);
172 DUMPREG(VP_DST_WIDTH);
173 DUMPREG(VP_DST_HEIGHT);
174 DUMPREG(VP_H_RATIO);
175 DUMPREG(VP_V_RATIO);
176
177#undef DUMPREG
178}
179
180static inline void vp_filter_set(struct mixer_resources *res,
181 int reg_id, const u8 *data, unsigned int size)
182{
183 /* assure 4-byte align */
184 BUG_ON(size & 3);
185 for (; size; size -= 4, reg_id += 4, data += 4) {
186 u32 val = (data[0] << 24) | (data[1] << 16) |
187 (data[2] << 8) | data[3];
188 vp_reg_write(res, reg_id, val);
189 }
190}
191
192static void vp_default_filter(struct mixer_resources *res)
193{
194 vp_filter_set(res, VP_POLY8_Y0_LL,
195 filter_y_horiz_tap8, sizeof filter_y_horiz_tap8);
196 vp_filter_set(res, VP_POLY4_Y0_LL,
197 filter_y_vert_tap4, sizeof filter_y_vert_tap4);
198 vp_filter_set(res, VP_POLY4_C0_LL,
199 filter_cr_horiz_tap4, sizeof filter_cr_horiz_tap4);
200}
201
202static void mixer_vsync_set_update(struct mixer_context *ctx, bool enable)
203{
204 struct mixer_resources *res = &ctx->mixer_res;
205
206 /* block update on vsync */
207 mixer_reg_writemask(res, MXR_STATUS, enable ?
208 MXR_STATUS_SYNC_ENABLE : 0, MXR_STATUS_SYNC_ENABLE);
209
210 vp_reg_write(res, VP_SHADOW_UPDATE, enable ?
211 VP_SHADOW_UPDATE_ENABLE : 0);
212}
213
214static void mixer_cfg_scan(struct mixer_context *ctx, unsigned int height)
215{
216 struct mixer_resources *res = &ctx->mixer_res;
217 u32 val;
218
219 /* choosing between interlace and progressive mode */
220 val = (ctx->interlace ? MXR_CFG_SCAN_INTERLACE :
221 MXR_CFG_SCAN_PROGRASSIVE);
222
223 /* choosing between porper HD and SD mode */
224 if (height == 480)
225 val |= MXR_CFG_SCAN_NTSC | MXR_CFG_SCAN_SD;
226 else if (height == 576)
227 val |= MXR_CFG_SCAN_PAL | MXR_CFG_SCAN_SD;
228 else if (height == 720)
229 val |= MXR_CFG_SCAN_HD_720 | MXR_CFG_SCAN_HD;
230 else if (height == 1080)
231 val |= MXR_CFG_SCAN_HD_1080 | MXR_CFG_SCAN_HD;
232 else
233 val |= MXR_CFG_SCAN_HD_720 | MXR_CFG_SCAN_HD;
234
235 mixer_reg_writemask(res, MXR_CFG, val, MXR_CFG_SCAN_MASK);
236}
237
238static void mixer_cfg_rgb_fmt(struct mixer_context *ctx, unsigned int height)
239{
240 struct mixer_resources *res = &ctx->mixer_res;
241 u32 val;
242
243 if (height == 480) {
244 val = MXR_CFG_RGB601_0_255;
245 } else if (height == 576) {
246 val = MXR_CFG_RGB601_0_255;
247 } else if (height == 720) {
248 val = MXR_CFG_RGB709_16_235;
249 mixer_reg_write(res, MXR_CM_COEFF_Y,
250 (1 << 30) | (94 << 20) | (314 << 10) |
251 (32 << 0));
252 mixer_reg_write(res, MXR_CM_COEFF_CB,
253 (972 << 20) | (851 << 10) | (225 << 0));
254 mixer_reg_write(res, MXR_CM_COEFF_CR,
255 (225 << 20) | (820 << 10) | (1004 << 0));
256 } else if (height == 1080) {
257 val = MXR_CFG_RGB709_16_235;
258 mixer_reg_write(res, MXR_CM_COEFF_Y,
259 (1 << 30) | (94 << 20) | (314 << 10) |
260 (32 << 0));
261 mixer_reg_write(res, MXR_CM_COEFF_CB,
262 (972 << 20) | (851 << 10) | (225 << 0));
263 mixer_reg_write(res, MXR_CM_COEFF_CR,
264 (225 << 20) | (820 << 10) | (1004 << 0));
265 } else {
266 val = MXR_CFG_RGB709_16_235;
267 mixer_reg_write(res, MXR_CM_COEFF_Y,
268 (1 << 30) | (94 << 20) | (314 << 10) |
269 (32 << 0));
270 mixer_reg_write(res, MXR_CM_COEFF_CB,
271 (972 << 20) | (851 << 10) | (225 << 0));
272 mixer_reg_write(res, MXR_CM_COEFF_CR,
273 (225 << 20) | (820 << 10) | (1004 << 0));
274 }
275
276 mixer_reg_writemask(res, MXR_CFG, val, MXR_CFG_RGB_FMT_MASK);
277}
278
279static void mixer_cfg_layer(struct mixer_context *ctx, int win, bool enable)
280{
281 struct mixer_resources *res = &ctx->mixer_res;
282 u32 val = enable ? ~0 : 0;
283
284 switch (win) {
285 case 0:
286 mixer_reg_writemask(res, MXR_CFG, val, MXR_CFG_GRP0_ENABLE);
287 break;
288 case 1:
289 mixer_reg_writemask(res, MXR_CFG, val, MXR_CFG_GRP1_ENABLE);
290 break;
291 case 2:
292 vp_reg_writemask(res, VP_ENABLE, val, VP_ENABLE_ON);
293 mixer_reg_writemask(res, MXR_CFG, val, MXR_CFG_VP_ENABLE);
294 break;
295 }
296}
297
298static void mixer_run(struct mixer_context *ctx)
299{
300 struct mixer_resources *res = &ctx->mixer_res;
301
302 mixer_reg_writemask(res, MXR_STATUS, ~0, MXR_STATUS_REG_RUN);
303
304 mixer_regs_dump(ctx);
305}
306
307static void vp_video_buffer(struct mixer_context *ctx, int win)
308{
309 struct mixer_resources *res = &ctx->mixer_res;
310 unsigned long flags;
311 struct hdmi_win_data *win_data;
312 unsigned int full_width, full_height, width, height;
313 unsigned int x_ratio, y_ratio;
314 unsigned int src_x_offset, src_y_offset, dst_x_offset, dst_y_offset;
315 unsigned int mode_width, mode_height;
316 unsigned int buf_num;
317 dma_addr_t luma_addr[2], chroma_addr[2];
318 bool tiled_mode = false;
319 bool crcb_mode = false;
320 u32 val;
321
322 win_data = &ctx->win_data[win];
323
324 switch (win_data->pixel_format) {
325 case DRM_FORMAT_NV12MT:
326 tiled_mode = true;
327 case DRM_FORMAT_NV12M:
328 crcb_mode = false;
329 buf_num = 2;
330 break;
331 /* TODO: single buffer format NV12, NV21 */
332 default:
333 /* ignore pixel format at disable time */
334 if (!win_data->dma_addr)
335 break;
336
337 DRM_ERROR("pixel format for vp is wrong [%d].\n",
338 win_data->pixel_format);
339 return;
340 }
341
342 full_width = win_data->fb_width;
343 full_height = win_data->fb_height;
344 width = win_data->crtc_width;
345 height = win_data->crtc_height;
346 mode_width = win_data->mode_width;
347 mode_height = win_data->mode_height;
348
349 /* scaling feature: (src << 16) / dst */
350 x_ratio = (width << 16) / width;
351 y_ratio = (height << 16) / height;
352
353 src_x_offset = win_data->fb_x;
354 src_y_offset = win_data->fb_y;
355 dst_x_offset = win_data->crtc_x;
356 dst_y_offset = win_data->crtc_y;
357
358 if (buf_num == 2) {
359 luma_addr[0] = win_data->dma_addr;
360 chroma_addr[0] = win_data->chroma_dma_addr;
361 } else {
362 luma_addr[0] = win_data->dma_addr;
363 chroma_addr[0] = win_data->dma_addr
364 + (full_width * full_height);
365 }
366
367 if (win_data->scan_flags & DRM_MODE_FLAG_INTERLACE) {
368 ctx->interlace = true;
369 if (tiled_mode) {
370 luma_addr[1] = luma_addr[0] + 0x40;
371 chroma_addr[1] = chroma_addr[0] + 0x40;
372 } else {
373 luma_addr[1] = luma_addr[0] + full_width;
374 chroma_addr[1] = chroma_addr[0] + full_width;
375 }
376 } else {
377 ctx->interlace = false;
378 luma_addr[1] = 0;
379 chroma_addr[1] = 0;
380 }
381
382 spin_lock_irqsave(&res->reg_slock, flags);
383 mixer_vsync_set_update(ctx, false);
384
385 /* interlace or progressive scan mode */
386 val = (ctx->interlace ? ~0 : 0);
387 vp_reg_writemask(res, VP_MODE, val, VP_MODE_LINE_SKIP);
388
389 /* setup format */
390 val = (crcb_mode ? VP_MODE_NV21 : VP_MODE_NV12);
391 val |= (tiled_mode ? VP_MODE_MEM_TILED : VP_MODE_MEM_LINEAR);
392 vp_reg_writemask(res, VP_MODE, val, VP_MODE_FMT_MASK);
393
394 /* setting size of input image */
395 vp_reg_write(res, VP_IMG_SIZE_Y, VP_IMG_HSIZE(full_width) |
396 VP_IMG_VSIZE(full_height));
397 /* chroma height has to reduced by 2 to avoid chroma distorions */
398 vp_reg_write(res, VP_IMG_SIZE_C, VP_IMG_HSIZE(full_width) |
399 VP_IMG_VSIZE(full_height / 2));
400
401 vp_reg_write(res, VP_SRC_WIDTH, width);
402 vp_reg_write(res, VP_SRC_HEIGHT, height);
403 vp_reg_write(res, VP_SRC_H_POSITION,
404 VP_SRC_H_POSITION_VAL(src_x_offset));
405 vp_reg_write(res, VP_SRC_V_POSITION, src_y_offset);
406
407 vp_reg_write(res, VP_DST_WIDTH, width);
408 vp_reg_write(res, VP_DST_H_POSITION, dst_x_offset);
409 if (ctx->interlace) {
410 vp_reg_write(res, VP_DST_HEIGHT, height / 2);
411 vp_reg_write(res, VP_DST_V_POSITION, dst_y_offset / 2);
412 } else {
413 vp_reg_write(res, VP_DST_HEIGHT, height);
414 vp_reg_write(res, VP_DST_V_POSITION, dst_y_offset);
415 }
416
417 vp_reg_write(res, VP_H_RATIO, x_ratio);
418 vp_reg_write(res, VP_V_RATIO, y_ratio);
419
420 vp_reg_write(res, VP_ENDIAN_MODE, VP_ENDIAN_MODE_LITTLE);
421
422 /* set buffer address to vp */
423 vp_reg_write(res, VP_TOP_Y_PTR, luma_addr[0]);
424 vp_reg_write(res, VP_BOT_Y_PTR, luma_addr[1]);
425 vp_reg_write(res, VP_TOP_C_PTR, chroma_addr[0]);
426 vp_reg_write(res, VP_BOT_C_PTR, chroma_addr[1]);
427
428 mixer_cfg_scan(ctx, mode_height);
429 mixer_cfg_rgb_fmt(ctx, mode_height);
430 mixer_cfg_layer(ctx, win, true);
431 mixer_run(ctx);
432
433 mixer_vsync_set_update(ctx, true);
434 spin_unlock_irqrestore(&res->reg_slock, flags);
435
436 vp_regs_dump(ctx);
437}
438
439static void mixer_graph_buffer(struct mixer_context *ctx, int win)
440{
441 struct mixer_resources *res = &ctx->mixer_res;
442 unsigned long flags;
443 struct hdmi_win_data *win_data;
444 unsigned int full_width, width, height;
445 unsigned int x_ratio, y_ratio;
446 unsigned int src_x_offset, src_y_offset, dst_x_offset, dst_y_offset;
447 unsigned int mode_width, mode_height;
448 dma_addr_t dma_addr;
449 unsigned int fmt;
450 u32 val;
451
452 win_data = &ctx->win_data[win];
453
454 #define RGB565 4
455 #define ARGB1555 5
456 #define ARGB4444 6
457 #define ARGB8888 7
458
459 switch (win_data->bpp) {
460 case 16:
461 fmt = ARGB4444;
462 break;
463 case 32:
464 fmt = ARGB8888;
465 break;
466 default:
467 fmt = ARGB8888;
468 }
469
470 dma_addr = win_data->dma_addr;
471 full_width = win_data->fb_width;
472 width = win_data->crtc_width;
473 height = win_data->crtc_height;
474 mode_width = win_data->mode_width;
475 mode_height = win_data->mode_height;
476
477 /* 2x scaling feature */
478 x_ratio = 0;
479 y_ratio = 0;
480
481 src_x_offset = win_data->fb_x;
482 src_y_offset = win_data->fb_y;
483 dst_x_offset = win_data->crtc_x;
484 dst_y_offset = win_data->crtc_y;
485
486 /* converting dma address base and source offset */
487 dma_addr = dma_addr
488 + (src_x_offset * win_data->bpp >> 3)
489 + (src_y_offset * full_width * win_data->bpp >> 3);
490 src_x_offset = 0;
491 src_y_offset = 0;
492
493 if (win_data->scan_flags & DRM_MODE_FLAG_INTERLACE)
494 ctx->interlace = true;
495 else
496 ctx->interlace = false;
497
498 spin_lock_irqsave(&res->reg_slock, flags);
499 mixer_vsync_set_update(ctx, false);
500
501 /* setup format */
502 mixer_reg_writemask(res, MXR_GRAPHIC_CFG(win),
503 MXR_GRP_CFG_FORMAT_VAL(fmt), MXR_GRP_CFG_FORMAT_MASK);
504
505 /* setup geometry */
506 mixer_reg_write(res, MXR_GRAPHIC_SPAN(win), full_width);
507
508 val = MXR_GRP_WH_WIDTH(width);
509 val |= MXR_GRP_WH_HEIGHT(height);
510 val |= MXR_GRP_WH_H_SCALE(x_ratio);
511 val |= MXR_GRP_WH_V_SCALE(y_ratio);
512 mixer_reg_write(res, MXR_GRAPHIC_WH(win), val);
513
514 /* setup offsets in source image */
515 val = MXR_GRP_SXY_SX(src_x_offset);
516 val |= MXR_GRP_SXY_SY(src_y_offset);
517 mixer_reg_write(res, MXR_GRAPHIC_SXY(win), val);
518
519 /* setup offsets in display image */
520 val = MXR_GRP_DXY_DX(dst_x_offset);
521 val |= MXR_GRP_DXY_DY(dst_y_offset);
522 mixer_reg_write(res, MXR_GRAPHIC_DXY(win), val);
523
524 /* set buffer address to mixer */
525 mixer_reg_write(res, MXR_GRAPHIC_BASE(win), dma_addr);
526
527 mixer_cfg_scan(ctx, mode_height);
528 mixer_cfg_rgb_fmt(ctx, mode_height);
529 mixer_cfg_layer(ctx, win, true);
530 mixer_run(ctx);
531
532 mixer_vsync_set_update(ctx, true);
533 spin_unlock_irqrestore(&res->reg_slock, flags);
534}
535
536static void vp_win_reset(struct mixer_context *ctx)
537{
538 struct mixer_resources *res = &ctx->mixer_res;
539 int tries = 100;
540
541 vp_reg_write(res, VP_SRESET, VP_SRESET_PROCESSING);
542 for (tries = 100; tries; --tries) {
543 /* waiting until VP_SRESET_PROCESSING is 0 */
544 if (~vp_reg_read(res, VP_SRESET) & VP_SRESET_PROCESSING)
545 break;
546 mdelay(10);
547 }
548 WARN(tries == 0, "failed to reset Video Processor\n");
549}
550
551static int mixer_enable_vblank(void *ctx, int pipe)
552{
553 struct mixer_context *mixer_ctx = ctx;
554 struct mixer_resources *res = &mixer_ctx->mixer_res;
555
556 DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
557
558 mixer_ctx->pipe = pipe;
559
560 /* enable vsync interrupt */
561 mixer_reg_writemask(res, MXR_INT_EN, MXR_INT_EN_VSYNC,
562 MXR_INT_EN_VSYNC);
563
564 return 0;
565}
566
567static void mixer_disable_vblank(void *ctx)
568{
569 struct mixer_context *mixer_ctx = ctx;
570 struct mixer_resources *res = &mixer_ctx->mixer_res;
571
572 DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
573
574 /* disable vsync interrupt */
575 mixer_reg_writemask(res, MXR_INT_EN, 0, MXR_INT_EN_VSYNC);
576}
577
578static void mixer_win_mode_set(void *ctx,
579 struct exynos_drm_overlay *overlay)
580{
581 struct mixer_context *mixer_ctx = ctx;
582 struct hdmi_win_data *win_data;
583 int win;
584
585 DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
586
587 if (!overlay) {
588 DRM_ERROR("overlay is NULL\n");
589 return;
590 }
591
592 DRM_DEBUG_KMS("set [%d]x[%d] at (%d,%d) to [%d]x[%d] at (%d,%d)\n",
593 overlay->fb_width, overlay->fb_height,
594 overlay->fb_x, overlay->fb_y,
595 overlay->crtc_width, overlay->crtc_height,
596 overlay->crtc_x, overlay->crtc_y);
597
598 win = overlay->zpos;
599 if (win == DEFAULT_ZPOS)
600 win = mixer_ctx->default_win;
601
602 if (win < 0 || win > HDMI_OVERLAY_NUMBER) {
603 DRM_ERROR("overlay plane[%d] is wrong\n", win);
604 return;
605 }
606
607 win_data = &mixer_ctx->win_data[win];
608
609 win_data->dma_addr = overlay->dma_addr[0];
610 win_data->vaddr = overlay->vaddr[0];
611 win_data->chroma_dma_addr = overlay->dma_addr[1];
612 win_data->chroma_vaddr = overlay->vaddr[1];
613 win_data->pixel_format = overlay->pixel_format;
614 win_data->bpp = overlay->bpp;
615
616 win_data->crtc_x = overlay->crtc_x;
617 win_data->crtc_y = overlay->crtc_y;
618 win_data->crtc_width = overlay->crtc_width;
619 win_data->crtc_height = overlay->crtc_height;
620
621 win_data->fb_x = overlay->fb_x;
622 win_data->fb_y = overlay->fb_y;
623 win_data->fb_width = overlay->fb_width;
624 win_data->fb_height = overlay->fb_height;
625
626 win_data->mode_width = overlay->mode_width;
627 win_data->mode_height = overlay->mode_height;
628
629 win_data->scan_flags = overlay->scan_flag;
630}
631
632static void mixer_win_commit(void *ctx, int zpos)
633{
634 struct mixer_context *mixer_ctx = ctx;
635 int win = zpos;
636
637 DRM_DEBUG_KMS("[%d] %s, win: %d\n", __LINE__, __func__, win);
638
639 if (win == DEFAULT_ZPOS)
640 win = mixer_ctx->default_win;
641
642 if (win < 0 || win > HDMI_OVERLAY_NUMBER) {
643 DRM_ERROR("overlay plane[%d] is wrong\n", win);
644 return;
645 }
646
647 if (win > 1)
648 vp_video_buffer(mixer_ctx, win);
649 else
650 mixer_graph_buffer(mixer_ctx, win);
651}
652
653static void mixer_win_disable(void *ctx, int zpos)
654{
655 struct mixer_context *mixer_ctx = ctx;
656 struct mixer_resources *res = &mixer_ctx->mixer_res;
657 unsigned long flags;
658 int win = zpos;
659
660 DRM_DEBUG_KMS("[%d] %s, win: %d\n", __LINE__, __func__, win);
661
662 if (win == DEFAULT_ZPOS)
663 win = mixer_ctx->default_win;
664
665 if (win < 0 || win > HDMI_OVERLAY_NUMBER) {
666 DRM_ERROR("overlay plane[%d] is wrong\n", win);
667 return;
668 }
669
670 spin_lock_irqsave(&res->reg_slock, flags);
671 mixer_vsync_set_update(mixer_ctx, false);
672
673 mixer_cfg_layer(mixer_ctx, win, false);
674
675 mixer_vsync_set_update(mixer_ctx, true);
676 spin_unlock_irqrestore(&res->reg_slock, flags);
677}
678
679static struct exynos_hdmi_overlay_ops overlay_ops = {
680 .enable_vblank = mixer_enable_vblank,
681 .disable_vblank = mixer_disable_vblank,
682 .win_mode_set = mixer_win_mode_set,
683 .win_commit = mixer_win_commit,
684 .win_disable = mixer_win_disable,
685};
686
687/* for pageflip event */
688static void mixer_finish_pageflip(struct drm_device *drm_dev, int crtc)
689{
690 struct exynos_drm_private *dev_priv = drm_dev->dev_private;
691 struct drm_pending_vblank_event *e, *t;
692 struct timeval now;
693 unsigned long flags;
694 bool is_checked = false;
695
696 spin_lock_irqsave(&drm_dev->event_lock, flags);
697
698 list_for_each_entry_safe(e, t, &dev_priv->pageflip_event_list,
699 base.link) {
700 /* if event's pipe isn't same as crtc then ignore it. */
701 if (crtc != e->pipe)
702 continue;
703
704 is_checked = true;
705 do_gettimeofday(&now);
706 e->event.sequence = 0;
707 e->event.tv_sec = now.tv_sec;
708 e->event.tv_usec = now.tv_usec;
709
710 list_move_tail(&e->base.link, &e->base.file_priv->event_list);
711 wake_up_interruptible(&e->base.file_priv->event_wait);
712 }
713
714 if (is_checked)
715 drm_vblank_put(drm_dev, crtc);
716
717 spin_unlock_irqrestore(&drm_dev->event_lock, flags);
718}
719
720static irqreturn_t mixer_irq_handler(int irq, void *arg)
721{
722 struct exynos_drm_hdmi_context *drm_hdmi_ctx = arg;
723 struct mixer_context *ctx =
724 (struct mixer_context *)drm_hdmi_ctx->ctx;
725 struct mixer_resources *res = &ctx->mixer_res;
726 u32 val, val_base;
727
728 spin_lock(&res->reg_slock);
729
730 /* read interrupt status for handling and clearing flags for VSYNC */
731 val = mixer_reg_read(res, MXR_INT_STATUS);
732
733 /* handling VSYNC */
734 if (val & MXR_INT_STATUS_VSYNC) {
735 /* interlace scan need to check shadow register */
736 if (ctx->interlace) {
737 val_base = mixer_reg_read(res, MXR_GRAPHIC_BASE_S(0));
738 if (ctx->win_data[0].dma_addr != val_base)
739 goto out;
740
741 val_base = mixer_reg_read(res, MXR_GRAPHIC_BASE_S(1));
742 if (ctx->win_data[1].dma_addr != val_base)
743 goto out;
744 }
745
746 drm_handle_vblank(drm_hdmi_ctx->drm_dev, ctx->pipe);
747 mixer_finish_pageflip(drm_hdmi_ctx->drm_dev, ctx->pipe);
748 }
749
750out:
751 /* clear interrupts */
752 if (~val & MXR_INT_EN_VSYNC) {
753 /* vsync interrupt use different bit for read and clear */
754 val &= ~MXR_INT_EN_VSYNC;
755 val |= MXR_INT_CLEAR_VSYNC;
756 }
757 mixer_reg_write(res, MXR_INT_STATUS, val);
758
759 spin_unlock(&res->reg_slock);
760
761 return IRQ_HANDLED;
762}
763
764static void mixer_win_reset(struct mixer_context *ctx)
765{
766 struct mixer_resources *res = &ctx->mixer_res;
767 unsigned long flags;
768 u32 val; /* value stored to register */
769
770 spin_lock_irqsave(&res->reg_slock, flags);
771 mixer_vsync_set_update(ctx, false);
772
773 mixer_reg_writemask(res, MXR_CFG, MXR_CFG_DST_HDMI, MXR_CFG_DST_MASK);
774
775 /* set output in RGB888 mode */
776 mixer_reg_writemask(res, MXR_CFG, MXR_CFG_OUT_RGB888, MXR_CFG_OUT_MASK);
777
778 /* 16 beat burst in DMA */
779 mixer_reg_writemask(res, MXR_STATUS, MXR_STATUS_16_BURST,
780 MXR_STATUS_BURST_MASK);
781
782 /* setting default layer priority: layer1 > video > layer0
783 * because typical usage scenario would be
784 * layer0 - framebuffer
785 * video - video overlay
786 * layer1 - OSD
787 */
788 val = MXR_LAYER_CFG_GRP0_VAL(1);
789 val |= MXR_LAYER_CFG_VP_VAL(2);
790 val |= MXR_LAYER_CFG_GRP1_VAL(3);
791 mixer_reg_write(res, MXR_LAYER_CFG, val);
792
793 /* setting background color */
794 mixer_reg_write(res, MXR_BG_COLOR0, 0x008080);
795 mixer_reg_write(res, MXR_BG_COLOR1, 0x008080);
796 mixer_reg_write(res, MXR_BG_COLOR2, 0x008080);
797
798 /* setting graphical layers */
799
800 val = MXR_GRP_CFG_COLOR_KEY_DISABLE; /* no blank key */
801 val |= MXR_GRP_CFG_WIN_BLEND_EN;
802 val |= MXR_GRP_CFG_ALPHA_VAL(0xff); /* non-transparent alpha */
803
804 /* the same configuration for both layers */
805 mixer_reg_write(res, MXR_GRAPHIC_CFG(0), val);
806
807 val |= MXR_GRP_CFG_BLEND_PRE_MUL;
808 val |= MXR_GRP_CFG_PIXEL_BLEND_EN;
809 mixer_reg_write(res, MXR_GRAPHIC_CFG(1), val);
810
811 /* configuration of Video Processor Registers */
812 vp_win_reset(ctx);
813 vp_default_filter(res);
814
815 /* disable all layers */
816 mixer_reg_writemask(res, MXR_CFG, 0, MXR_CFG_GRP0_ENABLE);
817 mixer_reg_writemask(res, MXR_CFG, 0, MXR_CFG_GRP1_ENABLE);
818 mixer_reg_writemask(res, MXR_CFG, 0, MXR_CFG_VP_ENABLE);
819
820 mixer_vsync_set_update(ctx, true);
821 spin_unlock_irqrestore(&res->reg_slock, flags);
822}
823
824static void mixer_resource_poweron(struct mixer_context *ctx)
825{
826 struct mixer_resources *res = &ctx->mixer_res;
827
828 DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
829
830 clk_enable(res->mixer);
831 clk_enable(res->vp);
832 clk_enable(res->sclk_mixer);
833
834 mixer_win_reset(ctx);
835}
836
837static void mixer_resource_poweroff(struct mixer_context *ctx)
838{
839 struct mixer_resources *res = &ctx->mixer_res;
840
841 DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
842
843 clk_disable(res->mixer);
844 clk_disable(res->vp);
845 clk_disable(res->sclk_mixer);
846}
847
848static int mixer_runtime_resume(struct device *dev)
849{
850 struct exynos_drm_hdmi_context *ctx = get_mixer_context(dev);
851
852 DRM_DEBUG_KMS("resume - start\n");
853
854 mixer_resource_poweron((struct mixer_context *)ctx->ctx);
855
856 return 0;
857}
858
859static int mixer_runtime_suspend(struct device *dev)
860{
861 struct exynos_drm_hdmi_context *ctx = get_mixer_context(dev);
862
863 DRM_DEBUG_KMS("suspend - start\n");
864
865 mixer_resource_poweroff((struct mixer_context *)ctx->ctx);
866
867 return 0;
868}
869
870static const struct dev_pm_ops mixer_pm_ops = {
871 .runtime_suspend = mixer_runtime_suspend,
872 .runtime_resume = mixer_runtime_resume,
873};
874
875static int __devinit mixer_resources_init(struct exynos_drm_hdmi_context *ctx,
876 struct platform_device *pdev)
877{
878 struct mixer_context *mixer_ctx =
879 (struct mixer_context *)ctx->ctx;
880 struct device *dev = &pdev->dev;
881 struct mixer_resources *mixer_res = &mixer_ctx->mixer_res;
882 struct resource *res;
883 int ret;
884
885 mixer_res->dev = dev;
886 spin_lock_init(&mixer_res->reg_slock);
887
888 mixer_res->mixer = clk_get(dev, "mixer");
889 if (IS_ERR_OR_NULL(mixer_res->mixer)) {
890 dev_err(dev, "failed to get clock 'mixer'\n");
891 ret = -ENODEV;
892 goto fail;
893 }
894 mixer_res->vp = clk_get(dev, "vp");
895 if (IS_ERR_OR_NULL(mixer_res->vp)) {
896 dev_err(dev, "failed to get clock 'vp'\n");
897 ret = -ENODEV;
898 goto fail;
899 }
900 mixer_res->sclk_mixer = clk_get(dev, "sclk_mixer");
901 if (IS_ERR_OR_NULL(mixer_res->sclk_mixer)) {
902 dev_err(dev, "failed to get clock 'sclk_mixer'\n");
903 ret = -ENODEV;
904 goto fail;
905 }
906 mixer_res->sclk_hdmi = clk_get(dev, "sclk_hdmi");
907 if (IS_ERR_OR_NULL(mixer_res->sclk_hdmi)) {
908 dev_err(dev, "failed to get clock 'sclk_hdmi'\n");
909 ret = -ENODEV;
910 goto fail;
911 }
912 mixer_res->sclk_dac = clk_get(dev, "sclk_dac");
913 if (IS_ERR_OR_NULL(mixer_res->sclk_dac)) {
914 dev_err(dev, "failed to get clock 'sclk_dac'\n");
915 ret = -ENODEV;
916 goto fail;
917 }
918 res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "mxr");
919 if (res == NULL) {
920 dev_err(dev, "get memory resource failed.\n");
921 ret = -ENXIO;
922 goto fail;
923 }
924
925 clk_set_parent(mixer_res->sclk_mixer, mixer_res->sclk_hdmi);
926
927 mixer_res->mixer_regs = ioremap(res->start, resource_size(res));
928 if (mixer_res->mixer_regs == NULL) {
929 dev_err(dev, "register mapping failed.\n");
930 ret = -ENXIO;
931 goto fail;
932 }
933
934 res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "vp");
935 if (res == NULL) {
936 dev_err(dev, "get memory resource failed.\n");
937 ret = -ENXIO;
938 goto fail_mixer_regs;
939 }
940
941 mixer_res->vp_regs = ioremap(res->start, resource_size(res));
942 if (mixer_res->vp_regs == NULL) {
943 dev_err(dev, "register mapping failed.\n");
944 ret = -ENXIO;
945 goto fail_mixer_regs;
946 }
947
948 res = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "irq");
949 if (res == NULL) {
950 dev_err(dev, "get interrupt resource failed.\n");
951 ret = -ENXIO;
952 goto fail_vp_regs;
953 }
954
955 ret = request_irq(res->start, mixer_irq_handler, 0, "drm_mixer", ctx);
956 if (ret) {
957 dev_err(dev, "request interrupt failed.\n");
958 goto fail_vp_regs;
959 }
960 mixer_res->irq = res->start;
961
962 return 0;
963
964fail_vp_regs:
965 iounmap(mixer_res->vp_regs);
966
967fail_mixer_regs:
968 iounmap(mixer_res->mixer_regs);
969
970fail:
971 if (!IS_ERR_OR_NULL(mixer_res->sclk_dac))
972 clk_put(mixer_res->sclk_dac);
973 if (!IS_ERR_OR_NULL(mixer_res->sclk_hdmi))
974 clk_put(mixer_res->sclk_hdmi);
975 if (!IS_ERR_OR_NULL(mixer_res->sclk_mixer))
976 clk_put(mixer_res->sclk_mixer);
977 if (!IS_ERR_OR_NULL(mixer_res->vp))
978 clk_put(mixer_res->vp);
979 if (!IS_ERR_OR_NULL(mixer_res->mixer))
980 clk_put(mixer_res->mixer);
981 mixer_res->dev = NULL;
982 return ret;
983}
984
985static void mixer_resources_cleanup(struct mixer_context *ctx)
986{
987 struct mixer_resources *res = &ctx->mixer_res;
988
989 disable_irq(res->irq);
990 free_irq(res->irq, ctx);
991
992 iounmap(res->vp_regs);
993 iounmap(res->mixer_regs);
994}
995
996static int __devinit mixer_probe(struct platform_device *pdev)
997{
998 struct device *dev = &pdev->dev;
999 struct exynos_drm_hdmi_context *drm_hdmi_ctx;
1000 struct mixer_context *ctx;
1001 int ret;
1002
1003 dev_info(dev, "probe start\n");
1004
1005 drm_hdmi_ctx = kzalloc(sizeof(*drm_hdmi_ctx), GFP_KERNEL);
1006 if (!drm_hdmi_ctx) {
1007 DRM_ERROR("failed to allocate common hdmi context.\n");
1008 return -ENOMEM;
1009 }
1010
1011 ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
1012 if (!ctx) {
1013 DRM_ERROR("failed to alloc mixer context.\n");
1014 kfree(drm_hdmi_ctx);
1015 return -ENOMEM;
1016 }
1017
1018 drm_hdmi_ctx->ctx = (void *)ctx;
1019
1020 platform_set_drvdata(pdev, drm_hdmi_ctx);
1021
1022 /* acquire resources: regs, irqs, clocks */
1023 ret = mixer_resources_init(drm_hdmi_ctx, pdev);
1024 if (ret)
1025 goto fail;
1026
1027 /* register specific callback point to common hdmi. */
1028 exynos_drm_overlay_ops_register(&overlay_ops);
1029
1030 mixer_resource_poweron(ctx);
1031
1032 return 0;
1033
1034
1035fail:
1036 dev_info(dev, "probe failed\n");
1037 return ret;
1038}
1039
1040static int mixer_remove(struct platform_device *pdev)
1041{
1042 struct device *dev = &pdev->dev;
1043 struct exynos_drm_hdmi_context *drm_hdmi_ctx =
1044 platform_get_drvdata(pdev);
1045 struct mixer_context *ctx = (struct mixer_context *)drm_hdmi_ctx->ctx;
1046
1047 dev_info(dev, "remove sucessful\n");
1048
1049 mixer_resource_poweroff(ctx);
1050 mixer_resources_cleanup(ctx);
1051
1052 return 0;
1053}
1054
1055struct platform_driver mixer_driver = {
1056 .driver = {
1057 .name = "s5p-mixer",
1058 .owner = THIS_MODULE,
1059 .pm = &mixer_pm_ops,
1060 },
1061 .probe = mixer_probe,
1062 .remove = __devexit_p(mixer_remove),
1063};
1064EXPORT_SYMBOL(mixer_driver);
1065
1066MODULE_AUTHOR("Seung-Woo Kim, <sw0312.kim@samsung.com>");
1067MODULE_AUTHOR("Inki Dae <inki.dae@samsung.com>");
1068MODULE_AUTHOR("Joonyoung Shim <jy0922.shim@samsung.com>");
1069MODULE_DESCRIPTION("Samsung DRM HDMI mixer Driver");
1070MODULE_LICENSE("GPL");
diff --git a/drivers/gpu/drm/exynos/exynos_mixer.h b/drivers/gpu/drm/exynos/exynos_mixer.h
new file mode 100644
index 000000000000..cebacfefc077
--- /dev/null
+++ b/drivers/gpu/drm/exynos/exynos_mixer.h
@@ -0,0 +1,92 @@
1/*
2 *
3 * Copyright (c) 2011 Samsung Electronics Co., Ltd.
4 * Authors:
5 * Seung-Woo Kim <sw0312.kim@samsung.com>
6 * Inki Dae <inki.dae@samsung.com>
7 *
8 * Permission is hereby granted, free of charge, to any person obtaining a
9 * copy of this software and associated documentation files (the "Software"),
10 * to deal in the Software without restriction, including without limitation
11 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
12 * and/or sell copies of the Software, and to permit persons to whom the
13 * Software is furnished to do so, subject to the following conditions:
14 *
15 * The above copyright notice and this permission notice (including the next
16 * paragraph) shall be included in all copies or substantial portions of the
17 * Software.
18 *
19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
22 * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
23 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
24 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
25 * OTHER DEALINGS IN THE SOFTWARE.
26 */
27
28#ifndef _EXYNOS_MIXER_H_
29#define _EXYNOS_MIXER_H_
30
31#define HDMI_OVERLAY_NUMBER 3
32
33struct hdmi_win_data {
34 dma_addr_t dma_addr;
35 void __iomem *vaddr;
36 dma_addr_t chroma_dma_addr;
37 void __iomem *chroma_vaddr;
38 uint32_t pixel_format;
39 unsigned int bpp;
40 unsigned int crtc_x;
41 unsigned int crtc_y;
42 unsigned int crtc_width;
43 unsigned int crtc_height;
44 unsigned int fb_x;
45 unsigned int fb_y;
46 unsigned int fb_width;
47 unsigned int fb_height;
48 unsigned int mode_width;
49 unsigned int mode_height;
50 unsigned int scan_flags;
51};
52
53struct mixer_resources {
54 struct device *dev;
55 /** interrupt index */
56 int irq;
57 /** pointer to Mixer registers */
58 void __iomem *mixer_regs;
59 /** pointer to Video Processor registers */
60 void __iomem *vp_regs;
61 /** spinlock for protection of registers */
62 spinlock_t reg_slock;
63 /** other resources */
64 struct clk *mixer;
65 struct clk *vp;
66 struct clk *sclk_mixer;
67 struct clk *sclk_hdmi;
68 struct clk *sclk_dac;
69};
70
71struct mixer_context {
72 unsigned int default_win;
73 struct fb_videomode *default_timing;
74 unsigned int default_bpp;
75
76 /** mixer interrupt */
77 unsigned int irq;
78 /** current crtc pipe for vblank */
79 int pipe;
80 /** interlace scan mode */
81 bool interlace;
82 /** vp enabled status */
83 bool vp_enabled;
84
85 /** mixer and vp resources */
86 struct mixer_resources mixer_res;
87
88 /** overlay window data */
89 struct hdmi_win_data win_data[HDMI_OVERLAY_NUMBER];
90};
91
92#endif
diff --git a/drivers/gpu/drm/exynos/regs-hdmi.h b/drivers/gpu/drm/exynos/regs-hdmi.h
new file mode 100644
index 000000000000..72e6b52be740
--- /dev/null
+++ b/drivers/gpu/drm/exynos/regs-hdmi.h
@@ -0,0 +1,147 @@
1/*
2 *
3 * Cloned from drivers/media/video/s5p-tv/regs-hdmi.h
4 *
5 * Copyright (c) 2010-2011 Samsung Electronics Co., Ltd.
6 * http://www.samsung.com/
7 *
8 * HDMI register header file for Samsung TVOUT driver
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License version 2 as
12 * published by the Free Software Foundation.
13*/
14
15#ifndef SAMSUNG_REGS_HDMI_H
16#define SAMSUNG_REGS_HDMI_H
17
18/*
19 * Register part
20*/
21
22#define HDMI_CTRL_BASE(x) ((x) + 0x00000000)
23#define HDMI_CORE_BASE(x) ((x) + 0x00010000)
24#define HDMI_TG_BASE(x) ((x) + 0x00050000)
25
26/* Control registers */
27#define HDMI_INTC_CON HDMI_CTRL_BASE(0x0000)
28#define HDMI_INTC_FLAG HDMI_CTRL_BASE(0x0004)
29#define HDMI_HPD_STATUS HDMI_CTRL_BASE(0x000C)
30#define HDMI_PHY_RSTOUT HDMI_CTRL_BASE(0x0014)
31#define HDMI_PHY_VPLL HDMI_CTRL_BASE(0x0018)
32#define HDMI_PHY_CMU HDMI_CTRL_BASE(0x001C)
33#define HDMI_CORE_RSTOUT HDMI_CTRL_BASE(0x0020)
34
35/* Core registers */
36#define HDMI_CON_0 HDMI_CORE_BASE(0x0000)
37#define HDMI_CON_1 HDMI_CORE_BASE(0x0004)
38#define HDMI_CON_2 HDMI_CORE_BASE(0x0008)
39#define HDMI_SYS_STATUS HDMI_CORE_BASE(0x0010)
40#define HDMI_PHY_STATUS HDMI_CORE_BASE(0x0014)
41#define HDMI_STATUS_EN HDMI_CORE_BASE(0x0020)
42#define HDMI_HPD HDMI_CORE_BASE(0x0030)
43#define HDMI_MODE_SEL HDMI_CORE_BASE(0x0040)
44#define HDMI_BLUE_SCREEN_0 HDMI_CORE_BASE(0x0050)
45#define HDMI_BLUE_SCREEN_1 HDMI_CORE_BASE(0x0054)
46#define HDMI_BLUE_SCREEN_2 HDMI_CORE_BASE(0x0058)
47#define HDMI_H_BLANK_0 HDMI_CORE_BASE(0x00A0)
48#define HDMI_H_BLANK_1 HDMI_CORE_BASE(0x00A4)
49#define HDMI_V_BLANK_0 HDMI_CORE_BASE(0x00B0)
50#define HDMI_V_BLANK_1 HDMI_CORE_BASE(0x00B4)
51#define HDMI_V_BLANK_2 HDMI_CORE_BASE(0x00B8)
52#define HDMI_H_V_LINE_0 HDMI_CORE_BASE(0x00C0)
53#define HDMI_H_V_LINE_1 HDMI_CORE_BASE(0x00C4)
54#define HDMI_H_V_LINE_2 HDMI_CORE_BASE(0x00C8)
55#define HDMI_VSYNC_POL HDMI_CORE_BASE(0x00E4)
56#define HDMI_INT_PRO_MODE HDMI_CORE_BASE(0x00E8)
57#define HDMI_V_BLANK_F_0 HDMI_CORE_BASE(0x0110)
58#define HDMI_V_BLANK_F_1 HDMI_CORE_BASE(0x0114)
59#define HDMI_V_BLANK_F_2 HDMI_CORE_BASE(0x0118)
60#define HDMI_H_SYNC_GEN_0 HDMI_CORE_BASE(0x0120)
61#define HDMI_H_SYNC_GEN_1 HDMI_CORE_BASE(0x0124)
62#define HDMI_H_SYNC_GEN_2 HDMI_CORE_BASE(0x0128)
63#define HDMI_V_SYNC_GEN_1_0 HDMI_CORE_BASE(0x0130)
64#define HDMI_V_SYNC_GEN_1_1 HDMI_CORE_BASE(0x0134)
65#define HDMI_V_SYNC_GEN_1_2 HDMI_CORE_BASE(0x0138)
66#define HDMI_V_SYNC_GEN_2_0 HDMI_CORE_BASE(0x0140)
67#define HDMI_V_SYNC_GEN_2_1 HDMI_CORE_BASE(0x0144)
68#define HDMI_V_SYNC_GEN_2_2 HDMI_CORE_BASE(0x0148)
69#define HDMI_V_SYNC_GEN_3_0 HDMI_CORE_BASE(0x0150)
70#define HDMI_V_SYNC_GEN_3_1 HDMI_CORE_BASE(0x0154)
71#define HDMI_V_SYNC_GEN_3_2 HDMI_CORE_BASE(0x0158)
72#define HDMI_ACR_CON HDMI_CORE_BASE(0x0180)
73#define HDMI_AVI_CON HDMI_CORE_BASE(0x0300)
74#define HDMI_AVI_BYTE(n) HDMI_CORE_BASE(0x0320 + 4 * (n))
75#define HDMI_DC_CONTROL HDMI_CORE_BASE(0x05C0)
76#define HDMI_VIDEO_PATTERN_GEN HDMI_CORE_BASE(0x05C4)
77#define HDMI_HPD_GEN HDMI_CORE_BASE(0x05C8)
78#define HDMI_AUI_CON HDMI_CORE_BASE(0x0360)
79#define HDMI_SPD_CON HDMI_CORE_BASE(0x0400)
80
81/* Timing generator registers */
82#define HDMI_TG_CMD HDMI_TG_BASE(0x0000)
83#define HDMI_TG_H_FSZ_L HDMI_TG_BASE(0x0018)
84#define HDMI_TG_H_FSZ_H HDMI_TG_BASE(0x001C)
85#define HDMI_TG_HACT_ST_L HDMI_TG_BASE(0x0020)
86#define HDMI_TG_HACT_ST_H HDMI_TG_BASE(0x0024)
87#define HDMI_TG_HACT_SZ_L HDMI_TG_BASE(0x0028)
88#define HDMI_TG_HACT_SZ_H HDMI_TG_BASE(0x002C)
89#define HDMI_TG_V_FSZ_L HDMI_TG_BASE(0x0030)
90#define HDMI_TG_V_FSZ_H HDMI_TG_BASE(0x0034)
91#define HDMI_TG_VSYNC_L HDMI_TG_BASE(0x0038)
92#define HDMI_TG_VSYNC_H HDMI_TG_BASE(0x003C)
93#define HDMI_TG_VSYNC2_L HDMI_TG_BASE(0x0040)
94#define HDMI_TG_VSYNC2_H HDMI_TG_BASE(0x0044)
95#define HDMI_TG_VACT_ST_L HDMI_TG_BASE(0x0048)
96#define HDMI_TG_VACT_ST_H HDMI_TG_BASE(0x004C)
97#define HDMI_TG_VACT_SZ_L HDMI_TG_BASE(0x0050)
98#define HDMI_TG_VACT_SZ_H HDMI_TG_BASE(0x0054)
99#define HDMI_TG_FIELD_CHG_L HDMI_TG_BASE(0x0058)
100#define HDMI_TG_FIELD_CHG_H HDMI_TG_BASE(0x005C)
101#define HDMI_TG_VACT_ST2_L HDMI_TG_BASE(0x0060)
102#define HDMI_TG_VACT_ST2_H HDMI_TG_BASE(0x0064)
103#define HDMI_TG_VSYNC_TOP_HDMI_L HDMI_TG_BASE(0x0078)
104#define HDMI_TG_VSYNC_TOP_HDMI_H HDMI_TG_BASE(0x007C)
105#define HDMI_TG_VSYNC_BOT_HDMI_L HDMI_TG_BASE(0x0080)
106#define HDMI_TG_VSYNC_BOT_HDMI_H HDMI_TG_BASE(0x0084)
107#define HDMI_TG_FIELD_TOP_HDMI_L HDMI_TG_BASE(0x0088)
108#define HDMI_TG_FIELD_TOP_HDMI_H HDMI_TG_BASE(0x008C)
109#define HDMI_TG_FIELD_BOT_HDMI_L HDMI_TG_BASE(0x0090)
110#define HDMI_TG_FIELD_BOT_HDMI_H HDMI_TG_BASE(0x0094)
111
112/*
113 * Bit definition part
114 */
115
116/* HDMI_INTC_CON */
117#define HDMI_INTC_EN_GLOBAL (1 << 6)
118#define HDMI_INTC_EN_HPD_PLUG (1 << 3)
119#define HDMI_INTC_EN_HPD_UNPLUG (1 << 2)
120
121/* HDMI_INTC_FLAG */
122#define HDMI_INTC_FLAG_HPD_PLUG (1 << 3)
123#define HDMI_INTC_FLAG_HPD_UNPLUG (1 << 2)
124
125/* HDMI_PHY_RSTOUT */
126#define HDMI_PHY_SW_RSTOUT (1 << 0)
127
128/* HDMI_CORE_RSTOUT */
129#define HDMI_CORE_SW_RSTOUT (1 << 0)
130
131/* HDMI_CON_0 */
132#define HDMI_BLUE_SCR_EN (1 << 5)
133#define HDMI_EN (1 << 0)
134
135/* HDMI_PHY_STATUS */
136#define HDMI_PHY_STATUS_READY (1 << 0)
137
138/* HDMI_MODE_SEL */
139#define HDMI_MODE_HDMI_EN (1 << 1)
140#define HDMI_MODE_DVI_EN (1 << 0)
141#define HDMI_MODE_MASK (3 << 0)
142
143/* HDMI_TG_CMD */
144#define HDMI_TG_EN (1 << 0)
145#define HDMI_FIELD_EN (1 << 1)
146
147#endif /* SAMSUNG_REGS_HDMI_H */
diff --git a/drivers/gpu/drm/exynos/regs-mixer.h b/drivers/gpu/drm/exynos/regs-mixer.h
new file mode 100644
index 000000000000..fd2f4d14cf6d
--- /dev/null
+++ b/drivers/gpu/drm/exynos/regs-mixer.h
@@ -0,0 +1,141 @@
1/*
2 *
3 * Cloned from drivers/media/video/s5p-tv/regs-mixer.h
4 *
5 * Copyright (c) 2010-2011 Samsung Electronics Co., Ltd.
6 * http://www.samsung.com/
7 *
8 * Mixer register header file for Samsung Mixer driver
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License version 2 as
12 * published by the Free Software Foundation.
13*/
14#ifndef SAMSUNG_REGS_MIXER_H
15#define SAMSUNG_REGS_MIXER_H
16
17/*
18 * Register part
19 */
20#define MXR_STATUS 0x0000
21#define MXR_CFG 0x0004
22#define MXR_INT_EN 0x0008
23#define MXR_INT_STATUS 0x000C
24#define MXR_LAYER_CFG 0x0010
25#define MXR_VIDEO_CFG 0x0014
26#define MXR_GRAPHIC0_CFG 0x0020
27#define MXR_GRAPHIC0_BASE 0x0024
28#define MXR_GRAPHIC0_SPAN 0x0028
29#define MXR_GRAPHIC0_SXY 0x002C
30#define MXR_GRAPHIC0_WH 0x0030
31#define MXR_GRAPHIC0_DXY 0x0034
32#define MXR_GRAPHIC0_BLANK 0x0038
33#define MXR_GRAPHIC1_CFG 0x0040
34#define MXR_GRAPHIC1_BASE 0x0044
35#define MXR_GRAPHIC1_SPAN 0x0048
36#define MXR_GRAPHIC1_SXY 0x004C
37#define MXR_GRAPHIC1_WH 0x0050
38#define MXR_GRAPHIC1_DXY 0x0054
39#define MXR_GRAPHIC1_BLANK 0x0058
40#define MXR_BG_CFG 0x0060
41#define MXR_BG_COLOR0 0x0064
42#define MXR_BG_COLOR1 0x0068
43#define MXR_BG_COLOR2 0x006C
44#define MXR_CM_COEFF_Y 0x0080
45#define MXR_CM_COEFF_CB 0x0084
46#define MXR_CM_COEFF_CR 0x0088
47#define MXR_GRAPHIC0_BASE_S 0x2024
48#define MXR_GRAPHIC1_BASE_S 0x2044
49
50/* for parametrized access to layer registers */
51#define MXR_GRAPHIC_CFG(i) (0x0020 + (i) * 0x20)
52#define MXR_GRAPHIC_BASE(i) (0x0024 + (i) * 0x20)
53#define MXR_GRAPHIC_SPAN(i) (0x0028 + (i) * 0x20)
54#define MXR_GRAPHIC_SXY(i) (0x002C + (i) * 0x20)
55#define MXR_GRAPHIC_WH(i) (0x0030 + (i) * 0x20)
56#define MXR_GRAPHIC_DXY(i) (0x0034 + (i) * 0x20)
57#define MXR_GRAPHIC_BLANK(i) (0x0038 + (i) * 0x20)
58#define MXR_GRAPHIC_BASE_S(i) (0x2024 + (i) * 0x20)
59
60/*
61 * Bit definition part
62 */
63
64/* generates mask for range of bits */
65#define MXR_MASK(high_bit, low_bit) \
66 (((2 << ((high_bit) - (low_bit))) - 1) << (low_bit))
67
68#define MXR_MASK_VAL(val, high_bit, low_bit) \
69 (((val) << (low_bit)) & MXR_MASK(high_bit, low_bit))
70
71/* bits for MXR_STATUS */
72#define MXR_STATUS_16_BURST (1 << 7)
73#define MXR_STATUS_BURST_MASK (1 << 7)
74#define MXR_STATUS_BIG_ENDIAN (1 << 3)
75#define MXR_STATUS_ENDIAN_MASK (1 << 3)
76#define MXR_STATUS_SYNC_ENABLE (1 << 2)
77#define MXR_STATUS_REG_RUN (1 << 0)
78
79/* bits for MXR_CFG */
80#define MXR_CFG_RGB601_0_255 (0 << 9)
81#define MXR_CFG_RGB601_16_235 (1 << 9)
82#define MXR_CFG_RGB709_0_255 (2 << 9)
83#define MXR_CFG_RGB709_16_235 (3 << 9)
84#define MXR_CFG_RGB_FMT_MASK 0x600
85#define MXR_CFG_OUT_YUV444 (0 << 8)
86#define MXR_CFG_OUT_RGB888 (1 << 8)
87#define MXR_CFG_OUT_MASK (1 << 8)
88#define MXR_CFG_DST_SDO (0 << 7)
89#define MXR_CFG_DST_HDMI (1 << 7)
90#define MXR_CFG_DST_MASK (1 << 7)
91#define MXR_CFG_SCAN_HD_720 (0 << 6)
92#define MXR_CFG_SCAN_HD_1080 (1 << 6)
93#define MXR_CFG_GRP1_ENABLE (1 << 5)
94#define MXR_CFG_GRP0_ENABLE (1 << 4)
95#define MXR_CFG_VP_ENABLE (1 << 3)
96#define MXR_CFG_SCAN_INTERLACE (0 << 2)
97#define MXR_CFG_SCAN_PROGRASSIVE (1 << 2)
98#define MXR_CFG_SCAN_NTSC (0 << 1)
99#define MXR_CFG_SCAN_PAL (1 << 1)
100#define MXR_CFG_SCAN_SD (0 << 0)
101#define MXR_CFG_SCAN_HD (1 << 0)
102#define MXR_CFG_SCAN_MASK 0x47
103
104/* bits for MXR_GRAPHICn_CFG */
105#define MXR_GRP_CFG_COLOR_KEY_DISABLE (1 << 21)
106#define MXR_GRP_CFG_BLEND_PRE_MUL (1 << 20)
107#define MXR_GRP_CFG_WIN_BLEND_EN (1 << 17)
108#define MXR_GRP_CFG_PIXEL_BLEND_EN (1 << 16)
109#define MXR_GRP_CFG_FORMAT_VAL(x) MXR_MASK_VAL(x, 11, 8)
110#define MXR_GRP_CFG_FORMAT_MASK MXR_GRP_CFG_FORMAT_VAL(~0)
111#define MXR_GRP_CFG_ALPHA_VAL(x) MXR_MASK_VAL(x, 7, 0)
112
113/* bits for MXR_GRAPHICn_WH */
114#define MXR_GRP_WH_H_SCALE(x) MXR_MASK_VAL(x, 28, 28)
115#define MXR_GRP_WH_V_SCALE(x) MXR_MASK_VAL(x, 12, 12)
116#define MXR_GRP_WH_WIDTH(x) MXR_MASK_VAL(x, 26, 16)
117#define MXR_GRP_WH_HEIGHT(x) MXR_MASK_VAL(x, 10, 0)
118
119/* bits for MXR_GRAPHICn_SXY */
120#define MXR_GRP_SXY_SX(x) MXR_MASK_VAL(x, 26, 16)
121#define MXR_GRP_SXY_SY(x) MXR_MASK_VAL(x, 10, 0)
122
123/* bits for MXR_GRAPHICn_DXY */
124#define MXR_GRP_DXY_DX(x) MXR_MASK_VAL(x, 26, 16)
125#define MXR_GRP_DXY_DY(x) MXR_MASK_VAL(x, 10, 0)
126
127/* bits for MXR_INT_EN */
128#define MXR_INT_EN_VSYNC (1 << 11)
129#define MXR_INT_EN_ALL (0x0f << 8)
130
131/* bit for MXR_INT_STATUS */
132#define MXR_INT_CLEAR_VSYNC (1 << 11)
133#define MXR_INT_STATUS_VSYNC (1 << 0)
134
135/* bit for MXR_LAYER_CFG */
136#define MXR_LAYER_CFG_GRP1_VAL(x) MXR_MASK_VAL(x, 11, 8)
137#define MXR_LAYER_CFG_GRP0_VAL(x) MXR_MASK_VAL(x, 7, 4)
138#define MXR_LAYER_CFG_VP_VAL(x) MXR_MASK_VAL(x, 3, 0)
139
140#endif /* SAMSUNG_REGS_MIXER_H */
141
diff --git a/drivers/gpu/drm/exynos/regs-vp.h b/drivers/gpu/drm/exynos/regs-vp.h
new file mode 100644
index 000000000000..10b737af0a72
--- /dev/null
+++ b/drivers/gpu/drm/exynos/regs-vp.h
@@ -0,0 +1,91 @@
1/*
2 *
3 * Cloned from drivers/media/video/s5p-tv/regs-vp.h
4 *
5 * Copyright (c) 2010-2011 Samsung Electronics Co., Ltd.
6 * http://www.samsung.com/
7 *
8 * Video processor register header file for Samsung Mixer driver
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License version 2 as
12 * published by the Free Software Foundation.
13 */
14
15#ifndef SAMSUNG_REGS_VP_H
16#define SAMSUNG_REGS_VP_H
17
18/*
19 * Register part
20 */
21
22#define VP_ENABLE 0x0000
23#define VP_SRESET 0x0004
24#define VP_SHADOW_UPDATE 0x0008
25#define VP_FIELD_ID 0x000C
26#define VP_MODE 0x0010
27#define VP_IMG_SIZE_Y 0x0014
28#define VP_IMG_SIZE_C 0x0018
29#define VP_PER_RATE_CTRL 0x001C
30#define VP_TOP_Y_PTR 0x0028
31#define VP_BOT_Y_PTR 0x002C
32#define VP_TOP_C_PTR 0x0030
33#define VP_BOT_C_PTR 0x0034
34#define VP_ENDIAN_MODE 0x03CC
35#define VP_SRC_H_POSITION 0x0044
36#define VP_SRC_V_POSITION 0x0048
37#define VP_SRC_WIDTH 0x004C
38#define VP_SRC_HEIGHT 0x0050
39#define VP_DST_H_POSITION 0x0054
40#define VP_DST_V_POSITION 0x0058
41#define VP_DST_WIDTH 0x005C
42#define VP_DST_HEIGHT 0x0060
43#define VP_H_RATIO 0x0064
44#define VP_V_RATIO 0x0068
45#define VP_POLY8_Y0_LL 0x006C
46#define VP_POLY4_Y0_LL 0x00EC
47#define VP_POLY4_C0_LL 0x012C
48
49/*
50 * Bit definition part
51 */
52
53/* generates mask for range of bits */
54
55#define VP_MASK(high_bit, low_bit) \
56 (((2 << ((high_bit) - (low_bit))) - 1) << (low_bit))
57
58#define VP_MASK_VAL(val, high_bit, low_bit) \
59 (((val) << (low_bit)) & VP_MASK(high_bit, low_bit))
60
61 /* VP_ENABLE */
62#define VP_ENABLE_ON (1 << 0)
63
64/* VP_SRESET */
65#define VP_SRESET_PROCESSING (1 << 0)
66
67/* VP_SHADOW_UPDATE */
68#define VP_SHADOW_UPDATE_ENABLE (1 << 0)
69
70/* VP_MODE */
71#define VP_MODE_NV12 (0 << 6)
72#define VP_MODE_NV21 (1 << 6)
73#define VP_MODE_LINE_SKIP (1 << 5)
74#define VP_MODE_MEM_LINEAR (0 << 4)
75#define VP_MODE_MEM_TILED (1 << 4)
76#define VP_MODE_FMT_MASK (5 << 4)
77#define VP_MODE_FIELD_ID_AUTO_TOGGLING (1 << 2)
78#define VP_MODE_2D_IPC (1 << 1)
79
80/* VP_IMG_SIZE_Y */
81/* VP_IMG_SIZE_C */
82#define VP_IMG_HSIZE(x) VP_MASK_VAL(x, 29, 16)
83#define VP_IMG_VSIZE(x) VP_MASK_VAL(x, 13, 0)
84
85/* VP_SRC_H_POSITION */
86#define VP_SRC_H_POSITION_VAL(x) VP_MASK_VAL(x, 14, 4)
87
88/* VP_ENDIAN_MODE */
89#define VP_ENDIAN_MODE_LITTLE (1 << 0)
90
91#endif /* SAMSUNG_REGS_VP_H */
diff --git a/include/drm/drm_fourcc.h b/include/drm/drm_fourcc.h
index 4f99cb41ed6e..bdf0152cbbe9 100644
--- a/include/drm/drm_fourcc.h
+++ b/include/drm/drm_fourcc.h
@@ -107,6 +107,10 @@
107#define DRM_FORMAT_NV16 fourcc_code('N', 'V', '1', '6') /* 2x1 subsampled Cr:Cb plane */ 107#define DRM_FORMAT_NV16 fourcc_code('N', 'V', '1', '6') /* 2x1 subsampled Cr:Cb plane */
108#define DRM_FORMAT_NV61 fourcc_code('N', 'V', '6', '1') /* 2x1 subsampled Cb:Cr plane */ 108#define DRM_FORMAT_NV61 fourcc_code('N', 'V', '6', '1') /* 2x1 subsampled Cb:Cr plane */
109 109
110/* 2 non contiguous plane YCbCr */
111#define DRM_FORMAT_NV12M fourcc_code('N', 'M', '1', '2') /* 2x2 subsampled Cr:Cb plane */
112#define DRM_FORMAT_NV12MT fourcc_code('T', 'M', '1', '2') /* 2x2 subsampled Cr:Cb plane 64x32 macroblocks */
113
110/* 114/*
111 * 3 plane YCbCr 115 * 3 plane YCbCr
112 * index 0: Y plane, [7:0] Y 116 * index 0: Y plane, [7:0] Y
@@ -127,4 +131,7 @@
127#define DRM_FORMAT_YUV444 fourcc_code('Y', 'U', '2', '4') /* non-subsampled Cb (1) and Cr (2) planes */ 131#define DRM_FORMAT_YUV444 fourcc_code('Y', 'U', '2', '4') /* non-subsampled Cb (1) and Cr (2) planes */
128#define DRM_FORMAT_YVU444 fourcc_code('Y', 'V', '2', '4') /* non-subsampled Cr (1) and Cb (2) planes */ 132#define DRM_FORMAT_YVU444 fourcc_code('Y', 'V', '2', '4') /* non-subsampled Cr (1) and Cb (2) planes */
129 133
134/* 3 non contiguous plane YCbCr */
135#define DRM_FORMAT_YUV420M fourcc_code('Y', 'M', '1', '2') /* 2x2 subsampled Cb (1) and Cr (2) planes */
136
130#endif /* DRM_FOURCC_H */ 137#endif /* DRM_FOURCC_H */
diff --git a/include/drm/exynos_drm.h b/include/drm/exynos_drm.h
index 7a2262a7689f..5e120f1c5cd9 100644
--- a/include/drm/exynos_drm.h
+++ b/include/drm/exynos_drm.h
@@ -112,4 +112,31 @@ struct exynos_drm_fimd_pdata {
112 unsigned int bpp; 112 unsigned int bpp;
113}; 113};
114 114
115/**
116 * Platform Specific Structure for DRM based HDMI.
117 *
118 * @hdmi_dev: device point to specific hdmi driver.
119 * @mixer_dev: device point to specific mixer driver.
120 *
121 * this structure is used for common hdmi driver and each device object
122 * would be used to access specific device driver(hdmi or mixer driver)
123 */
124struct exynos_drm_common_hdmi_pd {
125 struct device *hdmi_dev;
126 struct device *mixer_dev;
127};
128
129/**
130 * Platform Specific Structure for DRM based HDMI core.
131 *
132 * @timing: default video mode for initializing
133 * @default_win: default window layer number to be used for UI.
134 * @bpp: default bit per pixel.
135 */
136struct exynos_drm_hdmi_pdata {
137 struct fb_videomode timing;
138 unsigned int default_win;
139 unsigned int bpp;
140};
141
115#endif 142#endif