aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorInki Dae <inki.dae@samsung.com>2011-10-04 06:19:01 -0400
committerDave Airlie <airlied@redhat.com>2011-10-05 05:27:31 -0400
commit1c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3c (patch)
treedff45afe42d7f7bb5c2bece7a3a5830b49aaa60b
parent5383053627afab973ffe582a4db9646317bec726 (diff)
DRM: add DRM Driver for Samsung SoC EXYNOS4210.
This patch is a DRM Driver for Samsung SoC Exynos4210 and now enables only FIMD yet but we will add HDMI support also in the future. this patch is based on git repository below: git://people.freedesktop.org/~airlied/linux.git branch name: drm-next commit-id: 88ef4e3f4f616462b78a7838eb3ffc3818d30f67 you can refer to our working repository below: http://git.infradead.org/users/kmpark/linux-2.6-samsung branch name: samsung-drm We tried to re-use lowlevel codes of the FIMD driver(s3c-fb.c based on Linux framebuffer) but couldn't so because lowlevel codes of s3c-fb.c are included internally and so FIMD module of this driver has its own lowlevel codes. We used GEM framework for buffer management and DMA APIs(dma_alloc_*) for buffer allocation so we can allocate physically continuous memory for DMA through it and also we could use CMA later if CMA is applied to mainline. Refer to this link for CMA(Continuous Memory Allocator): http://lkml.org/lkml/2011/7/20/45 this driver supports only physically continuous memory(non-iommu). Links to previous versions of the patchset: v1: < https://lwn.net/Articles/454380/ > v2: < http://www.spinics.net/lists/kernel/msg1224275.html > v3: < http://www.spinics.net/lists/dri-devel/msg13755.html > v4: < http://permalink.gmane.org/gmane.comp.video.dri.devel/60439 > v5: < http://comments.gmane.org/gmane.comp.video.dri.devel/60802 > Changelog v2: DRM: add DRM_IOCTL_SAMSUNG_GEM_MMAP ioctl command. this feature maps user address space to physical memory region once user application requests DRM_IOCTL_SAMSUNG_GEM_MMAP ioctl. DRM: code clean and add exception codes. Changelog v3: DRM: Support multiple irq. FIMD and HDMI have their own irq handler but DRM Framework can regiter only one irq handler this patch supports mutiple irq for Samsung SoC. DRM: Consider modularization. each DRM, FIMD could be built as a module. DRM: Have indenpendent crtc object. crtc isn't specific to SoC Platform so this patch gets a crtc to be used as common object. created crtc could be attached to any encoder object. DRM: code clean and add exception codes. Changelog v4: DRM: remove is_defult from samsung_fb. is_default isn't used for default framebuffer. DRM: code refactoring to fimd module. this patch is be considered with multiple display objects and would use its own request_irq() to register a irq handler instead of drm framework's one. DRM: remove find_samsung_drm_gem_object() DRM: move kernel private data structures and definitions to driver folder. samsung_drm.h would contain only public information for userspace ioctl interface. DRM: code refactoring to gem modules. buffer module isn't dependent of gem module anymore. DRM: fixed security issue. DRM: remove encoder porinter from specific connector. samsung connector doesn't need to have generic encoder. DRM: code clean and add exception codes. Changelog v5: DRM: updated fimd(display controller) driver. added various pixel formats, color key and pixel blending features. DRM: removed end_buf_off from samsung_drm_overlay structure. this variable isn't used and end buffer address would be calculated by each sub driver. DRM: use generic function for mmap_offset. replaced samsung_drm_gem_create_mmap_offset() and samsung_drm_free_mmap_offset() with generic ones applied to mainline recentrly. DRM: removed unnecessary codes and added exception codes. DRM: added comments and code clean. Changelog v6: DRM: added default config options. DRM: added padding for 64-bit align. DRM: changed prefix 'samsung' to 'exynos' Signed-off-by: Inki Dae <inki.dae@samsung.com> Signed-off-by: Joonyoung Shim <jy0922.shim@samsung.com> Signed-off-by: Seung-Woo Kim <sw0312.kim@samsung.com> Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com> Reviewed-by: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com> Reviewed-by: Dave Airlie <airlied@redhat.com> Reviewed-by: Rob Clark <robdclark@gmail.com> Signed-off-by: Dave Airlie <airlied@redhat.com>
-rw-r--r--drivers/gpu/drm/Kconfig2
-rw-r--r--drivers/gpu/drm/Makefile1
-rw-r--r--drivers/gpu/drm/exynos/Kconfig20
-rw-r--r--drivers/gpu/drm/exynos/Makefile11
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_buf.c110
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_buf.h50
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_connector.c293
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_connector.h34
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_core.c272
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_crtc.c344
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_crtc.h39
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_drv.c230
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_drv.h242
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_encoder.c271
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_encoder.h45
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_fb.c271
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_fb.h47
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_fbdev.c441
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_fbdev.h37
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_fimd.c796
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_gem.c415
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_gem.h107
-rw-r--r--include/drm/exynos_drm.h104
23 files changed, 4182 insertions, 0 deletions
diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig
index b493663c7ba7..e405e61c27e2 100644
--- a/drivers/gpu/drm/Kconfig
+++ b/drivers/gpu/drm/Kconfig
@@ -158,3 +158,5 @@ config DRM_SAVAGE
158 help 158 help
159 Choose this option if you have a Savage3D/4/SuperSavage/Pro/Twister 159 Choose this option if you have a Savage3D/4/SuperSavage/Pro/Twister
160 chipset. If M is selected the module will be called savage. 160 chipset. If M is selected the module will be called savage.
161
162source "drivers/gpu/drm/exynos/Kconfig" \ No newline at end of file
diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile
index 89cf05a72d1c..c0496f660707 100644
--- a/drivers/gpu/drm/Makefile
+++ b/drivers/gpu/drm/Makefile
@@ -35,4 +35,5 @@ obj-$(CONFIG_DRM_SAVAGE)+= savage/
35obj-$(CONFIG_DRM_VMWGFX)+= vmwgfx/ 35obj-$(CONFIG_DRM_VMWGFX)+= vmwgfx/
36obj-$(CONFIG_DRM_VIA) +=via/ 36obj-$(CONFIG_DRM_VIA) +=via/
37obj-$(CONFIG_DRM_NOUVEAU) +=nouveau/ 37obj-$(CONFIG_DRM_NOUVEAU) +=nouveau/
38obj-$(CONFIG_DRM_EXYNOS) +=exynos/
38obj-y += i2c/ 39obj-y += i2c/
diff --git a/drivers/gpu/drm/exynos/Kconfig b/drivers/gpu/drm/exynos/Kconfig
new file mode 100644
index 000000000000..847466aab435
--- /dev/null
+++ b/drivers/gpu/drm/exynos/Kconfig
@@ -0,0 +1,20 @@
1config DRM_EXYNOS
2 tristate "DRM Support for Samsung SoC EXYNOS Series"
3 depends on DRM && PLAT_SAMSUNG
4 default n
5 select DRM_KMS_HELPER
6 select FB_CFB_FILLRECT
7 select FB_CFB_COPYAREA
8 select FB_CFB_IMAGEBLIT
9 select VT_HW_CONSOLE_BINDING if FRAMEBUFFER_CONSOLE
10 help
11 Choose this option if you have a Samsung SoC EXYNOS chipset.
12 If M is selected the module will be called exynosdrm.
13
14config DRM_EXYNOS_FIMD
15 tristate "Exynos DRM FIMD"
16 depends on DRM_EXYNOS
17 default n
18 help
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
diff --git a/drivers/gpu/drm/exynos/Makefile b/drivers/gpu/drm/exynos/Makefile
new file mode 100644
index 000000000000..0496d3ff2683
--- /dev/null
+++ b/drivers/gpu/drm/exynos/Makefile
@@ -0,0 +1,11 @@
1#
2# Makefile for the drm device driver. This driver provides support for the
3# Direct Rendering Infrastructure (DRI) in XFree86 4.1.0 and higher.
4
5ccflags-y := -Iinclude/drm -Idrivers/gpu/drm/exynos
6exynosdrm-y := exynos_drm_drv.o exynos_drm_encoder.o exynos_drm_connector.o \
7 exynos_drm_crtc.o exynos_drm_fbdev.o exynos_drm_fb.o \
8 exynos_drm_buf.o exynos_drm_gem.o exynos_drm_core.o
9
10obj-$(CONFIG_DRM_EXYNOS) += exynosdrm.o
11obj-$(CONFIG_DRM_EXYNOS_FIMD) += exynos_drm_fimd.o
diff --git a/drivers/gpu/drm/exynos/exynos_drm_buf.c b/drivers/gpu/drm/exynos/exynos_drm_buf.c
new file mode 100644
index 000000000000..6f8afea94fc9
--- /dev/null
+++ b/drivers/gpu/drm/exynos/exynos_drm_buf.c
@@ -0,0 +1,110 @@
1/* exynos_drm_buf.c
2 *
3 * Copyright (c) 2011 Samsung Electronics Co., Ltd.
4 * Author: 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#include "drmP.h"
27#include "drm.h"
28
29#include "exynos_drm_drv.h"
30#include "exynos_drm_buf.h"
31
32static DEFINE_MUTEX(exynos_drm_buf_lock);
33
34static int lowlevel_buffer_allocate(struct drm_device *dev,
35 struct exynos_drm_buf_entry *entry)
36{
37 DRM_DEBUG_KMS("%s\n", __FILE__);
38
39 entry->vaddr = dma_alloc_writecombine(dev->dev, entry->size,
40 (dma_addr_t *)&entry->paddr, GFP_KERNEL);
41 if (!entry->paddr) {
42 DRM_ERROR("failed to allocate buffer.\n");
43 return -ENOMEM;
44 }
45
46 DRM_DEBUG_KMS("allocated : vaddr(0x%x), paddr(0x%x), size(0x%x)\n",
47 (unsigned int)entry->vaddr, entry->paddr, entry->size);
48
49 return 0;
50}
51
52static void lowlevel_buffer_deallocate(struct drm_device *dev,
53 struct exynos_drm_buf_entry *entry)
54{
55 DRM_DEBUG_KMS("%s.\n", __FILE__);
56
57 if (entry->paddr && entry->vaddr && entry->size)
58 dma_free_writecombine(dev->dev, entry->size, entry->vaddr,
59 entry->paddr);
60 else
61 DRM_DEBUG_KMS("entry data is null.\n");
62}
63
64struct exynos_drm_buf_entry *exynos_drm_buf_create(struct drm_device *dev,
65 unsigned int size)
66{
67 struct exynos_drm_buf_entry *entry;
68
69 DRM_DEBUG_KMS("%s.\n", __FILE__);
70
71 entry = kzalloc(sizeof(*entry), GFP_KERNEL);
72 if (!entry) {
73 DRM_ERROR("failed to allocate exynos_drm_buf_entry.\n");
74 return ERR_PTR(-ENOMEM);
75 }
76
77 entry->size = size;
78
79 /*
80 * allocate memory region with size and set the memory information
81 * to vaddr and paddr of a entry object.
82 */
83 if (lowlevel_buffer_allocate(dev, entry) < 0) {
84 kfree(entry);
85 entry = NULL;
86 return ERR_PTR(-ENOMEM);
87 }
88
89 return entry;
90}
91
92void exynos_drm_buf_destroy(struct drm_device *dev,
93 struct exynos_drm_buf_entry *entry)
94{
95 DRM_DEBUG_KMS("%s.\n", __FILE__);
96
97 if (!entry) {
98 DRM_DEBUG_KMS("entry is null.\n");
99 return;
100 }
101
102 lowlevel_buffer_deallocate(dev, entry);
103
104 kfree(entry);
105 entry = NULL;
106}
107
108MODULE_AUTHOR("Inki Dae <inki.dae@samsung.com>");
109MODULE_DESCRIPTION("Samsung SoC DRM Buffer Management Module");
110MODULE_LICENSE("GPL");
diff --git a/drivers/gpu/drm/exynos/exynos_drm_buf.h b/drivers/gpu/drm/exynos/exynos_drm_buf.h
new file mode 100644
index 000000000000..9b1f0fb8d3a5
--- /dev/null
+++ b/drivers/gpu/drm/exynos/exynos_drm_buf.h
@@ -0,0 +1,50 @@
1/* exynos_drm_buf.h
2 *
3 * Copyright (c) 2011 Samsung Electronics Co., Ltd.
4 * Author: 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_BUF_H_
27#define _EXYNOS_DRM_BUF_H_
28
29/*
30 * exynos drm buffer entry structure.
31 *
32 * @paddr: physical address of allocated memory.
33 * @vaddr: kernel virtual address of allocated memory.
34 * @size: size of allocated memory.
35 */
36struct exynos_drm_buf_entry {
37 dma_addr_t paddr;
38 void __iomem *vaddr;
39 unsigned int size;
40};
41
42/* allocate physical memory. */
43struct exynos_drm_buf_entry *exynos_drm_buf_create(struct drm_device *dev,
44 unsigned int size);
45
46/* remove allocated physical memory. */
47void exynos_drm_buf_destroy(struct drm_device *dev,
48 struct exynos_drm_buf_entry *entry);
49
50#endif
diff --git a/drivers/gpu/drm/exynos/exynos_drm_connector.c b/drivers/gpu/drm/exynos/exynos_drm_connector.c
new file mode 100644
index 000000000000..985d9e768728
--- /dev/null
+++ b/drivers/gpu/drm/exynos/exynos_drm_connector.c
@@ -0,0 +1,293 @@
1/*
2 * Copyright (c) 2011 Samsung Electronics Co., Ltd.
3 * Authors:
4 * Inki Dae <inki.dae@samsung.com>
5 * Joonyoung Shim <jy0922.shim@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#include "drmP.h"
29#include "drm_crtc_helper.h"
30
31#include "exynos_drm_drv.h"
32#include "exynos_drm_encoder.h"
33
34#define MAX_EDID 256
35#define to_exynos_connector(x) container_of(x, struct exynos_drm_connector,\
36 drm_connector)
37
38struct exynos_drm_connector {
39 struct drm_connector drm_connector;
40};
41
42/* convert exynos_video_timings to drm_display_mode */
43static inline void
44convert_to_display_mode(struct drm_display_mode *mode,
45 struct fb_videomode *timing)
46{
47 DRM_DEBUG_KMS("%s\n", __FILE__);
48
49 mode->clock = timing->pixclock / 1000;
50
51 mode->hdisplay = timing->xres;
52 mode->hsync_start = mode->hdisplay + timing->left_margin;
53 mode->hsync_end = mode->hsync_start + timing->hsync_len;
54 mode->htotal = mode->hsync_end + timing->right_margin;
55
56 mode->vdisplay = timing->yres;
57 mode->vsync_start = mode->vdisplay + timing->upper_margin;
58 mode->vsync_end = mode->vsync_start + timing->vsync_len;
59 mode->vtotal = mode->vsync_end + timing->lower_margin;
60}
61
62/* convert drm_display_mode to exynos_video_timings */
63static inline void
64convert_to_video_timing(struct fb_videomode *timing,
65 struct drm_display_mode *mode)
66{
67 DRM_DEBUG_KMS("%s\n", __FILE__);
68
69 memset(timing, 0, sizeof(*timing));
70
71 timing->pixclock = mode->clock * 1000;
72 timing->refresh = mode->vrefresh;
73
74 timing->xres = mode->hdisplay;
75 timing->left_margin = mode->hsync_start - mode->hdisplay;
76 timing->hsync_len = mode->hsync_end - mode->hsync_start;
77 timing->right_margin = mode->htotal - mode->hsync_end;
78
79 timing->yres = mode->vdisplay;
80 timing->upper_margin = mode->vsync_start - mode->vdisplay;
81 timing->vsync_len = mode->vsync_end - mode->vsync_start;
82 timing->lower_margin = mode->vtotal - mode->vsync_end;
83
84 if (mode->flags & DRM_MODE_FLAG_INTERLACE)
85 timing->vmode = FB_VMODE_INTERLACED;
86 else
87 timing->vmode = FB_VMODE_NONINTERLACED;
88
89 if (mode->flags & DRM_MODE_FLAG_DBLSCAN)
90 timing->vmode |= FB_VMODE_DOUBLE;
91}
92
93static int exynos_drm_connector_get_modes(struct drm_connector *connector)
94{
95 struct exynos_drm_manager *manager =
96 exynos_drm_get_manager(connector->encoder);
97 struct exynos_drm_display *display = manager->display;
98 unsigned int count;
99
100 DRM_DEBUG_KMS("%s\n", __FILE__);
101
102 if (!display) {
103 DRM_DEBUG_KMS("display is null.\n");
104 return 0;
105 }
106
107 /*
108 * if get_edid() exists then get_edid() callback of hdmi side
109 * is called to get edid data through i2c interface else
110 * get timing from the FIMD driver(display controller).
111 *
112 * P.S. in case of lcd panel, count is always 1 if success
113 * because lcd panel has only one mode.
114 */
115 if (display->get_edid) {
116 int ret;
117 void *edid;
118
119 edid = kzalloc(MAX_EDID, GFP_KERNEL);
120 if (!edid) {
121 DRM_ERROR("failed to allocate edid\n");
122 return 0;
123 }
124
125 ret = display->get_edid(manager->dev, connector,
126 edid, MAX_EDID);
127 if (ret < 0) {
128 DRM_ERROR("failed to get edid data.\n");
129 kfree(edid);
130 edid = NULL;
131 return 0;
132 }
133
134 drm_mode_connector_update_edid_property(connector, edid);
135 count = drm_add_edid_modes(connector, edid);
136
137 kfree(connector->display_info.raw_edid);
138 connector->display_info.raw_edid = edid;
139 } else {
140 struct drm_display_mode *mode = drm_mode_create(connector->dev);
141 struct fb_videomode *timing;
142
143 if (display->get_timing)
144 timing = display->get_timing(manager->dev);
145 else {
146 drm_mode_destroy(connector->dev, mode);
147 return 0;
148 }
149
150 convert_to_display_mode(mode, timing);
151
152 mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;
153 drm_mode_set_name(mode);
154 drm_mode_probed_add(connector, mode);
155
156 count = 1;
157 }
158
159 return count;
160}
161
162static int exynos_drm_connector_mode_valid(struct drm_connector *connector,
163 struct drm_display_mode *mode)
164{
165 struct exynos_drm_manager *manager =
166 exynos_drm_get_manager(connector->encoder);
167 struct exynos_drm_display *display = manager->display;
168 struct fb_videomode timing;
169 int ret = MODE_BAD;
170
171 DRM_DEBUG_KMS("%s\n", __FILE__);
172
173 convert_to_video_timing(&timing, mode);
174
175 if (display && display->check_timing)
176 if (!display->check_timing(manager->dev, (void *)&timing))
177 ret = MODE_OK;
178
179 return ret;
180}
181
182struct drm_encoder *exynos_drm_best_encoder(struct drm_connector *connector)
183{
184 DRM_DEBUG_KMS("%s\n", __FILE__);
185
186 return connector->encoder;
187}
188
189static struct drm_connector_helper_funcs exynos_connector_helper_funcs = {
190 .get_modes = exynos_drm_connector_get_modes,
191 .mode_valid = exynos_drm_connector_mode_valid,
192 .best_encoder = exynos_drm_best_encoder,
193};
194
195/* get detection status of display device. */
196static enum drm_connector_status
197exynos_drm_connector_detect(struct drm_connector *connector, bool force)
198{
199 struct exynos_drm_manager *manager =
200 exynos_drm_get_manager(connector->encoder);
201 struct exynos_drm_display *display = manager->display;
202 enum drm_connector_status status = connector_status_disconnected;
203
204 DRM_DEBUG_KMS("%s\n", __FILE__);
205
206 if (display && display->is_connected) {
207 if (display->is_connected(manager->dev))
208 status = connector_status_connected;
209 else
210 status = connector_status_disconnected;
211 }
212
213 return status;
214}
215
216static void exynos_drm_connector_destroy(struct drm_connector *connector)
217{
218 struct exynos_drm_connector *exynos_connector =
219 to_exynos_connector(connector);
220
221 DRM_DEBUG_KMS("%s\n", __FILE__);
222
223 drm_sysfs_connector_remove(connector);
224 drm_connector_cleanup(connector);
225 kfree(exynos_connector);
226}
227
228static struct drm_connector_funcs exynos_connector_funcs = {
229 .dpms = drm_helper_connector_dpms,
230 .fill_modes = drm_helper_probe_single_connector_modes,
231 .detect = exynos_drm_connector_detect,
232 .destroy = exynos_drm_connector_destroy,
233};
234
235struct drm_connector *exynos_drm_connector_create(struct drm_device *dev,
236 struct drm_encoder *encoder)
237{
238 struct exynos_drm_connector *exynos_connector;
239 struct exynos_drm_manager *manager = exynos_drm_get_manager(encoder);
240 struct drm_connector *connector;
241 int type;
242 int err;
243
244 DRM_DEBUG_KMS("%s\n", __FILE__);
245
246 exynos_connector = kzalloc(sizeof(*exynos_connector), GFP_KERNEL);
247 if (!exynos_connector) {
248 DRM_ERROR("failed to allocate connector\n");
249 return NULL;
250 }
251
252 connector = &exynos_connector->drm_connector;
253
254 switch (manager->display->type) {
255 case EXYNOS_DISPLAY_TYPE_HDMI:
256 type = DRM_MODE_CONNECTOR_HDMIA;
257 break;
258 default:
259 type = DRM_MODE_CONNECTOR_Unknown;
260 break;
261 }
262
263 drm_connector_init(dev, connector, &exynos_connector_funcs, type);
264 drm_connector_helper_add(connector, &exynos_connector_helper_funcs);
265
266 err = drm_sysfs_connector_add(connector);
267 if (err)
268 goto err_connector;
269
270 connector->encoder = encoder;
271 err = drm_mode_connector_attach_encoder(connector, encoder);
272 if (err) {
273 DRM_ERROR("failed to attach a connector to a encoder\n");
274 goto err_sysfs;
275 }
276
277 DRM_DEBUG_KMS("connector has been created\n");
278
279 return connector;
280
281err_sysfs:
282 drm_sysfs_connector_remove(connector);
283err_connector:
284 drm_connector_cleanup(connector);
285 kfree(exynos_connector);
286 return NULL;
287}
288
289MODULE_AUTHOR("Inki Dae <inki.dae@samsung.com>");
290MODULE_AUTHOR("Joonyoung Shim <jy0922.shim@samsung.com>");
291MODULE_AUTHOR("Seung-Woo Kim <sw0312.kim@samsung.com>");
292MODULE_DESCRIPTION("Samsung SoC DRM Connector Driver");
293MODULE_LICENSE("GPL");
diff --git a/drivers/gpu/drm/exynos/exynos_drm_connector.h b/drivers/gpu/drm/exynos/exynos_drm_connector.h
new file mode 100644
index 000000000000..1c7b2b5b579c
--- /dev/null
+++ b/drivers/gpu/drm/exynos/exynos_drm_connector.h
@@ -0,0 +1,34 @@
1/*
2 * Copyright (c) 2011 Samsung Electronics Co., Ltd.
3 * Authors:
4 * Inki Dae <inki.dae@samsung.com>
5 * Joonyoung Shim <jy0922.shim@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_DRM_CONNECTOR_H_
29#define _EXYNOS_DRM_CONNECTOR_H_
30
31struct drm_connector *exynos_drm_connector_create(struct drm_device *dev,
32 struct drm_encoder *encoder);
33
34#endif
diff --git a/drivers/gpu/drm/exynos/exynos_drm_core.c b/drivers/gpu/drm/exynos/exynos_drm_core.c
new file mode 100644
index 000000000000..edb0ee13cffc
--- /dev/null
+++ b/drivers/gpu/drm/exynos/exynos_drm_core.c
@@ -0,0 +1,272 @@
1/* exynos_drm_core.c
2 *
3 * Copyright (c) 2011 Samsung Electronics Co., Ltd.
4 * Author:
5 * Inki Dae <inki.dae@samsung.com>
6 * Joonyoung Shim <jy0922.shim@samsung.com>
7 * Seung-Woo Kim <sw0312.kim@samsung.com>
8 *
9 * Permission is hereby granted, free of charge, to any person obtaining a
10 * copy of this software and associated documentation files (the "Software"),
11 * to deal in the Software without restriction, including without limitation
12 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
13 * and/or sell copies of the Software, and to permit persons to whom the
14 * Software is furnished to do so, subject to the following conditions:
15 *
16 * The above copyright notice and this permission notice (including the next
17 * paragraph) shall be included in all copies or substantial portions of the
18 * Software.
19 *
20 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
23 * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
24 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
25 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
26 * OTHER DEALINGS IN THE SOFTWARE.
27 */
28
29#include "drmP.h"
30#include "exynos_drm_drv.h"
31#include "exynos_drm_encoder.h"
32#include "exynos_drm_connector.h"
33#include "exynos_drm_fbdev.h"
34
35static DEFINE_MUTEX(exynos_drm_mutex);
36static LIST_HEAD(exynos_drm_subdrv_list);
37static struct drm_device *drm_dev;
38
39static int exynos_drm_subdrv_probe(struct drm_device *dev,
40 struct exynos_drm_subdrv *subdrv)
41{
42 struct drm_encoder *encoder;
43 struct drm_connector *connector;
44
45 DRM_DEBUG_DRIVER("%s\n", __FILE__);
46
47 if (subdrv->probe) {
48 int ret;
49
50 /*
51 * this probe callback would be called by sub driver
52 * after setting of all resources to this sub driver,
53 * such as clock, irq and register map are done or by load()
54 * of exynos drm driver.
55 *
56 * P.S. note that this driver is considered for modularization.
57 */
58 ret = subdrv->probe(dev);
59 if (ret)
60 return ret;
61 }
62
63 /* create and initialize a encoder for this sub driver. */
64 encoder = exynos_drm_encoder_create(dev, &subdrv->manager,
65 (1 << MAX_CRTC) - 1);
66 if (!encoder) {
67 DRM_ERROR("failed to create encoder\n");
68 return -EFAULT;
69 }
70
71 /*
72 * create and initialize a connector for this sub driver and
73 * attach the encoder created above to the connector.
74 */
75 connector = exynos_drm_connector_create(dev, encoder);
76 if (!connector) {
77 DRM_ERROR("failed to create connector\n");
78 encoder->funcs->destroy(encoder);
79 return -EFAULT;
80 }
81
82 subdrv->encoder = encoder;
83 subdrv->connector = connector;
84
85 return 0;
86}
87
88static void exynos_drm_subdrv_remove(struct drm_device *dev,
89 struct exynos_drm_subdrv *subdrv)
90{
91 DRM_DEBUG_DRIVER("%s\n", __FILE__);
92
93 if (subdrv->remove)
94 subdrv->remove(dev);
95
96 if (subdrv->encoder) {
97 struct drm_encoder *encoder = subdrv->encoder;
98 encoder->funcs->destroy(encoder);
99 subdrv->encoder = NULL;
100 }
101
102 if (subdrv->connector) {
103 struct drm_connector *connector = subdrv->connector;
104 connector->funcs->destroy(connector);
105 subdrv->connector = NULL;
106 }
107}
108
109int exynos_drm_device_register(struct drm_device *dev)
110{
111 struct exynos_drm_subdrv *subdrv, *n;
112 int err;
113
114 DRM_DEBUG_DRIVER("%s\n", __FILE__);
115
116 if (!dev)
117 return -EINVAL;
118
119 if (drm_dev) {
120 DRM_ERROR("Already drm device were registered\n");
121 return -EBUSY;
122 }
123
124 mutex_lock(&exynos_drm_mutex);
125 list_for_each_entry_safe(subdrv, n, &exynos_drm_subdrv_list, list) {
126 err = exynos_drm_subdrv_probe(dev, subdrv);
127 if (err) {
128 DRM_DEBUG("exynos drm subdrv probe failed.\n");
129 list_del(&subdrv->list);
130 }
131 }
132
133 drm_dev = dev;
134 mutex_unlock(&exynos_drm_mutex);
135
136 return 0;
137}
138EXPORT_SYMBOL_GPL(exynos_drm_device_register);
139
140int exynos_drm_device_unregister(struct drm_device *dev)
141{
142 struct exynos_drm_subdrv *subdrv;
143
144 DRM_DEBUG_DRIVER("%s\n", __FILE__);
145
146 if (!dev || dev != drm_dev) {
147 WARN(1, "Unexpected drm device unregister!\n");
148 return -EINVAL;
149 }
150
151 mutex_lock(&exynos_drm_mutex);
152 list_for_each_entry(subdrv, &exynos_drm_subdrv_list, list)
153 exynos_drm_subdrv_remove(dev, subdrv);
154
155 drm_dev = NULL;
156 mutex_unlock(&exynos_drm_mutex);
157
158 return 0;
159}
160EXPORT_SYMBOL_GPL(exynos_drm_device_unregister);
161
162static int exynos_drm_mode_group_reinit(struct drm_device *dev)
163{
164 struct drm_mode_group *group = &dev->primary->mode_group;
165 uint32_t *id_list = group->id_list;
166 int ret;
167
168 DRM_DEBUG_DRIVER("%s\n", __FILE__);
169
170 ret = drm_mode_group_init_legacy_group(dev, group);
171 if (ret < 0)
172 return ret;
173
174 kfree(id_list);
175 return 0;
176}
177
178int exynos_drm_subdrv_register(struct exynos_drm_subdrv *subdrv)
179{
180 int err;
181
182 DRM_DEBUG_DRIVER("%s\n", __FILE__);
183
184 if (!subdrv)
185 return -EINVAL;
186
187 mutex_lock(&exynos_drm_mutex);
188 if (drm_dev) {
189 err = exynos_drm_subdrv_probe(drm_dev, subdrv);
190 if (err) {
191 DRM_ERROR("failed to probe exynos drm subdrv\n");
192 mutex_unlock(&exynos_drm_mutex);
193 return err;
194 }
195
196 /*
197 * if any specific driver such as fimd or hdmi driver called
198 * exynos_drm_subdrv_register() later than drm_load(),
199 * the fb helper should be re-initialized and re-configured.
200 */
201 err = exynos_drm_fbdev_reinit(drm_dev);
202 if (err) {
203 DRM_ERROR("failed to reinitialize exynos drm fbdev\n");
204 exynos_drm_subdrv_remove(drm_dev, subdrv);
205 mutex_unlock(&exynos_drm_mutex);
206 return err;
207 }
208
209 err = exynos_drm_mode_group_reinit(drm_dev);
210 if (err) {
211 DRM_ERROR("failed to reinitialize mode group\n");
212 exynos_drm_fbdev_fini(drm_dev);
213 exynos_drm_subdrv_remove(drm_dev, subdrv);
214 mutex_unlock(&exynos_drm_mutex);
215 return err;
216 }
217 }
218
219 subdrv->drm_dev = drm_dev;
220
221 list_add_tail(&subdrv->list, &exynos_drm_subdrv_list);
222 mutex_unlock(&exynos_drm_mutex);
223
224 return 0;
225}
226EXPORT_SYMBOL_GPL(exynos_drm_subdrv_register);
227
228int exynos_drm_subdrv_unregister(struct exynos_drm_subdrv *subdrv)
229{
230 int ret = -EFAULT;
231
232 DRM_DEBUG_DRIVER("%s\n", __FILE__);
233
234 if (!subdrv) {
235 DRM_DEBUG("Unexpected exynos drm subdrv unregister!\n");
236 return ret;
237 }
238
239 mutex_lock(&exynos_drm_mutex);
240 if (drm_dev) {
241 exynos_drm_subdrv_remove(drm_dev, subdrv);
242 list_del(&subdrv->list);
243
244 /*
245 * fb helper should be updated once a sub driver is released
246 * to re-configure crtc and connector and also to re-setup
247 * drm framebuffer.
248 */
249 ret = exynos_drm_fbdev_reinit(drm_dev);
250 if (ret < 0) {
251 DRM_ERROR("failed fb helper reinit.\n");
252 goto fail;
253 }
254
255 ret = exynos_drm_mode_group_reinit(drm_dev);
256 if (ret < 0) {
257 DRM_ERROR("failed drm mode group reinit.\n");
258 goto fail;
259 }
260 }
261
262fail:
263 mutex_unlock(&exynos_drm_mutex);
264 return ret;
265}
266EXPORT_SYMBOL_GPL(exynos_drm_subdrv_unregister);
267
268MODULE_AUTHOR("Inki Dae <inki.dae@samsung.com>");
269MODULE_AUTHOR("Joonyoung Shim <jy0922.shim@samsung.com>");
270MODULE_AUTHOR("Seung-Woo Kim <sw0312.kim@samsung.com>");
271MODULE_DESCRIPTION("Samsung SoC DRM Core Driver");
272MODULE_LICENSE("GPL");
diff --git a/drivers/gpu/drm/exynos/exynos_drm_crtc.c b/drivers/gpu/drm/exynos/exynos_drm_crtc.c
new file mode 100644
index 000000000000..683ceb0f5277
--- /dev/null
+++ b/drivers/gpu/drm/exynos/exynos_drm_crtc.c
@@ -0,0 +1,344 @@
1/* exynos_drm_crtc.c
2 *
3 * Copyright (c) 2011 Samsung Electronics Co., Ltd.
4 * Authors:
5 * Inki Dae <inki.dae@samsung.com>
6 * Joonyoung Shim <jy0922.shim@samsung.com>
7 * Seung-Woo Kim <sw0312.kim@samsung.com>
8 *
9 * Permission is hereby granted, free of charge, to any person obtaining a
10 * copy of this software and associated documentation files (the "Software"),
11 * to deal in the Software without restriction, including without limitation
12 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
13 * and/or sell copies of the Software, and to permit persons to whom the
14 * Software is furnished to do so, subject to the following conditions:
15 *
16 * The above copyright notice and this permission notice (including the next
17 * paragraph) shall be included in all copies or substantial portions of the
18 * Software.
19 *
20 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
23 * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
24 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
25 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
26 * OTHER DEALINGS IN THE SOFTWARE.
27 */
28
29#include "drmP.h"
30#include "drm_crtc_helper.h"
31
32#include "exynos_drm_drv.h"
33#include "exynos_drm_fb.h"
34#include "exynos_drm_encoder.h"
35
36#define to_exynos_crtc(x) container_of(x, struct exynos_drm_crtc,\
37 drm_crtc)
38
39/*
40 * @fb_x: horizontal position from framebuffer base
41 * @fb_y: vertical position from framebuffer base
42 * @base_x: horizontal position from screen base
43 * @base_y: vertical position from screen base
44 * @crtc_w: width of crtc
45 * @crtc_h: height of crtc
46 */
47struct exynos_drm_crtc_pos {
48 unsigned int fb_x;
49 unsigned int fb_y;
50 unsigned int base_x;
51 unsigned int base_y;
52 unsigned int crtc_w;
53 unsigned int crtc_h;
54};
55
56/*
57 * Exynos specific crtc structure.
58 *
59 * @drm_crtc: crtc object.
60 * @overlay: contain information common to display controller and hdmi and
61 * contents of this overlay object would be copied to sub driver size.
62 * @pipe: a crtc index created at load() with a new crtc object creation
63 * and the crtc object would be set to private->crtc array
64 * to get a crtc object corresponding to this pipe from private->crtc
65 * array when irq interrupt occured. the reason of using this pipe is that
66 * drm framework doesn't support multiple irq yet.
67 * we can refer to the crtc to current hardware interrupt occured through
68 * this pipe value.
69 */
70struct exynos_drm_crtc {
71 struct drm_crtc drm_crtc;
72 struct exynos_drm_overlay overlay;
73 unsigned int pipe;
74};
75
76void exynos_drm_crtc_apply(struct drm_crtc *crtc)
77{
78 struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc);
79 struct exynos_drm_overlay *overlay = &exynos_crtc->overlay;
80
81 exynos_drm_fn_encoder(crtc, overlay,
82 exynos_drm_encoder_crtc_mode_set);
83 exynos_drm_fn_encoder(crtc, NULL, exynos_drm_encoder_crtc_commit);
84}
85
86static void exynos_drm_overlay_update(struct exynos_drm_overlay *overlay,
87 struct drm_framebuffer *fb,
88 struct drm_display_mode *mode,
89 struct exynos_drm_crtc_pos *pos)
90{
91 struct exynos_drm_buffer_info buffer_info;
92 unsigned int actual_w = pos->crtc_w;
93 unsigned int actual_h = pos->crtc_h;
94 unsigned int hw_w;
95 unsigned int hw_h;
96
97 /* update buffer address of framebuffer. */
98 exynos_drm_fb_update_buf_off(fb, pos->fb_x, pos->fb_y, &buffer_info);
99 overlay->paddr = buffer_info.paddr;
100 overlay->vaddr = buffer_info.vaddr;
101
102 hw_w = mode->hdisplay - pos->base_x;
103 hw_h = mode->vdisplay - pos->base_y;
104
105 if (actual_w > hw_w)
106 actual_w = hw_w;
107 if (actual_h > hw_h)
108 actual_h = hw_h;
109
110 overlay->offset_x = pos->base_x;
111 overlay->offset_y = pos->base_y;
112 overlay->width = actual_w;
113 overlay->height = actual_h;
114 overlay->bpp = fb->bits_per_pixel;
115
116 DRM_DEBUG_KMS("overlay : offset_x/y(%d,%d), width/height(%d,%d)",
117 overlay->offset_x, overlay->offset_y,
118 overlay->width, overlay->height);
119
120 overlay->buf_offsize = fb->width - actual_w;
121 overlay->line_size = actual_w;
122}
123
124static int exynos_drm_crtc_update(struct drm_crtc *crtc)
125{
126 struct exynos_drm_crtc *exynos_crtc;
127 struct exynos_drm_overlay *overlay;
128 struct exynos_drm_crtc_pos pos;
129 struct drm_display_mode *mode = &crtc->mode;
130 struct drm_framebuffer *fb = crtc->fb;
131
132 if (!mode || !fb)
133 return -EINVAL;
134
135 exynos_crtc = to_exynos_crtc(crtc);
136 overlay = &exynos_crtc->overlay;
137
138 memset(&pos, 0, sizeof(struct exynos_drm_crtc_pos));
139 pos.fb_x = crtc->x;
140 pos.fb_y = crtc->y;
141 pos.crtc_w = fb->width - crtc->x;
142 pos.crtc_h = fb->height - crtc->y;
143
144 exynos_drm_overlay_update(overlay, crtc->fb, mode, &pos);
145
146 return 0;
147}
148
149static void exynos_drm_crtc_dpms(struct drm_crtc *crtc, int mode)
150{
151 DRM_DEBUG_KMS("%s\n", __FILE__);
152
153 /* TODO */
154}
155
156static void exynos_drm_crtc_prepare(struct drm_crtc *crtc)
157{
158 DRM_DEBUG_KMS("%s\n", __FILE__);
159
160 /* drm framework doesn't check NULL. */
161}
162
163static void exynos_drm_crtc_commit(struct drm_crtc *crtc)
164{
165 DRM_DEBUG_KMS("%s\n", __FILE__);
166
167 /* drm framework doesn't check NULL. */
168}
169
170static bool
171exynos_drm_crtc_mode_fixup(struct drm_crtc *crtc,
172 struct drm_display_mode *mode,
173 struct drm_display_mode *adjusted_mode)
174{
175 DRM_DEBUG_KMS("%s\n", __FILE__);
176
177 /* drm framework doesn't check NULL */
178 return true;
179}
180
181static int
182exynos_drm_crtc_mode_set(struct drm_crtc *crtc, struct drm_display_mode *mode,
183 struct drm_display_mode *adjusted_mode, int x, int y,
184 struct drm_framebuffer *old_fb)
185{
186 DRM_DEBUG_KMS("%s\n", __FILE__);
187
188 mode = adjusted_mode;
189
190 return exynos_drm_crtc_update(crtc);
191}
192
193static int exynos_drm_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y,
194 struct drm_framebuffer *old_fb)
195{
196 int ret;
197
198 DRM_DEBUG_KMS("%s\n", __FILE__);
199
200 ret = exynos_drm_crtc_update(crtc);
201 if (ret)
202 return ret;
203
204 exynos_drm_crtc_apply(crtc);
205
206 return ret;
207}
208
209static void exynos_drm_crtc_load_lut(struct drm_crtc *crtc)
210{
211 DRM_DEBUG_KMS("%s\n", __FILE__);
212 /* drm framework doesn't check NULL */
213}
214
215static struct drm_crtc_helper_funcs exynos_crtc_helper_funcs = {
216 .dpms = exynos_drm_crtc_dpms,
217 .prepare = exynos_drm_crtc_prepare,
218 .commit = exynos_drm_crtc_commit,
219 .mode_fixup = exynos_drm_crtc_mode_fixup,
220 .mode_set = exynos_drm_crtc_mode_set,
221 .mode_set_base = exynos_drm_crtc_mode_set_base,
222 .load_lut = exynos_drm_crtc_load_lut,
223};
224
225static int exynos_drm_crtc_page_flip(struct drm_crtc *crtc,
226 struct drm_framebuffer *fb,
227 struct drm_pending_vblank_event *event)
228{
229 struct drm_device *dev = crtc->dev;
230 struct exynos_drm_private *dev_priv = dev->dev_private;
231 struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc);
232 struct drm_framebuffer *old_fb = crtc->fb;
233 int ret = -EINVAL;
234
235 DRM_DEBUG_KMS("%s\n", __FILE__);
236
237 mutex_lock(&dev->struct_mutex);
238
239 if (event && !dev_priv->pageflip_event) {
240 list_add_tail(&event->base.link,
241 &dev_priv->pageflip_event_list);
242
243 ret = drm_vblank_get(dev, exynos_crtc->pipe);
244 if (ret) {
245 DRM_DEBUG("failed to acquire vblank counter\n");
246 goto out;
247 }
248
249 crtc->fb = fb;
250 ret = exynos_drm_crtc_update(crtc);
251 if (ret) {
252 crtc->fb = old_fb;
253 drm_vblank_put(dev, exynos_crtc->pipe);
254 dev_priv->pageflip_event = false;
255
256 goto out;
257 }
258
259 dev_priv->pageflip_event = true;
260 }
261out:
262 mutex_unlock(&dev->struct_mutex);
263 return ret;
264}
265
266static void exynos_drm_crtc_destroy(struct drm_crtc *crtc)
267{
268 struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc);
269 struct exynos_drm_private *private = crtc->dev->dev_private;
270
271 DRM_DEBUG_KMS("%s\n", __FILE__);
272
273 private->crtc[exynos_crtc->pipe] = NULL;
274
275 drm_crtc_cleanup(crtc);
276 kfree(exynos_crtc);
277}
278
279static struct drm_crtc_funcs exynos_crtc_funcs = {
280 .set_config = drm_crtc_helper_set_config,
281 .page_flip = exynos_drm_crtc_page_flip,
282 .destroy = exynos_drm_crtc_destroy,
283};
284
285struct exynos_drm_overlay *get_exynos_drm_overlay(struct drm_device *dev,
286 struct drm_crtc *crtc)
287{
288 struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc);
289
290 return &exynos_crtc->overlay;
291}
292
293int exynos_drm_crtc_create(struct drm_device *dev, unsigned int nr)
294{
295 struct exynos_drm_crtc *exynos_crtc;
296 struct exynos_drm_private *private = dev->dev_private;
297 struct drm_crtc *crtc;
298
299 DRM_DEBUG_KMS("%s\n", __FILE__);
300
301 exynos_crtc = kzalloc(sizeof(*exynos_crtc), GFP_KERNEL);
302 if (!exynos_crtc) {
303 DRM_ERROR("failed to allocate exynos crtc\n");
304 return -ENOMEM;
305 }
306
307 exynos_crtc->pipe = nr;
308 crtc = &exynos_crtc->drm_crtc;
309
310 private->crtc[nr] = crtc;
311
312 drm_crtc_init(dev, crtc, &exynos_crtc_funcs);
313 drm_crtc_helper_add(crtc, &exynos_crtc_helper_funcs);
314
315 return 0;
316}
317
318int exynos_drm_crtc_enable_vblank(struct drm_device *dev, int crtc)
319{
320 struct exynos_drm_private *private = dev->dev_private;
321
322 DRM_DEBUG_KMS("%s\n", __FILE__);
323
324 exynos_drm_fn_encoder(private->crtc[crtc], &crtc,
325 exynos_drm_enable_vblank);
326
327 return 0;
328}
329
330void exynos_drm_crtc_disable_vblank(struct drm_device *dev, int crtc)
331{
332 struct exynos_drm_private *private = dev->dev_private;
333
334 DRM_DEBUG_KMS("%s\n", __FILE__);
335
336 exynos_drm_fn_encoder(private->crtc[crtc], &crtc,
337 exynos_drm_disable_vblank);
338}
339
340MODULE_AUTHOR("Inki Dae <inki.dae@samsung.com>");
341MODULE_AUTHOR("Joonyoung Shim <jy0922.shim@samsung.com>");
342MODULE_AUTHOR("Seung-Woo Kim <sw0312.kim@samsung.com>");
343MODULE_DESCRIPTION("Samsung SoC DRM CRTC Driver");
344MODULE_LICENSE("GPL");
diff --git a/drivers/gpu/drm/exynos/exynos_drm_crtc.h b/drivers/gpu/drm/exynos/exynos_drm_crtc.h
new file mode 100644
index 000000000000..452b62b23853
--- /dev/null
+++ b/drivers/gpu/drm/exynos/exynos_drm_crtc.h
@@ -0,0 +1,39 @@
1/* exynos_drm_crtc.h
2 *
3 * Copyright (c) 2011 Samsung Electronics Co., Ltd.
4 * Authors:
5 * Inki Dae <inki.dae@samsung.com>
6 * Joonyoung Shim <jy0922.shim@samsung.com>
7 * Seung-Woo Kim <sw0312.kim@samsung.com>
8 *
9 * Permission is hereby granted, free of charge, to any person obtaining a
10 * copy of this software and associated documentation files (the "Software"),
11 * to deal in the Software without restriction, including without limitation
12 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
13 * and/or sell copies of the Software, and to permit persons to whom the
14 * Software is furnished to do so, subject to the following conditions:
15 *
16 * The above copyright notice and this permission notice (including the next
17 * paragraph) shall be included in all copies or substantial portions of the
18 * Software.
19 *
20 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
23 * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
24 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
25 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
26 * OTHER DEALINGS IN THE SOFTWARE.
27 */
28
29#ifndef _EXYNOS_DRM_CRTC_H_
30#define _EXYNOS_DRM_CRTC_H_
31
32struct exynos_drm_overlay *get_exynos_drm_overlay(struct drm_device *dev,
33 struct drm_crtc *crtc);
34void exynos_drm_crtc_apply(struct drm_crtc *crtc);
35int exynos_drm_crtc_create(struct drm_device *dev, unsigned int nr);
36int exynos_drm_crtc_enable_vblank(struct drm_device *dev, int crtc);
37void exynos_drm_crtc_disable_vblank(struct drm_device *dev, int crtc);
38
39#endif
diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.c b/drivers/gpu/drm/exynos/exynos_drm_drv.c
new file mode 100644
index 000000000000..a190348ed9bd
--- /dev/null
+++ b/drivers/gpu/drm/exynos/exynos_drm_drv.c
@@ -0,0 +1,230 @@
1/*
2 * Copyright (c) 2011 Samsung Electronics Co., Ltd.
3 * Authors:
4 * Inki Dae <inki.dae@samsung.com>
5 * Joonyoung Shim <jy0922.shim@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#include "drmP.h"
29#include "drm.h"
30
31#include <drm/exynos_drm.h>
32
33#include "exynos_drm_drv.h"
34#include "exynos_drm_crtc.h"
35#include "exynos_drm_fbdev.h"
36#include "exynos_drm_fb.h"
37#include "exynos_drm_gem.h"
38
39#define DRIVER_NAME "exynos-drm"
40#define DRIVER_DESC "Samsung SoC DRM"
41#define DRIVER_DATE "20110530"
42#define DRIVER_MAJOR 1
43#define DRIVER_MINOR 0
44
45static int exynos_drm_load(struct drm_device *dev, unsigned long flags)
46{
47 struct exynos_drm_private *private;
48 int ret;
49 int nr;
50
51 DRM_DEBUG_DRIVER("%s\n", __FILE__);
52
53 private = kzalloc(sizeof(struct exynos_drm_private), GFP_KERNEL);
54 if (!private) {
55 DRM_ERROR("failed to allocate private\n");
56 return -ENOMEM;
57 }
58
59 INIT_LIST_HEAD(&private->pageflip_event_list);
60 dev->dev_private = (void *)private;
61
62 drm_mode_config_init(dev);
63
64 exynos_drm_mode_config_init(dev);
65
66 /*
67 * EXYNOS4 is enough to have two CRTCs and each crtc would be used
68 * without dependency of hardware.
69 */
70 for (nr = 0; nr < MAX_CRTC; nr++) {
71 ret = exynos_drm_crtc_create(dev, nr);
72 if (ret)
73 goto err_crtc;
74 }
75
76 ret = drm_vblank_init(dev, MAX_CRTC);
77 if (ret)
78 goto err_crtc;
79
80 /*
81 * probe sub drivers such as display controller and hdmi driver,
82 * that were registered at probe() of platform driver
83 * to the sub driver and create encoder and connector for them.
84 */
85 ret = exynos_drm_device_register(dev);
86 if (ret)
87 goto err_vblank;
88
89 /*
90 * create and configure fb helper and also exynos specific
91 * fbdev object.
92 */
93 ret = exynos_drm_fbdev_init(dev);
94 if (ret) {
95 DRM_ERROR("failed to initialize drm fbdev\n");
96 goto err_drm_device;
97 }
98
99 return 0;
100
101err_drm_device:
102 exynos_drm_device_unregister(dev);
103err_vblank:
104 drm_vblank_cleanup(dev);
105err_crtc:
106 drm_mode_config_cleanup(dev);
107 kfree(private);
108
109 return ret;
110}
111
112static int exynos_drm_unload(struct drm_device *dev)
113{
114 DRM_DEBUG_DRIVER("%s\n", __FILE__);
115
116 exynos_drm_fbdev_fini(dev);
117 exynos_drm_device_unregister(dev);
118 drm_vblank_cleanup(dev);
119 drm_mode_config_cleanup(dev);
120 kfree(dev->dev_private);
121
122 dev->dev_private = NULL;
123
124 return 0;
125}
126
127static void exynos_drm_lastclose(struct drm_device *dev)
128{
129 DRM_DEBUG_DRIVER("%s\n", __FILE__);
130
131 exynos_drm_fbdev_restore_mode(dev);
132}
133
134static struct vm_operations_struct exynos_drm_gem_vm_ops = {
135 .fault = exynos_drm_gem_fault,
136 .open = drm_gem_vm_open,
137 .close = drm_gem_vm_close,
138};
139
140static struct drm_ioctl_desc exynos_ioctls[] = {
141 DRM_IOCTL_DEF_DRV(EXYNOS_GEM_CREATE, exynos_drm_gem_create_ioctl,
142 DRM_UNLOCKED | DRM_AUTH),
143 DRM_IOCTL_DEF_DRV(EXYNOS_GEM_MAP_OFFSET,
144 exynos_drm_gem_map_offset_ioctl, DRM_UNLOCKED |
145 DRM_AUTH),
146 DRM_IOCTL_DEF_DRV(EXYNOS_GEM_MMAP,
147 exynos_drm_gem_mmap_ioctl, DRM_UNLOCKED | DRM_AUTH),
148};
149
150static struct drm_driver exynos_drm_driver = {
151 .driver_features = DRIVER_HAVE_IRQ | DRIVER_BUS_PLATFORM |
152 DRIVER_MODESET | DRIVER_GEM,
153 .load = exynos_drm_load,
154 .unload = exynos_drm_unload,
155 .lastclose = exynos_drm_lastclose,
156 .get_vblank_counter = drm_vblank_count,
157 .enable_vblank = exynos_drm_crtc_enable_vblank,
158 .disable_vblank = exynos_drm_crtc_disable_vblank,
159 .gem_init_object = exynos_drm_gem_init_object,
160 .gem_free_object = exynos_drm_gem_free_object,
161 .gem_vm_ops = &exynos_drm_gem_vm_ops,
162 .dumb_create = exynos_drm_gem_dumb_create,
163 .dumb_map_offset = exynos_drm_gem_dumb_map_offset,
164 .dumb_destroy = exynos_drm_gem_dumb_destroy,
165 .ioctls = exynos_ioctls,
166 .fops = {
167 .owner = THIS_MODULE,
168 .open = drm_open,
169 .mmap = exynos_drm_gem_mmap,
170 .poll = drm_poll,
171 .read = drm_read,
172 .unlocked_ioctl = drm_ioctl,
173 .release = drm_release,
174 },
175 .name = DRIVER_NAME,
176 .desc = DRIVER_DESC,
177 .date = DRIVER_DATE,
178 .major = DRIVER_MAJOR,
179 .minor = DRIVER_MINOR,
180};
181
182static int exynos_drm_platform_probe(struct platform_device *pdev)
183{
184 DRM_DEBUG_DRIVER("%s\n", __FILE__);
185
186 exynos_drm_driver.num_ioctls = DRM_ARRAY_SIZE(exynos_ioctls);
187
188 return drm_platform_init(&exynos_drm_driver, pdev);
189}
190
191static int exynos_drm_platform_remove(struct platform_device *pdev)
192{
193 DRM_DEBUG_DRIVER("%s\n", __FILE__);
194
195 drm_platform_exit(&exynos_drm_driver, pdev);
196
197 return 0;
198}
199
200static struct platform_driver exynos_drm_platform_driver = {
201 .probe = exynos_drm_platform_probe,
202 .remove = __devexit_p(exynos_drm_platform_remove),
203 .driver = {
204 .owner = THIS_MODULE,
205 .name = DRIVER_NAME,
206 },
207};
208
209static int __init exynos_drm_init(void)
210{
211 DRM_DEBUG_DRIVER("%s\n", __FILE__);
212
213 return platform_driver_register(&exynos_drm_platform_driver);
214}
215
216static void __exit exynos_drm_exit(void)
217{
218 DRM_DEBUG_DRIVER("%s\n", __FILE__);
219
220 platform_driver_unregister(&exynos_drm_platform_driver);
221}
222
223module_init(exynos_drm_init);
224module_exit(exynos_drm_exit);
225
226MODULE_AUTHOR("Inki Dae <inki.dae@samsung.com>");
227MODULE_AUTHOR("Joonyoung Shim <jy0922.shim@samsung.com>");
228MODULE_AUTHOR("Seung-Woo Kim <sw0312.kim@samsung.com>");
229MODULE_DESCRIPTION("Samsung SoC DRM Driver");
230MODULE_LICENSE("GPL");
diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.h b/drivers/gpu/drm/exynos/exynos_drm_drv.h
new file mode 100644
index 000000000000..832b6508adbd
--- /dev/null
+++ b/drivers/gpu/drm/exynos/exynos_drm_drv.h
@@ -0,0 +1,242 @@
1/* exynos_drm_drv.h
2 *
3 * Copyright (c) 2011 Samsung Electronics Co., Ltd.
4 * Authors:
5 * Inki Dae <inki.dae@samsung.com>
6 * Joonyoung Shim <jy0922.shim@samsung.com>
7 * Seung-Woo Kim <sw0312.kim@samsung.com>
8 *
9 * Permission is hereby granted, free of charge, to any person obtaining a
10 * copy of this software and associated documentation files (the "Software"),
11 * to deal in the Software without restriction, including without limitation
12 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
13 * and/or sell copies of the Software, and to permit persons to whom the
14 * Software is furnished to do so, subject to the following conditions:
15 *
16 * The above copyright notice and this permission notice (including the next
17 * paragraph) shall be included in all copies or substantial portions of the
18 * Software.
19 *
20 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
23 * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
24 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
25 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
26 * OTHER DEALINGS IN THE SOFTWARE.
27 */
28
29#ifndef _EXYNOS_DRM_DRV_H_
30#define _EXYNOS_DRM_DRV_H_
31
32#include "drm.h"
33
34#define MAX_CRTC 2
35
36struct drm_device;
37struct exynos_drm_overlay;
38struct drm_connector;
39
40/* this enumerates display type. */
41enum exynos_drm_output_type {
42 EXYNOS_DISPLAY_TYPE_NONE,
43 /* RGB or CPU Interface. */
44 EXYNOS_DISPLAY_TYPE_LCD,
45 /* HDMI Interface. */
46 EXYNOS_DISPLAY_TYPE_HDMI,
47};
48
49/*
50 * Exynos drm overlay ops structure.
51 *
52 * @mode_set: copy drm overlay info to hw specific overlay info.
53 * @commit: apply hardware specific overlay data to registers.
54 * @disable: disable hardware specific overlay.
55 */
56struct exynos_drm_overlay_ops {
57 void (*mode_set)(struct device *subdrv_dev,
58 struct exynos_drm_overlay *overlay);
59 void (*commit)(struct device *subdrv_dev);
60 void (*disable)(struct device *subdrv_dev);
61};
62
63/*
64 * Exynos drm common overlay structure.
65 *
66 * @offset_x: offset to x position.
67 * @offset_y: offset to y position.
68 * @width: window width.
69 * @height: window height.
70 * @bpp: pixel size.(in bit)
71 * @paddr: bus(accessed by dma) physical memory address to this overlay
72 * and this is physically continuous.
73 * @vaddr: virtual memory addresss to this overlay.
74 * @buf_off: start offset of framebuffer to be displayed.
75 * @buf_offsize: this value has result from
76 * (framebuffer width - display width) * bpp.
77 * @line_size: line size to this overlay memory in bytes.
78 * @default_win: a window to be enabled.
79 * @color_key: color key on or off.
80 * @index_color: if using color key feature then this value would be used
81 * as index color.
82 * @local_path: in case of lcd type, local path mode on or off.
83 * @transparency: transparency on or off.
84 * @activated: activated or not.
85 *
86 * this structure is common to exynos SoC and its contents would be copied
87 * to hardware specific overlay info.
88 */
89struct exynos_drm_overlay {
90 unsigned int offset_x;
91 unsigned int offset_y;
92 unsigned int width;
93 unsigned int height;
94 unsigned int bpp;
95 dma_addr_t paddr;
96 void __iomem *vaddr;
97 unsigned int buf_off;
98 unsigned int buf_offsize;
99 unsigned int line_size;
100
101 bool default_win;
102 bool color_key;
103 unsigned int index_color;
104 bool local_path;
105 bool transparency;
106 bool activated;
107};
108
109/*
110 * Exynos DRM Display Structure.
111 * - this structure is common to analog tv, digital tv and lcd panel.
112 *
113 * @type: one of exynos_DISPLAY_TYPE_LCD and HDMI.
114 * @is_connected: check for that display is connected or not.
115 * @get_edid: get edid modes from display driver.
116 * @get_timing: get timing object from display driver.
117 * @check_timing: check if timing is valid or not.
118 * @power_on: display device on or off.
119 */
120struct exynos_drm_display {
121 enum exynos_drm_output_type type;
122 bool (*is_connected)(struct device *dev);
123 int (*get_edid)(struct device *dev, struct drm_connector *connector,
124 u8 *edid, int len);
125 void *(*get_timing)(struct device *dev);
126 int (*check_timing)(struct device *dev, void *timing);
127 int (*power_on)(struct device *dev, int mode);
128};
129
130/*
131 * Exynos drm manager ops
132 *
133 * @mode_set: convert drm_display_mode to hw specific display mode and
134 * would be called by encoder->mode_set().
135 * @commit: set current hw specific display mode to hw.
136 * @enable_vblank: specific driver callback for enabling vblank interrupt.
137 * @disable_vblank: specific driver callback for disabling vblank interrupt.
138 */
139struct exynos_drm_manager_ops {
140 void (*mode_set)(struct device *subdrv_dev, void *mode);
141 void (*commit)(struct device *subdrv_dev);
142 int (*enable_vblank)(struct device *subdrv_dev);
143 void (*disable_vblank)(struct device *subdrv_dev);
144};
145
146/*
147 * Exynos drm common manager structure.
148 *
149 * @dev: pointer to device object for subdrv device driver.
150 * sub drivers such as display controller or hdmi driver,
151 * have their own device object.
152 * @ops: pointer to callbacks for exynos drm specific framebuffer.
153 * these callbacks should be set by specific drivers such fimd
154 * or hdmi driver and are used to control hardware global registers.
155 * @overlay_ops: pointer to callbacks for exynos drm specific framebuffer.
156 * these callbacks should be set by specific drivers such fimd
157 * or hdmi driver and are used to control hardware overlay reigsters.
158 * @display: pointer to callbacks for exynos drm specific framebuffer.
159 * these callbacks should be set by specific drivers such fimd
160 * or hdmi driver and are used to control display devices such as
161 * analog tv, digital tv and lcd panel and also get timing data for them.
162 */
163struct exynos_drm_manager {
164 struct device *dev;
165 int pipe;
166 struct exynos_drm_manager_ops *ops;
167 struct exynos_drm_overlay_ops *overlay_ops;
168 struct exynos_drm_display *display;
169};
170
171/*
172 * Exynos drm private structure.
173 */
174struct exynos_drm_private {
175 struct drm_fb_helper *fb_helper;
176
177 /* for pageflip */
178 struct list_head pageflip_event_list;
179 bool pageflip_event;
180
181 /*
182 * created crtc object would be contained at this array and
183 * this array is used to be aware of which crtc did it request vblank.
184 */
185 struct drm_crtc *crtc[MAX_CRTC];
186};
187
188/*
189 * Exynos drm sub driver structure.
190 *
191 * @list: sub driver has its own list object to register to exynos drm driver.
192 * @drm_dev: pointer to drm_device and this pointer would be set
193 * when sub driver calls exynos_drm_subdrv_register().
194 * @probe: this callback would be called by exynos drm driver after
195 * subdrv is registered to it.
196 * @remove: this callback is used to release resources created
197 * by probe callback.
198 * @manager: subdrv has its own manager to control a hardware appropriately
199 * and we can access a hardware drawing on this manager.
200 * @encoder: encoder object owned by this sub driver.
201 * @connector: connector object owned by this sub driver.
202 */
203struct exynos_drm_subdrv {
204 struct list_head list;
205 struct drm_device *drm_dev;
206
207 int (*probe)(struct drm_device *dev);
208 void (*remove)(struct drm_device *dev);
209
210 struct exynos_drm_manager manager;
211 struct drm_encoder *encoder;
212 struct drm_connector *connector;
213};
214
215/*
216 * this function calls a probe callback registered to sub driver list and
217 * create its own encoder and connector and then set drm_device object
218 * to global one.
219 */
220int exynos_drm_device_register(struct drm_device *dev);
221/*
222 * this function calls a remove callback registered to sub driver list and
223 * destroy its own encoder and connetor.
224 */
225int exynos_drm_device_unregister(struct drm_device *dev);
226
227/*
228 * this function would be called by sub drivers such as display controller
229 * or hdmi driver to register this sub driver object to exynos drm driver
230 * and when a sub driver is registered to exynos drm driver a probe callback
231 * of the sub driver is called and creates its own encoder and connector
232 * and then fb helper and drm mode group would be re-initialized.
233 */
234int exynos_drm_subdrv_register(struct exynos_drm_subdrv *drm_subdrv);
235
236/*
237 * this function removes subdrv list from exynos drm driver and fb helper
238 * and drm mode group would be re-initialized.
239 */
240int exynos_drm_subdrv_unregister(struct exynos_drm_subdrv *drm_subdrv);
241
242#endif
diff --git a/drivers/gpu/drm/exynos/exynos_drm_encoder.c b/drivers/gpu/drm/exynos/exynos_drm_encoder.c
new file mode 100644
index 000000000000..7cf6fa86a67e
--- /dev/null
+++ b/drivers/gpu/drm/exynos/exynos_drm_encoder.c
@@ -0,0 +1,271 @@
1/* exynos_drm_encoder.c
2 *
3 * Copyright (c) 2011 Samsung Electronics Co., Ltd.
4 * Authors:
5 * Inki Dae <inki.dae@samsung.com>
6 * Joonyoung Shim <jy0922.shim@samsung.com>
7 * Seung-Woo Kim <sw0312.kim@samsung.com>
8 *
9 * Permission is hereby granted, free of charge, to any person obtaining a
10 * copy of this software and associated documentation files (the "Software"),
11 * to deal in the Software without restriction, including without limitation
12 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
13 * and/or sell copies of the Software, and to permit persons to whom the
14 * Software is furnished to do so, subject to the following conditions:
15 *
16 * The above copyright notice and this permission notice (including the next
17 * paragraph) shall be included in all copies or substantial portions of the
18 * Software.
19 *
20 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
23 * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
24 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
25 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
26 * OTHER DEALINGS IN THE SOFTWARE.
27 */
28
29#include "drmP.h"
30#include "drm_crtc_helper.h"
31
32#include "exynos_drm_drv.h"
33#include "exynos_drm_crtc.h"
34#include "exynos_drm_encoder.h"
35
36#define to_exynos_encoder(x) container_of(x, struct exynos_drm_encoder,\
37 drm_encoder)
38
39/*
40 * exynos specific encoder structure.
41 *
42 * @drm_encoder: encoder object.
43 * @manager: specific encoder has its own manager to control a hardware
44 * appropriately and we can access a hardware drawing on this manager.
45 */
46struct exynos_drm_encoder {
47 struct drm_encoder drm_encoder;
48 struct exynos_drm_manager *manager;
49};
50
51static void exynos_drm_encoder_dpms(struct drm_encoder *encoder, int mode)
52{
53 struct drm_device *dev = encoder->dev;
54 struct drm_connector *connector;
55 struct exynos_drm_manager *manager = exynos_drm_get_manager(encoder);
56
57 DRM_DEBUG_KMS("%s, encoder dpms: %d\n", __FILE__, mode);
58
59 list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
60 if (connector->encoder == encoder) {
61 struct exynos_drm_display *display = manager->display;
62
63 if (display && display->power_on)
64 display->power_on(manager->dev, mode);
65 }
66 }
67}
68
69static bool
70exynos_drm_encoder_mode_fixup(struct drm_encoder *encoder,
71 struct drm_display_mode *mode,
72 struct drm_display_mode *adjusted_mode)
73{
74 DRM_DEBUG_KMS("%s\n", __FILE__);
75
76 /* drm framework doesn't check NULL. */
77
78 return true;
79}
80
81static void exynos_drm_encoder_mode_set(struct drm_encoder *encoder,
82 struct drm_display_mode *mode,
83 struct drm_display_mode *adjusted_mode)
84{
85 struct drm_device *dev = encoder->dev;
86 struct drm_connector *connector;
87 struct exynos_drm_manager *manager = exynos_drm_get_manager(encoder);
88 struct exynos_drm_manager_ops *manager_ops = manager->ops;
89 struct exynos_drm_overlay_ops *overlay_ops = manager->overlay_ops;
90 struct exynos_drm_overlay *overlay = get_exynos_drm_overlay(dev,
91 encoder->crtc);
92
93 DRM_DEBUG_KMS("%s\n", __FILE__);
94
95 mode = adjusted_mode;
96
97 list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
98 if (connector->encoder == encoder) {
99 if (manager_ops && manager_ops->mode_set)
100 manager_ops->mode_set(manager->dev, mode);
101
102 if (overlay_ops && overlay_ops->mode_set)
103 overlay_ops->mode_set(manager->dev, overlay);
104 }
105 }
106}
107
108static void exynos_drm_encoder_prepare(struct drm_encoder *encoder)
109{
110 DRM_DEBUG_KMS("%s\n", __FILE__);
111
112 /* drm framework doesn't check NULL. */
113}
114
115static void exynos_drm_encoder_commit(struct drm_encoder *encoder)
116{
117 struct exynos_drm_manager *manager = exynos_drm_get_manager(encoder);
118 struct exynos_drm_manager_ops *manager_ops = manager->ops;
119 struct exynos_drm_overlay_ops *overlay_ops = manager->overlay_ops;
120
121 DRM_DEBUG_KMS("%s\n", __FILE__);
122
123 if (manager_ops && manager_ops->commit)
124 manager_ops->commit(manager->dev);
125
126 if (overlay_ops && overlay_ops->commit)
127 overlay_ops->commit(manager->dev);
128}
129
130static struct drm_crtc *
131exynos_drm_encoder_get_crtc(struct drm_encoder *encoder)
132{
133 return encoder->crtc;
134}
135
136static struct drm_encoder_helper_funcs exynos_encoder_helper_funcs = {
137 .dpms = exynos_drm_encoder_dpms,
138 .mode_fixup = exynos_drm_encoder_mode_fixup,
139 .mode_set = exynos_drm_encoder_mode_set,
140 .prepare = exynos_drm_encoder_prepare,
141 .commit = exynos_drm_encoder_commit,
142 .get_crtc = exynos_drm_encoder_get_crtc,
143};
144
145static void exynos_drm_encoder_destroy(struct drm_encoder *encoder)
146{
147 struct exynos_drm_encoder *exynos_encoder =
148 to_exynos_encoder(encoder);
149
150 DRM_DEBUG_KMS("%s\n", __FILE__);
151
152 exynos_encoder->manager->pipe = -1;
153
154 drm_encoder_cleanup(encoder);
155 encoder->dev->mode_config.num_encoder--;
156 kfree(exynos_encoder);
157}
158
159static struct drm_encoder_funcs exynos_encoder_funcs = {
160 .destroy = exynos_drm_encoder_destroy,
161};
162
163struct drm_encoder *
164exynos_drm_encoder_create(struct drm_device *dev,
165 struct exynos_drm_manager *manager,
166 unsigned int possible_crtcs)
167{
168 struct drm_encoder *encoder;
169 struct exynos_drm_encoder *exynos_encoder;
170
171 DRM_DEBUG_KMS("%s\n", __FILE__);
172
173 if (!manager || !possible_crtcs)
174 return NULL;
175
176 if (!manager->dev)
177 return NULL;
178
179 exynos_encoder = kzalloc(sizeof(*exynos_encoder), GFP_KERNEL);
180 if (!exynos_encoder) {
181 DRM_ERROR("failed to allocate encoder\n");
182 return NULL;
183 }
184
185 exynos_encoder->manager = manager;
186 encoder = &exynos_encoder->drm_encoder;
187 encoder->possible_crtcs = possible_crtcs;
188
189 DRM_DEBUG_KMS("possible_crtcs = 0x%x\n", encoder->possible_crtcs);
190
191 drm_encoder_init(dev, encoder, &exynos_encoder_funcs,
192 DRM_MODE_ENCODER_TMDS);
193
194 drm_encoder_helper_add(encoder, &exynos_encoder_helper_funcs);
195
196 DRM_DEBUG_KMS("encoder has been created\n");
197
198 return encoder;
199}
200
201struct exynos_drm_manager *exynos_drm_get_manager(struct drm_encoder *encoder)
202{
203 return to_exynos_encoder(encoder)->manager;
204}
205
206void exynos_drm_fn_encoder(struct drm_crtc *crtc, void *data,
207 void (*fn)(struct drm_encoder *, void *))
208{
209 struct drm_device *dev = crtc->dev;
210 struct drm_encoder *encoder;
211
212 list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
213 if (encoder->crtc != crtc)
214 continue;
215
216 fn(encoder, data);
217 }
218}
219
220void exynos_drm_enable_vblank(struct drm_encoder *encoder, void *data)
221{
222 struct exynos_drm_manager *manager =
223 to_exynos_encoder(encoder)->manager;
224 struct exynos_drm_manager_ops *manager_ops = manager->ops;
225 int crtc = *(int *)data;
226
227 if (manager->pipe == -1)
228 manager->pipe = crtc;
229
230 if (manager_ops->enable_vblank)
231 manager_ops->enable_vblank(manager->dev);
232}
233
234void exynos_drm_disable_vblank(struct drm_encoder *encoder, void *data)
235{
236 struct exynos_drm_manager *manager =
237 to_exynos_encoder(encoder)->manager;
238 struct exynos_drm_manager_ops *manager_ops = manager->ops;
239 int crtc = *(int *)data;
240
241 if (manager->pipe == -1)
242 manager->pipe = crtc;
243
244 if (manager_ops->disable_vblank)
245 manager_ops->disable_vblank(manager->dev);
246}
247
248void exynos_drm_encoder_crtc_commit(struct drm_encoder *encoder, void *data)
249{
250 struct exynos_drm_manager *manager =
251 to_exynos_encoder(encoder)->manager;
252 struct exynos_drm_overlay_ops *overlay_ops = manager->overlay_ops;
253
254 overlay_ops->commit(manager->dev);
255}
256
257void exynos_drm_encoder_crtc_mode_set(struct drm_encoder *encoder, void *data)
258{
259 struct exynos_drm_manager *manager =
260 to_exynos_encoder(encoder)->manager;
261 struct exynos_drm_overlay_ops *overlay_ops = manager->overlay_ops;
262 struct exynos_drm_overlay *overlay = data;
263
264 overlay_ops->mode_set(manager->dev, overlay);
265}
266
267MODULE_AUTHOR("Inki Dae <inki.dae@samsung.com>");
268MODULE_AUTHOR("Joonyoung Shim <jy0922.shim@samsung.com>");
269MODULE_AUTHOR("Seung-Woo Kim <sw0312.kim@samsung.com>");
270MODULE_DESCRIPTION("Samsung SoC DRM Encoder Driver");
271MODULE_LICENSE("GPL");
diff --git a/drivers/gpu/drm/exynos/exynos_drm_encoder.h b/drivers/gpu/drm/exynos/exynos_drm_encoder.h
new file mode 100644
index 000000000000..5ecd645d06a9
--- /dev/null
+++ b/drivers/gpu/drm/exynos/exynos_drm_encoder.h
@@ -0,0 +1,45 @@
1/*
2 * Copyright (c) 2011 Samsung Electronics Co., Ltd.
3 * Authors:
4 * Inki Dae <inki.dae@samsung.com>
5 * Joonyoung Shim <jy0922.shim@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_DRM_ENCODER_H_
29#define _EXYNOS_DRM_ENCODER_H_
30
31struct exynos_drm_manager;
32
33struct drm_encoder *exynos_drm_encoder_create(struct drm_device *dev,
34 struct exynos_drm_manager *mgr,
35 unsigned int possible_crtcs);
36struct exynos_drm_manager *
37exynos_drm_get_manager(struct drm_encoder *encoder);
38void exynos_drm_fn_encoder(struct drm_crtc *crtc, void *data,
39 void (*fn)(struct drm_encoder *, void *));
40void exynos_drm_enable_vblank(struct drm_encoder *encoder, void *data);
41void exynos_drm_disable_vblank(struct drm_encoder *encoder, void *data);
42void exynos_drm_encoder_crtc_commit(struct drm_encoder *encoder, void *data);
43void exynos_drm_encoder_crtc_mode_set(struct drm_encoder *encoder, void *data);
44
45#endif
diff --git a/drivers/gpu/drm/exynos/exynos_drm_fb.c b/drivers/gpu/drm/exynos/exynos_drm_fb.c
new file mode 100644
index 000000000000..4505d90d657a
--- /dev/null
+++ b/drivers/gpu/drm/exynos/exynos_drm_fb.c
@@ -0,0 +1,271 @@
1/* exynos_drm_fb.c
2 *
3 * Copyright (c) 2011 Samsung Electronics Co., Ltd.
4 * Authors:
5 * Inki Dae <inki.dae@samsung.com>
6 * Joonyoung Shim <jy0922.shim@samsung.com>
7 * Seung-Woo Kim <sw0312.kim@samsung.com>
8 *
9 * Permission is hereby granted, free of charge, to any person obtaining a
10 * copy of this software and associated documentation files (the "Software"),
11 * to deal in the Software without restriction, including without limitation
12 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
13 * and/or sell copies of the Software, and to permit persons to whom the
14 * Software is furnished to do so, subject to the following conditions:
15 *
16 * The above copyright notice and this permission notice (including the next
17 * paragraph) shall be included in all copies or substantial portions of the
18 * Software.
19 *
20 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
23 * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
24 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
25 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
26 * OTHER DEALINGS IN THE SOFTWARE.
27 */
28
29#include "drmP.h"
30#include "drm_crtc.h"
31#include "drm_crtc_helper.h"
32
33#include "exynos_drm_fb.h"
34#include "exynos_drm_buf.h"
35#include "exynos_drm_gem.h"
36
37#define to_exynos_fb(x) container_of(x, struct exynos_drm_fb, fb)
38
39/*
40 * exynos specific framebuffer structure.
41 *
42 * @fb: drm framebuffer obejct.
43 * @exynos_gem_obj: exynos specific gem object containing a gem object.
44 * @entry: pointer to exynos drm buffer entry object.
45 * - containing only the information to physically continuous memory
46 * region allocated at default framebuffer creation.
47 */
48struct exynos_drm_fb {
49 struct drm_framebuffer fb;
50 struct exynos_drm_gem_obj *exynos_gem_obj;
51 struct exynos_drm_buf_entry *entry;
52};
53
54static void exynos_drm_fb_destroy(struct drm_framebuffer *fb)
55{
56 struct exynos_drm_fb *exynos_fb = to_exynos_fb(fb);
57
58 DRM_DEBUG_KMS("%s\n", __FILE__);
59
60 drm_framebuffer_cleanup(fb);
61
62 /*
63 * default framebuffer has no gem object so
64 * a buffer of the default framebuffer should be released at here.
65 */
66 if (!exynos_fb->exynos_gem_obj && exynos_fb->entry)
67 exynos_drm_buf_destroy(fb->dev, exynos_fb->entry);
68
69 kfree(exynos_fb);
70 exynos_fb = NULL;
71}
72
73static int exynos_drm_fb_create_handle(struct drm_framebuffer *fb,
74 struct drm_file *file_priv,
75 unsigned int *handle)
76{
77 struct exynos_drm_fb *exynos_fb = to_exynos_fb(fb);
78
79 DRM_DEBUG_KMS("%s\n", __FILE__);
80
81 return drm_gem_handle_create(file_priv,
82 &exynos_fb->exynos_gem_obj->base, handle);
83}
84
85static int exynos_drm_fb_dirty(struct drm_framebuffer *fb,
86 struct drm_file *file_priv, unsigned flags,
87 unsigned color, struct drm_clip_rect *clips,
88 unsigned num_clips)
89{
90 DRM_DEBUG_KMS("%s\n", __FILE__);
91
92 /* TODO */
93
94 return 0;
95}
96
97static struct drm_framebuffer_funcs exynos_drm_fb_funcs = {
98 .destroy = exynos_drm_fb_destroy,
99 .create_handle = exynos_drm_fb_create_handle,
100 .dirty = exynos_drm_fb_dirty,
101};
102
103static struct drm_framebuffer *
104exynos_drm_fb_init(struct drm_file *file_priv, struct drm_device *dev,
105 struct drm_mode_fb_cmd *mode_cmd)
106{
107 struct exynos_drm_fb *exynos_fb;
108 struct drm_framebuffer *fb;
109 struct exynos_drm_gem_obj *exynos_gem_obj = NULL;
110 struct drm_gem_object *obj;
111 unsigned int size;
112 int ret;
113
114 DRM_DEBUG_KMS("%s\n", __FILE__);
115
116 mode_cmd->pitch = max(mode_cmd->pitch,
117 mode_cmd->width * (mode_cmd->bpp >> 3));
118
119 DRM_LOG_KMS("drm fb create(%dx%d)\n",
120 mode_cmd->width, mode_cmd->height);
121
122 exynos_fb = kzalloc(sizeof(*exynos_fb), GFP_KERNEL);
123 if (!exynos_fb) {
124 DRM_ERROR("failed to allocate exynos drm framebuffer.\n");
125 return ERR_PTR(-ENOMEM);
126 }
127
128 fb = &exynos_fb->fb;
129 ret = drm_framebuffer_init(dev, fb, &exynos_drm_fb_funcs);
130 if (ret) {
131 DRM_ERROR("failed to initialize framebuffer.\n");
132 goto err_init;
133 }
134
135 DRM_LOG_KMS("create: fb id: %d\n", fb->base.id);
136
137 size = mode_cmd->pitch * mode_cmd->height;
138
139 /*
140 * mode_cmd->handle could be NULL at booting time or
141 * with user request. if NULL, a new buffer or a gem object
142 * would be allocated.
143 */
144 if (!mode_cmd->handle) {
145 if (!file_priv) {
146 struct exynos_drm_buf_entry *entry;
147
148 /*
149 * in case that file_priv is NULL, it allocates
150 * only buffer and this buffer would be used
151 * for default framebuffer.
152 */
153 entry = exynos_drm_buf_create(dev, size);
154 if (IS_ERR(entry)) {
155 ret = PTR_ERR(entry);
156 goto err_buffer;
157 }
158
159 exynos_fb->entry = entry;
160
161 DRM_LOG_KMS("default fb: paddr = 0x%lx, size = 0x%x\n",
162 (unsigned long)entry->paddr, size);
163
164 goto out;
165 } else {
166 exynos_gem_obj = exynos_drm_gem_create(file_priv, dev,
167 size,
168 &mode_cmd->handle);
169 if (IS_ERR(exynos_gem_obj)) {
170 ret = PTR_ERR(exynos_gem_obj);
171 goto err_buffer;
172 }
173 }
174 } else {
175 obj = drm_gem_object_lookup(dev, file_priv, mode_cmd->handle);
176 if (!obj) {
177 DRM_ERROR("failed to lookup gem object.\n");
178 goto err_buffer;
179 }
180
181 exynos_gem_obj = to_exynos_gem_obj(obj);
182
183 drm_gem_object_unreference_unlocked(obj);
184 }
185
186 /*
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->entry = exynos_gem_obj->entry;
193
194 DRM_LOG_KMS("paddr = 0x%lx, size = 0x%x, gem object = 0x%x\n",
195 (unsigned long)exynos_fb->entry->paddr, size,
196 (unsigned int)&exynos_gem_obj->base);
197
198out:
199 exynos_fb->exynos_gem_obj = exynos_gem_obj;
200
201 drm_helper_mode_fill_fb_struct(fb, mode_cmd);
202
203 return fb;
204
205err_buffer:
206 drm_framebuffer_cleanup(fb);
207
208err_init:
209 kfree(exynos_fb);
210
211 return ERR_PTR(ret);
212}
213
214struct drm_framebuffer *exynos_drm_fb_create(struct drm_device *dev,
215 struct drm_file *file_priv,
216 struct drm_mode_fb_cmd *mode_cmd)
217{
218 DRM_DEBUG_KMS("%s\n", __FILE__);
219
220 return exynos_drm_fb_init(file_priv, dev, mode_cmd);
221}
222
223void exynos_drm_fb_update_buf_off(struct drm_framebuffer *fb,
224 unsigned int x, unsigned int y,
225 struct exynos_drm_buffer_info *info)
226{
227 struct exynos_drm_fb *exynos_fb = to_exynos_fb(fb);
228 struct exynos_drm_buf_entry *entry;
229 unsigned long offset;
230
231 DRM_DEBUG_KMS("%s\n", __FILE__);
232
233 offset = x * (fb->bits_per_pixel >> 3);
234 offset += y * fb->pitch;
235
236 entry = exynos_fb->entry;
237
238 info->base_addr = entry->paddr;
239 info->vaddr = entry->vaddr + offset;
240 info->paddr = entry->paddr + offset;
241
242 DRM_DEBUG_KMS("updated vaddr = 0x%lx, paddr = 0x%lx, offset = 0x%x\n",
243 (unsigned long)info->vaddr, (unsigned long)info->paddr,
244 (unsigned int)offset);
245}
246
247static struct drm_mode_config_funcs exynos_drm_mode_config_funcs = {
248 .fb_create = exynos_drm_fb_create,
249};
250
251void exynos_drm_mode_config_init(struct drm_device *dev)
252{
253 dev->mode_config.min_width = 0;
254 dev->mode_config.min_height = 0;
255
256 /*
257 * set max width and height as default value(4096x4096).
258 * this value would be used to check framebuffer size limitation
259 * at drm_mode_addfb().
260 */
261 dev->mode_config.max_width = 4096;
262 dev->mode_config.max_height = 4096;
263
264 dev->mode_config.funcs = &exynos_drm_mode_config_funcs;
265}
266
267MODULE_AUTHOR("Inki Dae <inki.dae@samsung.com>");
268MODULE_AUTHOR("Joonyoung Shim <jy0922.shim@samsung.com>");
269MODULE_AUTHOR("Seung-Woo Kim <sw0312.kim@samsung.com>");
270MODULE_DESCRIPTION("Samsung SoC DRM FB Driver");
271MODULE_LICENSE("GPL");
diff --git a/drivers/gpu/drm/exynos/exynos_drm_fb.h b/drivers/gpu/drm/exynos/exynos_drm_fb.h
new file mode 100644
index 000000000000..eaa478abb6d1
--- /dev/null
+++ b/drivers/gpu/drm/exynos/exynos_drm_fb.h
@@ -0,0 +1,47 @@
1/*
2 * Copyright (c) 2011 Samsung Electronics Co., Ltd.
3 * Authors:
4 * Inki Dae <inki.dae@samsung.com>
5 * Joonyoung Shim <jy0922.shim@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_DRM_FB_H_
29#define _EXYNOS_DRM_FB_H
30
31struct exynos_drm_buffer_info {
32 unsigned long base_addr;
33 dma_addr_t paddr;
34 void __iomem *vaddr;
35};
36
37void exynos_drm_fb_update_buf_off(struct drm_framebuffer *fb,
38 unsigned int x, unsigned int y,
39 struct exynos_drm_buffer_info *info);
40
41struct drm_framebuffer *exynos_drm_fb_create(struct drm_device *dev,
42 struct drm_file *filp,
43 struct drm_mode_fb_cmd *mode_cmd);
44
45void exynos_drm_mode_config_init(struct drm_device *dev);
46
47#endif
diff --git a/drivers/gpu/drm/exynos/exynos_drm_fbdev.c b/drivers/gpu/drm/exynos/exynos_drm_fbdev.c
new file mode 100644
index 000000000000..ac43bfc9e1f0
--- /dev/null
+++ b/drivers/gpu/drm/exynos/exynos_drm_fbdev.c
@@ -0,0 +1,441 @@
1/* exynos_drm_fbdev.c
2 *
3 * Copyright (c) 2011 Samsung Electronics Co., Ltd.
4 * Authors:
5 * Inki Dae <inki.dae@samsung.com>
6 * Joonyoung Shim <jy0922.shim@samsung.com>
7 * Seung-Woo Kim <sw0312.kim@samsung.com>
8 *
9 * Permission is hereby granted, free of charge, to any person obtaining a
10 * copy of this software and associated documentation files (the "Software"),
11 * to deal in the Software without restriction, including without limitation
12 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
13 * and/or sell copies of the Software, and to permit persons to whom the
14 * Software is furnished to do so, subject to the following conditions:
15 *
16 * The above copyright notice and this permission notice (including the next
17 * paragraph) shall be included in all copies or substantial portions of the
18 * Software.
19 *
20 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
23 * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
24 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
25 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
26 * OTHER DEALINGS IN THE SOFTWARE.
27 */
28
29#include "drmP.h"
30#include "drm_crtc.h"
31#include "drm_fb_helper.h"
32#include "drm_crtc_helper.h"
33
34#include "exynos_drm_drv.h"
35#include "exynos_drm_fb.h"
36
37#define MAX_CONNECTOR 4
38#define PREFERRED_BPP 32
39
40#define to_exynos_fbdev(x) container_of(x, struct exynos_drm_fbdev,\
41 drm_fb_helper)
42
43struct exynos_drm_fbdev {
44 struct drm_fb_helper drm_fb_helper;
45 struct drm_framebuffer *fb;
46};
47
48static int exynos_drm_fbdev_set_par(struct fb_info *info)
49{
50 struct fb_var_screeninfo *var = &info->var;
51
52 switch (var->bits_per_pixel) {
53 case 32:
54 case 24:
55 case 18:
56 case 16:
57 case 12:
58 info->fix.visual = FB_VISUAL_TRUECOLOR;
59 break;
60 case 1:
61 info->fix.visual = FB_VISUAL_MONO01;
62 break;
63 default:
64 info->fix.visual = FB_VISUAL_PSEUDOCOLOR;
65 break;
66 }
67
68 info->fix.line_length = (var->xres_virtual * var->bits_per_pixel) / 8;
69
70 return drm_fb_helper_set_par(info);
71}
72
73
74static struct fb_ops exynos_drm_fb_ops = {
75 .owner = THIS_MODULE,
76 .fb_fillrect = cfb_fillrect,
77 .fb_copyarea = cfb_copyarea,
78 .fb_imageblit = cfb_imageblit,
79 .fb_check_var = drm_fb_helper_check_var,
80 .fb_set_par = exynos_drm_fbdev_set_par,
81 .fb_blank = drm_fb_helper_blank,
82 .fb_pan_display = drm_fb_helper_pan_display,
83 .fb_setcmap = drm_fb_helper_setcmap,
84};
85
86static void exynos_drm_fbdev_update(struct drm_fb_helper *helper,
87 struct drm_framebuffer *fb,
88 unsigned int fb_width,
89 unsigned int fb_height)
90{
91 struct fb_info *fbi = helper->fbdev;
92 struct drm_device *dev = helper->dev;
93 struct exynos_drm_fbdev *exynos_fb = to_exynos_fbdev(helper);
94 struct exynos_drm_buffer_info buffer_info;
95 unsigned int size = fb_width * fb_height * (fb->bits_per_pixel >> 3);
96
97 DRM_DEBUG_KMS("%s\n", __FILE__);
98
99 exynos_fb->fb = fb;
100
101 drm_fb_helper_fill_fix(fbi, fb->pitch, fb->depth);
102 drm_fb_helper_fill_var(fbi, helper, fb_width, fb_height);
103
104 exynos_drm_fb_update_buf_off(fb, fbi->var.xoffset, fbi->var.yoffset,
105 &buffer_info);
106
107 dev->mode_config.fb_base = buffer_info.base_addr;
108
109 fbi->screen_base = buffer_info.vaddr;
110 fbi->screen_size = size;
111 fbi->fix.smem_start = buffer_info.paddr;
112 fbi->fix.smem_len = size;
113}
114
115static int exynos_drm_fbdev_create(struct drm_fb_helper *helper,
116 struct drm_fb_helper_surface_size *sizes)
117{
118 struct exynos_drm_fbdev *exynos_fbdev = to_exynos_fbdev(helper);
119 struct drm_device *dev = helper->dev;
120 struct fb_info *fbi;
121 struct drm_mode_fb_cmd mode_cmd = { 0 };
122 struct platform_device *pdev = dev->platformdev;
123 int ret;
124
125 DRM_DEBUG_KMS("%s\n", __FILE__);
126
127 DRM_DEBUG_KMS("surface width(%d), height(%d) and bpp(%d\n",
128 sizes->surface_width, sizes->surface_height,
129 sizes->surface_bpp);
130
131 mode_cmd.width = sizes->surface_width;
132 mode_cmd.height = sizes->surface_height;
133 mode_cmd.bpp = sizes->surface_bpp;
134 mode_cmd.depth = sizes->surface_depth;
135
136 mutex_lock(&dev->struct_mutex);
137
138 fbi = framebuffer_alloc(0, &pdev->dev);
139 if (!fbi) {
140 DRM_ERROR("failed to allocate fb info.\n");
141 ret = -ENOMEM;
142 goto out;
143 }
144
145 exynos_fbdev->fb = exynos_drm_fb_create(dev, NULL, &mode_cmd);
146 if (IS_ERR_OR_NULL(exynos_fbdev->fb)) {
147 DRM_ERROR("failed to create drm framebuffer.\n");
148 ret = PTR_ERR(exynos_fbdev->fb);
149 goto out;
150 }
151
152 helper->fb = exynos_fbdev->fb;
153 helper->fbdev = fbi;
154
155 fbi->par = helper;
156 fbi->flags = FBINFO_FLAG_DEFAULT;
157 fbi->fbops = &exynos_drm_fb_ops;
158
159 ret = fb_alloc_cmap(&fbi->cmap, 256, 0);
160 if (ret) {
161 DRM_ERROR("failed to allocate cmap.\n");
162 goto out;
163 }
164
165 exynos_drm_fbdev_update(helper, helper->fb, sizes->fb_width,
166 sizes->fb_height);
167
168/*
169 * if failed, all resources allocated above would be released by
170 * drm_mode_config_cleanup() when drm_load() had been called prior
171 * to any specific driver such as fimd or hdmi driver.
172 */
173out:
174 mutex_unlock(&dev->struct_mutex);
175 return ret;
176}
177
178static bool
179exynos_drm_fbdev_is_samefb(struct drm_framebuffer *fb,
180 struct drm_fb_helper_surface_size *sizes)
181{
182 if (fb->width != sizes->surface_width)
183 return false;
184 if (fb->height != sizes->surface_height)
185 return false;
186 if (fb->bits_per_pixel != sizes->surface_bpp)
187 return false;
188 if (fb->depth != sizes->surface_depth)
189 return false;
190
191 return true;
192}
193
194static int exynos_drm_fbdev_recreate(struct drm_fb_helper *helper,
195 struct drm_fb_helper_surface_size *sizes)
196{
197 struct drm_device *dev = helper->dev;
198 struct exynos_drm_fbdev *exynos_fbdev = to_exynos_fbdev(helper);
199 struct drm_framebuffer *fb = exynos_fbdev->fb;
200 struct drm_mode_fb_cmd mode_cmd = { 0 };
201
202 DRM_DEBUG_KMS("%s\n", __FILE__);
203
204 if (helper->fb != fb) {
205 DRM_ERROR("drm framebuffer is different\n");
206 return -EINVAL;
207 }
208
209 if (exynos_drm_fbdev_is_samefb(fb, sizes))
210 return 0;
211
212 mode_cmd.width = sizes->surface_width;
213 mode_cmd.height = sizes->surface_height;
214 mode_cmd.bpp = sizes->surface_bpp;
215 mode_cmd.depth = sizes->surface_depth;
216
217 if (fb->funcs->destroy)
218 fb->funcs->destroy(fb);
219
220 exynos_fbdev->fb = exynos_drm_fb_create(dev, NULL, &mode_cmd);
221 if (IS_ERR(exynos_fbdev->fb)) {
222 DRM_ERROR("failed to allocate fb.\n");
223 return PTR_ERR(exynos_fbdev->fb);
224 }
225
226 helper->fb = exynos_fbdev->fb;
227 exynos_drm_fbdev_update(helper, helper->fb, sizes->fb_width,
228 sizes->fb_height);
229
230 return 0;
231}
232
233static int exynos_drm_fbdev_probe(struct drm_fb_helper *helper,
234 struct drm_fb_helper_surface_size *sizes)
235{
236 int ret = 0;
237
238 DRM_DEBUG_KMS("%s\n", __FILE__);
239
240 if (!helper->fb) {
241 ret = exynos_drm_fbdev_create(helper, sizes);
242 if (ret < 0) {
243 DRM_ERROR("failed to create fbdev.\n");
244 return ret;
245 }
246
247 /*
248 * fb_helper expects a value more than 1 if succeed
249 * because register_framebuffer() should be called.
250 */
251 ret = 1;
252 } else {
253 ret = exynos_drm_fbdev_recreate(helper, sizes);
254 if (ret < 0) {
255 DRM_ERROR("failed to reconfigure fbdev\n");
256 return ret;
257 }
258 }
259
260 return ret;
261}
262
263static struct drm_fb_helper_funcs exynos_drm_fb_helper_funcs = {
264 .fb_probe = exynos_drm_fbdev_probe,
265};
266
267int exynos_drm_fbdev_init(struct drm_device *dev)
268{
269 struct exynos_drm_fbdev *fbdev;
270 struct exynos_drm_private *private = dev->dev_private;
271 struct drm_fb_helper *helper;
272 unsigned int num_crtc;
273 int ret;
274
275 DRM_DEBUG_KMS("%s\n", __FILE__);
276
277 if (!dev->mode_config.num_crtc || !dev->mode_config.num_connector)
278 return 0;
279
280 fbdev = kzalloc(sizeof(*fbdev), GFP_KERNEL);
281 if (!fbdev) {
282 DRM_ERROR("failed to allocate drm fbdev.\n");
283 return -ENOMEM;
284 }
285
286 private->fb_helper = helper = &fbdev->drm_fb_helper;
287 helper->funcs = &exynos_drm_fb_helper_funcs;
288
289 num_crtc = dev->mode_config.num_crtc;
290
291 ret = drm_fb_helper_init(dev, helper, num_crtc, MAX_CONNECTOR);
292 if (ret < 0) {
293 DRM_ERROR("failed to initialize drm fb helper.\n");
294 goto err_init;
295 }
296
297 ret = drm_fb_helper_single_add_all_connectors(helper);
298 if (ret < 0) {
299 DRM_ERROR("failed to register drm_fb_helper_connector.\n");
300 goto err_setup;
301
302 }
303
304 ret = drm_fb_helper_initial_config(helper, PREFERRED_BPP);
305 if (ret < 0) {
306 DRM_ERROR("failed to set up hw configuration.\n");
307 goto err_setup;
308 }
309
310 return 0;
311
312err_setup:
313 drm_fb_helper_fini(helper);
314
315err_init:
316 private->fb_helper = NULL;
317 kfree(fbdev);
318
319 return ret;
320}
321
322static void exynos_drm_fbdev_destroy(struct drm_device *dev,
323 struct drm_fb_helper *fb_helper)
324{
325 struct drm_framebuffer *fb;
326
327 /* release drm framebuffer and real buffer */
328 if (fb_helper->fb && fb_helper->fb->funcs) {
329 fb = fb_helper->fb;
330 if (fb && fb->funcs->destroy)
331 fb->funcs->destroy(fb);
332 }
333
334 /* release linux framebuffer */
335 if (fb_helper->fbdev) {
336 struct fb_info *info;
337 int ret;
338
339 info = fb_helper->fbdev;
340 ret = unregister_framebuffer(info);
341 if (ret < 0)
342 DRM_DEBUG_KMS("failed unregister_framebuffer()\n");
343
344 if (info->cmap.len)
345 fb_dealloc_cmap(&info->cmap);
346
347 framebuffer_release(info);
348 }
349
350 drm_fb_helper_fini(fb_helper);
351}
352
353void exynos_drm_fbdev_fini(struct drm_device *dev)
354{
355 struct exynos_drm_private *private = dev->dev_private;
356 struct exynos_drm_fbdev *fbdev;
357
358 if (!private || !private->fb_helper)
359 return;
360
361 fbdev = to_exynos_fbdev(private->fb_helper);
362
363 exynos_drm_fbdev_destroy(dev, private->fb_helper);
364 kfree(fbdev);
365 private->fb_helper = NULL;
366}
367
368void exynos_drm_fbdev_restore_mode(struct drm_device *dev)
369{
370 struct exynos_drm_private *private = dev->dev_private;
371
372 if (!private || !private->fb_helper)
373 return;
374
375 drm_fb_helper_restore_fbdev_mode(private->fb_helper);
376}
377
378int exynos_drm_fbdev_reinit(struct drm_device *dev)
379{
380 struct exynos_drm_private *private = dev->dev_private;
381 struct drm_fb_helper *fb_helper;
382 int ret;
383
384 if (!private)
385 return -EINVAL;
386
387 if (!dev->mode_config.num_connector) {
388 exynos_drm_fbdev_fini(dev);
389 return 0;
390 }
391
392 fb_helper = private->fb_helper;
393
394 if (fb_helper) {
395 drm_fb_helper_fini(fb_helper);
396
397 ret = drm_fb_helper_init(dev, fb_helper,
398 dev->mode_config.num_crtc, MAX_CONNECTOR);
399 if (ret < 0) {
400 DRM_ERROR("failed to initialize drm fb helper\n");
401 return ret;
402 }
403
404 ret = drm_fb_helper_single_add_all_connectors(fb_helper);
405 if (ret < 0) {
406 DRM_ERROR("failed to add fb helper to connectors\n");
407 goto err;
408 }
409
410 ret = drm_fb_helper_initial_config(fb_helper, PREFERRED_BPP);
411 if (ret < 0) {
412 DRM_ERROR("failed to set up hw configuration.\n");
413 goto err;
414 }
415 } else {
416 /*
417 * if drm_load() failed whem drm load() was called prior
418 * to specific drivers, fb_helper must be NULL and so
419 * this fuction should be called again to re-initialize and
420 * re-configure the fb helper. it means that this function
421 * has been called by the specific drivers.
422 */
423 return exynos_drm_fbdev_init(dev);
424 }
425
426err:
427 /*
428 * if drm_load() failed when drm load() was called prior
429 * to specific drivers, the fb_helper must be NULL and so check it.
430 */
431 if (fb_helper)
432 drm_fb_helper_fini(fb_helper);
433
434 return ret;
435}
436
437MODULE_AUTHOR("Inki Dae <inki.dae@samsung.com>");
438MODULE_AUTHOR("Joonyoung Shim <jy0922.shim@samsung.com>");
439MODULE_AUTHOR("Seung-Woo Kim <sw0312.kim@samsung.com>");
440MODULE_DESCRIPTION("Samsung SoC DRM FBDEV Driver");
441MODULE_LICENSE("GPL");
diff --git a/drivers/gpu/drm/exynos/exynos_drm_fbdev.h b/drivers/gpu/drm/exynos/exynos_drm_fbdev.h
new file mode 100644
index 000000000000..ccfce8a1a451
--- /dev/null
+++ b/drivers/gpu/drm/exynos/exynos_drm_fbdev.h
@@ -0,0 +1,37 @@
1/*
2 * Copyright (c) 2011 Samsung Electronics Co., Ltd.
3 *
4 * Authors:
5 * Inki Dae <inki.dae@samsung.com>
6 * Joonyoung Shim <jy0922.shim@samsung.com>
7 * Seung-Woo Kim <sw0312.kim@samsung.com>
8 *
9 * Permission is hereby granted, free of charge, to any person obtaining a
10 * copy of this software and associated documentation files (the "Software"),
11 * to deal in the Software without restriction, including without limitation
12 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
13 * and/or sell copies of the Software, and to permit persons to whom the
14 * Software is furnished to do so, subject to the following conditions:
15 *
16 * The above copyright notice and this permission notice (including the next
17 * paragraph) shall be included in all copies or substantial portions of the
18 * Software.
19 *
20 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
23 * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
24 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
25 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
26 * OTHER DEALINGS IN THE SOFTWARE.
27 */
28
29#ifndef _EXYNOS_DRM_FBDEV_H_
30#define _EXYNOS_DRM_FBDEV_H_
31
32int exynos_drm_fbdev_init(struct drm_device *dev);
33int exynos_drm_fbdev_reinit(struct drm_device *dev);
34void exynos_drm_fbdev_fini(struct drm_device *dev);
35void exynos_drm_fbdev_restore_mode(struct drm_device *dev);
36
37#endif
diff --git a/drivers/gpu/drm/exynos/exynos_drm_fimd.c b/drivers/gpu/drm/exynos/exynos_drm_fimd.c
new file mode 100644
index 000000000000..620ad2d51368
--- /dev/null
+++ b/drivers/gpu/drm/exynos/exynos_drm_fimd.c
@@ -0,0 +1,796 @@
1/* exynos_drm_fimd.c
2 *
3 * Copyright (C) 2011 Samsung Electronics Co.Ltd
4 * Authors:
5 * Joonyoung Shim <jy0922.shim@samsung.com>
6 * Inki Dae <inki.dae@samsung.com>
7 *
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms of the GNU General Public License as published by the
10 * Free Software Foundation; either version 2 of the License, or (at your
11 * option) any later version.
12 *
13 */
14#include "drmP.h"
15
16#include <linux/kernel.h>
17#include <linux/module.h>
18#include <linux/platform_device.h>
19#include <linux/clk.h>
20
21#include <drm/exynos_drm.h>
22#include <plat/regs-fb-v4.h>
23
24#include "exynos_drm_drv.h"
25#include "exynos_drm_fbdev.h"
26#include "exynos_drm_crtc.h"
27
28/*
29 * FIMD is stand for Fully Interactive Mobile Display and
30 * as a display controller, it transfers contents drawn on memory
31 * to a LCD Panel through Display Interfaces such as RGB or
32 * CPU Interface.
33 */
34
35/* position control register for hardware window 0, 2 ~ 4.*/
36#define VIDOSD_A(win) (VIDOSD_BASE + 0x00 + (win) * 16)
37#define VIDOSD_B(win) (VIDOSD_BASE + 0x04 + (win) * 16)
38/* size control register for hardware window 0. */
39#define VIDOSD_C_SIZE_W0 (VIDOSD_BASE + 0x08)
40/* alpha control register for hardware window 1 ~ 4. */
41#define VIDOSD_C(win) (VIDOSD_BASE + 0x18 + (win) * 16)
42/* size control register for hardware window 1 ~ 4. */
43#define VIDOSD_D(win) (VIDOSD_BASE + 0x0C + (win) * 16)
44
45#define VIDWx_BUF_START(win, buf) (VIDW_BUF_START(buf) + (win) * 8)
46#define VIDWx_BUF_END(win, buf) (VIDW_BUF_END(buf) + (win) * 8)
47#define VIDWx_BUF_SIZE(win, buf) (VIDW_BUF_SIZE(buf) + (win) * 4)
48
49/* color key control register for hardware window 1 ~ 4. */
50#define WKEYCON0_BASE(x) ((WKEYCON0 + 0x140) + (x * 8))
51/* color key value register for hardware window 1 ~ 4. */
52#define WKEYCON1_BASE(x) ((WKEYCON1 + 0x140) + (x * 8))
53
54/* FIMD has totally five hardware windows. */
55#define WINDOWS_NR 5
56
57#define get_fimd_context(dev) platform_get_drvdata(to_platform_device(dev))
58
59struct fimd_win_data {
60 unsigned int offset_x;
61 unsigned int offset_y;
62 unsigned int width;
63 unsigned int height;
64 unsigned int bpp;
65 dma_addr_t paddr;
66 void __iomem *vaddr;
67 unsigned int buf_offsize;
68 unsigned int line_size; /* bytes */
69};
70
71struct fimd_context {
72 struct exynos_drm_subdrv subdrv;
73 int irq;
74 struct drm_crtc *crtc;
75 struct clk *bus_clk;
76 struct clk *lcd_clk;
77 struct resource *regs_res;
78 void __iomem *regs;
79 struct fimd_win_data win_data[WINDOWS_NR];
80 unsigned int clkdiv;
81 unsigned int default_win;
82 unsigned long irq_flags;
83 u32 vidcon0;
84 u32 vidcon1;
85
86 struct fb_videomode *timing;
87};
88
89static bool fimd_display_is_connected(struct device *dev)
90{
91 struct fimd_context *ctx = get_fimd_context(dev);
92
93 DRM_DEBUG_KMS("%s\n", __FILE__);
94
95 /* TODO. */
96
97 return true;
98}
99
100static void *fimd_get_timing(struct device *dev)
101{
102 struct fimd_context *ctx = get_fimd_context(dev);
103
104 DRM_DEBUG_KMS("%s\n", __FILE__);
105
106 return ctx->timing;
107}
108
109static int fimd_check_timing(struct device *dev, void *timing)
110{
111 struct fimd_context *ctx = get_fimd_context(dev);
112
113 DRM_DEBUG_KMS("%s\n", __FILE__);
114
115 /* TODO. */
116
117 return 0;
118}
119
120static int fimd_display_power_on(struct device *dev, int mode)
121{
122 struct fimd_context *ctx = get_fimd_context(dev);
123
124 DRM_DEBUG_KMS("%s\n", __FILE__);
125
126 /* TODO. */
127
128 return 0;
129}
130
131static struct exynos_drm_display fimd_display = {
132 .type = EXYNOS_DISPLAY_TYPE_LCD,
133 .is_connected = fimd_display_is_connected,
134 .get_timing = fimd_get_timing,
135 .check_timing = fimd_check_timing,
136 .power_on = fimd_display_power_on,
137};
138
139static void fimd_commit(struct device *dev)
140{
141 struct fimd_context *ctx = get_fimd_context(dev);
142 struct fb_videomode *timing = ctx->timing;
143 u32 val;
144
145 DRM_DEBUG_KMS("%s\n", __FILE__);
146
147 /* setup polarity values from machine code. */
148 writel(ctx->vidcon1, ctx->regs + VIDCON1);
149
150 /* setup vertical timing values. */
151 val = VIDTCON0_VBPD(timing->upper_margin - 1) |
152 VIDTCON0_VFPD(timing->lower_margin - 1) |
153 VIDTCON0_VSPW(timing->vsync_len - 1);
154 writel(val, ctx->regs + VIDTCON0);
155
156 /* setup horizontal timing values. */
157 val = VIDTCON1_HBPD(timing->left_margin - 1) |
158 VIDTCON1_HFPD(timing->right_margin - 1) |
159 VIDTCON1_HSPW(timing->hsync_len - 1);
160 writel(val, ctx->regs + VIDTCON1);
161
162 /* setup horizontal and vertical display size. */
163 val = VIDTCON2_LINEVAL(timing->yres - 1) |
164 VIDTCON2_HOZVAL(timing->xres - 1);
165 writel(val, ctx->regs + VIDTCON2);
166
167 /* setup clock source, clock divider, enable dma. */
168 val = ctx->vidcon0;
169 val &= ~(VIDCON0_CLKVAL_F_MASK | VIDCON0_CLKDIR);
170
171 if (ctx->clkdiv > 1)
172 val |= VIDCON0_CLKVAL_F(ctx->clkdiv - 1) | VIDCON0_CLKDIR;
173 else
174 val &= ~VIDCON0_CLKDIR; /* 1:1 clock */
175
176 /*
177 * fields of register with prefix '_F' would be updated
178 * at vsync(same as dma start)
179 */
180 val |= VIDCON0_ENVID | VIDCON0_ENVID_F;
181 writel(val, ctx->regs + VIDCON0);
182}
183
184static int fimd_enable_vblank(struct device *dev)
185{
186 struct fimd_context *ctx = get_fimd_context(dev);
187 u32 val;
188
189 DRM_DEBUG_KMS("%s\n", __FILE__);
190
191 if (!test_and_set_bit(0, &ctx->irq_flags)) {
192 val = readl(ctx->regs + VIDINTCON0);
193
194 val |= VIDINTCON0_INT_ENABLE;
195 val |= VIDINTCON0_INT_FRAME;
196
197 val &= ~VIDINTCON0_FRAMESEL0_MASK;
198 val |= VIDINTCON0_FRAMESEL0_VSYNC;
199 val &= ~VIDINTCON0_FRAMESEL1_MASK;
200 val |= VIDINTCON0_FRAMESEL1_NONE;
201
202 writel(val, ctx->regs + VIDINTCON0);
203 }
204
205 return 0;
206}
207
208static void fimd_disable_vblank(struct device *dev)
209{
210 struct fimd_context *ctx = get_fimd_context(dev);
211 u32 val;
212
213 DRM_DEBUG_KMS("%s\n", __FILE__);
214
215 if (test_and_clear_bit(0, &ctx->irq_flags)) {
216 val = readl(ctx->regs + VIDINTCON0);
217
218 val &= ~VIDINTCON0_INT_FRAME;
219 val &= ~VIDINTCON0_INT_ENABLE;
220
221 writel(val, ctx->regs + VIDINTCON0);
222 }
223}
224
225static struct exynos_drm_manager_ops fimd_manager_ops = {
226 .commit = fimd_commit,
227 .enable_vblank = fimd_enable_vblank,
228 .disable_vblank = fimd_disable_vblank,
229};
230
231static void fimd_win_mode_set(struct device *dev,
232 struct exynos_drm_overlay *overlay)
233{
234 struct fimd_context *ctx = get_fimd_context(dev);
235 struct fimd_win_data *win_data;
236
237 DRM_DEBUG_KMS("%s\n", __FILE__);
238
239 if (!overlay) {
240 dev_err(dev, "overlay is NULL\n");
241 return;
242 }
243
244 win_data = &ctx->win_data[ctx->default_win];
245
246 win_data->offset_x = overlay->offset_x;
247 win_data->offset_y = overlay->offset_y;
248 win_data->width = overlay->width;
249 win_data->height = overlay->height;
250 win_data->paddr = overlay->paddr;
251 win_data->vaddr = overlay->vaddr;
252 win_data->bpp = overlay->bpp;
253 win_data->buf_offsize = overlay->buf_offsize * (overlay->bpp >> 3);
254 win_data->line_size = overlay->line_size * (overlay->bpp >> 3);
255}
256
257static void fimd_win_set_pixfmt(struct device *dev, unsigned int win)
258{
259 struct fimd_context *ctx = get_fimd_context(dev);
260 struct fimd_win_data *win_data = &ctx->win_data[win];
261 unsigned long val;
262
263 DRM_DEBUG_KMS("%s\n", __FILE__);
264
265 val = WINCONx_ENWIN;
266
267 switch (win_data->bpp) {
268 case 1:
269 val |= WINCON0_BPPMODE_1BPP;
270 val |= WINCONx_BITSWP;
271 val |= WINCONx_BURSTLEN_4WORD;
272 break;
273 case 2:
274 val |= WINCON0_BPPMODE_2BPP;
275 val |= WINCONx_BITSWP;
276 val |= WINCONx_BURSTLEN_8WORD;
277 break;
278 case 4:
279 val |= WINCON0_BPPMODE_4BPP;
280 val |= WINCONx_BITSWP;
281 val |= WINCONx_BURSTLEN_8WORD;
282 break;
283 case 8:
284 val |= WINCON0_BPPMODE_8BPP_PALETTE;
285 val |= WINCONx_BURSTLEN_8WORD;
286 val |= WINCONx_BYTSWP;
287 break;
288 case 16:
289 val |= WINCON0_BPPMODE_16BPP_565;
290 val |= WINCONx_HAWSWP;
291 val |= WINCONx_BURSTLEN_16WORD;
292 break;
293 case 24:
294 val |= WINCON0_BPPMODE_24BPP_888;
295 val |= WINCONx_WSWP;
296 val |= WINCONx_BURSTLEN_16WORD;
297 break;
298 case 32:
299 val |= WINCON1_BPPMODE_28BPP_A4888
300 | WINCON1_BLD_PIX | WINCON1_ALPHA_SEL;
301 val |= WINCONx_WSWP;
302 val |= WINCONx_BURSTLEN_16WORD;
303 break;
304 default:
305 DRM_DEBUG_KMS("invalid pixel size so using unpacked 24bpp.\n");
306
307 val |= WINCON0_BPPMODE_24BPP_888;
308 val |= WINCONx_WSWP;
309 val |= WINCONx_BURSTLEN_16WORD;
310 break;
311 }
312
313 DRM_DEBUG_KMS("bpp = %d\n", win_data->bpp);
314
315 writel(val, ctx->regs + WINCON(win));
316}
317
318static void fimd_win_set_colkey(struct device *dev, unsigned int win)
319{
320 struct fimd_context *ctx = get_fimd_context(dev);
321 unsigned int keycon0 = 0, keycon1 = 0;
322
323 DRM_DEBUG_KMS("%s\n", __FILE__);
324
325 keycon0 = ~(WxKEYCON0_KEYBL_EN | WxKEYCON0_KEYEN_F |
326 WxKEYCON0_DIRCON) | WxKEYCON0_COMPKEY(0);
327
328 keycon1 = WxKEYCON1_COLVAL(0xffffffff);
329
330 writel(keycon0, ctx->regs + WKEYCON0_BASE(win));
331 writel(keycon1, ctx->regs + WKEYCON1_BASE(win));
332}
333
334static void fimd_win_commit(struct device *dev)
335{
336 struct fimd_context *ctx = get_fimd_context(dev);
337 struct fimd_win_data *win_data;
338 int win = ctx->default_win;
339 unsigned long val, alpha, size;
340
341 DRM_DEBUG_KMS("%s\n", __FILE__);
342
343 if (win < 0 || win > WINDOWS_NR)
344 return;
345
346 win_data = &ctx->win_data[win];
347
348 /*
349 * SHADOWCON register is used for enabling timing.
350 *
351 * for example, once only width value of a register is set,
352 * if the dma is started then fimd hardware could malfunction so
353 * with protect window setting, the register fields with prefix '_F'
354 * wouldn't be updated at vsync also but updated once unprotect window
355 * is set.
356 */
357
358 /* protect windows */
359 val = readl(ctx->regs + SHADOWCON);
360 val |= SHADOWCON_WINx_PROTECT(win);
361 writel(val, ctx->regs + SHADOWCON);
362
363 /* buffer start address */
364 val = win_data->paddr;
365 writel(val, ctx->regs + VIDWx_BUF_START(win, 0));
366
367 /* buffer end address */
368 size = win_data->width * win_data->height * (win_data->bpp >> 3);
369 val = win_data->paddr + size;
370 writel(val, ctx->regs + VIDWx_BUF_END(win, 0));
371
372 DRM_DEBUG_KMS("start addr = 0x%lx, end addr = 0x%lx, size = 0x%lx\n",
373 (unsigned long)win_data->paddr, val, size);
374
375 /* buffer size */
376 val = VIDW_BUF_SIZE_OFFSET(win_data->buf_offsize) |
377 VIDW_BUF_SIZE_PAGEWIDTH(win_data->line_size);
378 writel(val, ctx->regs + VIDWx_BUF_SIZE(win, 0));
379
380 /* OSD position */
381 val = VIDOSDxA_TOPLEFT_X(win_data->offset_x) |
382 VIDOSDxA_TOPLEFT_Y(win_data->offset_y);
383 writel(val, ctx->regs + VIDOSD_A(win));
384
385 val = VIDOSDxB_BOTRIGHT_X(win_data->offset_x + win_data->width - 1) |
386 VIDOSDxB_BOTRIGHT_Y(win_data->offset_y + win_data->height - 1);
387 writel(val, ctx->regs + VIDOSD_B(win));
388
389 DRM_DEBUG_KMS("osd pos: tx = %d, ty = %d, bx = %d, by = %x\n",
390 win_data->offset_x, win_data->offset_y,
391 win_data->offset_x + win_data->width - 1,
392 win_data->offset_y + win_data->height - 1);
393
394 /* hardware window 0 doesn't support alpha channel. */
395 if (win != 0) {
396 /* OSD alpha */
397 alpha = VIDISD14C_ALPHA1_R(0xf) |
398 VIDISD14C_ALPHA1_G(0xf) |
399 VIDISD14C_ALPHA1_B(0xf);
400
401 writel(alpha, ctx->regs + VIDOSD_C(win));
402 }
403
404 /* OSD size */
405 if (win != 3 && win != 4) {
406 u32 offset = VIDOSD_D(win);
407 if (win == 0)
408 offset = VIDOSD_C_SIZE_W0;
409 val = win_data->width * win_data->height;
410 writel(val, ctx->regs + offset);
411
412 DRM_DEBUG_KMS("osd size = 0x%x\n", (unsigned int)val);
413 }
414
415 fimd_win_set_pixfmt(dev, win);
416
417 /* hardware window 0 doesn't support color key. */
418 if (win != 0)
419 fimd_win_set_colkey(dev, win);
420
421 /* Enable DMA channel and unprotect windows */
422 val = readl(ctx->regs + SHADOWCON);
423 val |= SHADOWCON_CHx_ENABLE(win);
424 val &= ~SHADOWCON_WINx_PROTECT(win);
425 writel(val, ctx->regs + SHADOWCON);
426}
427
428static void fimd_win_disable(struct device *dev)
429{
430 struct fimd_context *ctx = get_fimd_context(dev);
431 struct fimd_win_data *win_data;
432 int win = ctx->default_win;
433 u32 val;
434
435 DRM_DEBUG_KMS("%s\n", __FILE__);
436
437 if (win < 0 || win > WINDOWS_NR)
438 return;
439
440 win_data = &ctx->win_data[win];
441
442 /* protect windows */
443 val = readl(ctx->regs + SHADOWCON);
444 val |= SHADOWCON_WINx_PROTECT(win);
445 writel(val, ctx->regs + SHADOWCON);
446
447 /* wincon */
448 val = readl(ctx->regs + WINCON(win));
449 val &= ~WINCONx_ENWIN;
450 writel(val, ctx->regs + WINCON(win));
451
452 /* unprotect windows */
453 val = readl(ctx->regs + SHADOWCON);
454 val &= ~SHADOWCON_CHx_ENABLE(win);
455 val &= ~SHADOWCON_WINx_PROTECT(win);
456 writel(val, ctx->regs + SHADOWCON);
457}
458
459static struct exynos_drm_overlay_ops fimd_overlay_ops = {
460 .mode_set = fimd_win_mode_set,
461 .commit = fimd_win_commit,
462 .disable = fimd_win_disable,
463};
464
465/* for pageflip event */
466static void fimd_finish_pageflip(struct drm_device *drm_dev, int crtc)
467{
468 struct exynos_drm_private *dev_priv = drm_dev->dev_private;
469 struct drm_pending_vblank_event *e, *t;
470 struct timeval now;
471 unsigned long flags;
472
473 if (!dev_priv->pageflip_event)
474 return;
475
476 spin_lock_irqsave(&drm_dev->event_lock, flags);
477
478 exynos_drm_crtc_apply(dev_priv->crtc[crtc]);
479
480 list_for_each_entry_safe(e, t, &dev_priv->pageflip_event_list,
481 base.link) {
482 do_gettimeofday(&now);
483 e->event.sequence = 0;
484 e->event.tv_sec = now.tv_sec;
485 e->event.tv_usec = now.tv_usec;
486
487 list_move_tail(&e->base.link, &e->base.file_priv->event_list);
488 wake_up_interruptible(&e->base.file_priv->event_wait);
489 }
490
491 drm_vblank_put(drm_dev, crtc);
492 dev_priv->pageflip_event = false;
493
494 spin_unlock_irqrestore(&drm_dev->event_lock, flags);
495}
496
497static irqreturn_t fimd_irq_handler(int irq, void *dev_id)
498{
499 struct fimd_context *ctx = (struct fimd_context *)dev_id;
500 struct exynos_drm_subdrv *subdrv = &ctx->subdrv;
501 struct drm_device *drm_dev = subdrv->drm_dev;
502 struct device *dev = subdrv->manager.dev;
503 struct exynos_drm_manager *manager = &subdrv->manager;
504 u32 val;
505
506 val = readl(ctx->regs + VIDINTCON1);
507
508 if (val & VIDINTCON1_INT_FRAME)
509 /* VSYNC interrupt */
510 writel(VIDINTCON1_INT_FRAME, ctx->regs + VIDINTCON1);
511
512 drm_handle_vblank(drm_dev, manager->pipe);
513 fimd_finish_pageflip(drm_dev, manager->pipe);
514
515 return IRQ_HANDLED;
516}
517
518static int fimd_subdrv_probe(struct drm_device *drm_dev)
519{
520 struct drm_driver *drm_driver = drm_dev->driver;
521
522 DRM_DEBUG_KMS("%s\n", __FILE__);
523
524 /*
525 * enable drm irq mode.
526 * - with irq_enabled = 1, we can use the vblank feature.
527 *
528 * P.S. note that we wouldn't use drm irq handler but
529 * just specific driver own one instead because
530 * drm framework supports only one irq handler.
531 */
532 drm_dev->irq_enabled = 1;
533
534 /*
535 * with vblank_disable_allowed = 1, vblank interrupt will be disabled
536 * by drm timer once a current process gives up ownership of
537 * vblank event.(drm_vblank_put function was called)
538 */
539 drm_dev->vblank_disable_allowed = 1;
540
541 return 0;
542}
543
544static void fimd_subdrv_remove(struct drm_device *drm_dev)
545{
546 struct drm_driver *drm_driver = drm_dev->driver;
547
548 DRM_DEBUG_KMS("%s\n", __FILE__);
549
550 /* TODO. */
551}
552
553static int fimd_calc_clkdiv(struct fimd_context *ctx,
554 struct fb_videomode *timing)
555{
556 unsigned long clk = clk_get_rate(ctx->lcd_clk);
557 u32 retrace;
558 u32 clkdiv;
559 u32 best_framerate = 0;
560 u32 framerate;
561
562 DRM_DEBUG_KMS("%s\n", __FILE__);
563
564 retrace = timing->left_margin + timing->hsync_len +
565 timing->right_margin + timing->xres;
566 retrace *= timing->upper_margin + timing->vsync_len +
567 timing->lower_margin + timing->yres;
568
569 /* default framerate is 60Hz */
570 if (!timing->refresh)
571 timing->refresh = 60;
572
573 clk /= retrace;
574
575 for (clkdiv = 1; clkdiv < 0x100; clkdiv++) {
576 int tmp;
577
578 /* get best framerate */
579 framerate = clk / clkdiv;
580 tmp = timing->refresh - framerate;
581 if (tmp < 0) {
582 best_framerate = framerate;
583 continue;
584 } else {
585 if (!best_framerate)
586 best_framerate = framerate;
587 else if (tmp < (best_framerate - framerate))
588 best_framerate = framerate;
589 break;
590 }
591 }
592
593 return clkdiv;
594}
595
596static void fimd_clear_win(struct fimd_context *ctx, int win)
597{
598 u32 val;
599
600 DRM_DEBUG_KMS("%s\n", __FILE__);
601
602 writel(0, ctx->regs + WINCON(win));
603 writel(0, ctx->regs + VIDOSD_A(win));
604 writel(0, ctx->regs + VIDOSD_B(win));
605 writel(0, ctx->regs + VIDOSD_C(win));
606
607 if (win == 1 || win == 2)
608 writel(0, ctx->regs + VIDOSD_D(win));
609
610 val = readl(ctx->regs + SHADOWCON);
611 val &= ~SHADOWCON_WINx_PROTECT(win);
612 writel(val, ctx->regs + SHADOWCON);
613}
614
615static int __devinit fimd_probe(struct platform_device *pdev)
616{
617 struct device *dev = &pdev->dev;
618 struct fimd_context *ctx;
619 struct exynos_drm_subdrv *subdrv;
620 struct exynos_drm_fimd_pdata *pdata;
621 struct fb_videomode *timing;
622 struct resource *res;
623 int win;
624 int ret = -EINVAL;
625
626 DRM_DEBUG_KMS("%s\n", __FILE__);
627
628 pdata = pdev->dev.platform_data;
629 if (!pdata) {
630 dev_err(dev, "no platform data specified\n");
631 return -EINVAL;
632 }
633
634 timing = &pdata->timing;
635 if (!timing) {
636 dev_err(dev, "timing is null.\n");
637 return -EINVAL;
638 }
639
640 ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
641 if (!ctx)
642 return -ENOMEM;
643
644 ctx->bus_clk = clk_get(dev, "fimd");
645 if (IS_ERR(ctx->bus_clk)) {
646 dev_err(dev, "failed to get bus clock\n");
647 ret = PTR_ERR(ctx->bus_clk);
648 goto err_clk_get;
649 }
650
651 clk_enable(ctx->bus_clk);
652
653 ctx->lcd_clk = clk_get(dev, "sclk_fimd");
654 if (IS_ERR(ctx->lcd_clk)) {
655 dev_err(dev, "failed to get lcd clock\n");
656 ret = PTR_ERR(ctx->lcd_clk);
657 goto err_bus_clk;
658 }
659
660 clk_enable(ctx->lcd_clk);
661
662 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
663 if (!res) {
664 dev_err(dev, "failed to find registers\n");
665 ret = -ENOENT;
666 goto err_clk;
667 }
668
669 ctx->regs_res = request_mem_region(res->start, resource_size(res),
670 dev_name(dev));
671 if (!ctx->regs_res) {
672 dev_err(dev, "failed to claim register region\n");
673 ret = -ENOENT;
674 goto err_clk;
675 }
676
677 ctx->regs = ioremap(res->start, resource_size(res));
678 if (!ctx->regs) {
679 dev_err(dev, "failed to map registers\n");
680 ret = -ENXIO;
681 goto err_req_region_io;
682 }
683
684 res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
685 if (!res) {
686 dev_err(dev, "irq request failed.\n");
687 goto err_req_region_irq;
688 }
689
690 ctx->irq = res->start;
691
692 for (win = 0; win < WINDOWS_NR; win++)
693 fimd_clear_win(ctx, win);
694
695 ret = request_irq(ctx->irq, fimd_irq_handler, 0, "drm_fimd", ctx);
696 if (ret < 0) {
697 dev_err(dev, "irq request failed.\n");
698 goto err_req_irq;
699 }
700
701 ctx->clkdiv = fimd_calc_clkdiv(ctx, timing);
702 ctx->vidcon0 = pdata->vidcon0;
703 ctx->vidcon1 = pdata->vidcon1;
704 ctx->default_win = pdata->default_win;
705 ctx->timing = timing;
706
707 timing->pixclock = clk_get_rate(ctx->lcd_clk) / ctx->clkdiv;
708
709 DRM_DEBUG_KMS("pixel clock = %d, clkdiv = %d\n",
710 timing->pixclock, ctx->clkdiv);
711
712 subdrv = &ctx->subdrv;
713
714 subdrv->probe = fimd_subdrv_probe;
715 subdrv->remove = fimd_subdrv_remove;
716 subdrv->manager.pipe = -1;
717 subdrv->manager.ops = &fimd_manager_ops;
718 subdrv->manager.overlay_ops = &fimd_overlay_ops;
719 subdrv->manager.display = &fimd_display;
720 subdrv->manager.dev = dev;
721
722 platform_set_drvdata(pdev, ctx);
723 exynos_drm_subdrv_register(subdrv);
724
725 return 0;
726
727err_req_irq:
728err_req_region_irq:
729 iounmap(ctx->regs);
730
731err_req_region_io:
732 release_resource(ctx->regs_res);
733 kfree(ctx->regs_res);
734
735err_clk:
736 clk_disable(ctx->lcd_clk);
737 clk_put(ctx->lcd_clk);
738
739err_bus_clk:
740 clk_disable(ctx->bus_clk);
741 clk_put(ctx->bus_clk);
742
743err_clk_get:
744 kfree(ctx);
745 return ret;
746}
747
748static int __devexit fimd_remove(struct platform_device *pdev)
749{
750 struct fimd_context *ctx = platform_get_drvdata(pdev);
751
752 DRM_DEBUG_KMS("%s\n", __FILE__);
753
754 exynos_drm_subdrv_unregister(&ctx->subdrv);
755
756 clk_disable(ctx->lcd_clk);
757 clk_disable(ctx->bus_clk);
758 clk_put(ctx->lcd_clk);
759 clk_put(ctx->bus_clk);
760
761 iounmap(ctx->regs);
762 release_resource(ctx->regs_res);
763 kfree(ctx->regs_res);
764 free_irq(ctx->irq, ctx);
765
766 kfree(ctx);
767
768 return 0;
769}
770
771static struct platform_driver fimd_driver = {
772 .probe = fimd_probe,
773 .remove = __devexit_p(fimd_remove),
774 .driver = {
775 .name = "exynos4-fb",
776 .owner = THIS_MODULE,
777 },
778};
779
780static int __init fimd_init(void)
781{
782 return platform_driver_register(&fimd_driver);
783}
784
785static void __exit fimd_exit(void)
786{
787 platform_driver_unregister(&fimd_driver);
788}
789
790module_init(fimd_init);
791module_exit(fimd_exit);
792
793MODULE_AUTHOR("Joonyoung Shim <jy0922.shim@samsung.com>");
794MODULE_AUTHOR("Inki Dae <inki.dae@samsung.com>");
795MODULE_DESCRIPTION("Samsung DRM FIMD Driver");
796MODULE_LICENSE("GPL");
diff --git a/drivers/gpu/drm/exynos/exynos_drm_gem.c b/drivers/gpu/drm/exynos/exynos_drm_gem.c
new file mode 100644
index 000000000000..a8e7a88906ed
--- /dev/null
+++ b/drivers/gpu/drm/exynos/exynos_drm_gem.c
@@ -0,0 +1,415 @@
1/* exynos_drm_gem.c
2 *
3 * Copyright (c) 2011 Samsung Electronics Co., Ltd.
4 * Author: 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#include "drmP.h"
27#include "drm.h"
28
29#include <drm/exynos_drm.h>
30
31#include "exynos_drm_drv.h"
32#include "exynos_drm_gem.h"
33#include "exynos_drm_buf.h"
34
35static unsigned int convert_to_vm_err_msg(int msg)
36{
37 unsigned int out_msg;
38
39 switch (msg) {
40 case 0:
41 case -ERESTARTSYS:
42 case -EINTR:
43 out_msg = VM_FAULT_NOPAGE;
44 break;
45
46 case -ENOMEM:
47 out_msg = VM_FAULT_OOM;
48 break;
49
50 default:
51 out_msg = VM_FAULT_SIGBUS;
52 break;
53 }
54
55 return out_msg;
56}
57
58static unsigned int get_gem_mmap_offset(struct drm_gem_object *obj)
59{
60 DRM_DEBUG_KMS("%s\n", __FILE__);
61
62 return (unsigned int)obj->map_list.hash.key << PAGE_SHIFT;
63}
64
65struct exynos_drm_gem_obj *exynos_drm_gem_create(struct drm_file *file_priv,
66 struct drm_device *dev, unsigned int size,
67 unsigned int *handle)
68{
69 struct exynos_drm_gem_obj *exynos_gem_obj;
70 struct exynos_drm_buf_entry *entry;
71 struct drm_gem_object *obj;
72 int ret;
73
74 DRM_DEBUG_KMS("%s\n", __FILE__);
75
76 size = roundup(size, PAGE_SIZE);
77
78 exynos_gem_obj = kzalloc(sizeof(*exynos_gem_obj), GFP_KERNEL);
79 if (!exynos_gem_obj) {
80 DRM_ERROR("failed to allocate exynos gem object.\n");
81 return ERR_PTR(-ENOMEM);
82 }
83
84 /* allocate the new buffer object and memory region. */
85 entry = exynos_drm_buf_create(dev, size);
86 if (!entry) {
87 kfree(exynos_gem_obj);
88 return ERR_PTR(-ENOMEM);
89 }
90
91 exynos_gem_obj->entry = entry;
92
93 obj = &exynos_gem_obj->base;
94
95 ret = drm_gem_object_init(dev, obj, size);
96 if (ret < 0) {
97 DRM_ERROR("failed to initailize gem object.\n");
98 goto err_obj_init;
99 }
100
101 DRM_DEBUG_KMS("created file object = 0x%x\n", (unsigned int)obj->filp);
102
103 ret = drm_gem_create_mmap_offset(obj);
104 if (ret < 0) {
105 DRM_ERROR("failed to allocate mmap offset.\n");
106 goto err_create_mmap_offset;
107 }
108
109 /*
110 * allocate a id of idr table where the obj is registered
111 * and handle has the id what user can see.
112 */
113 ret = drm_gem_handle_create(file_priv, obj, handle);
114 if (ret)
115 goto err_handle_create;
116
117 DRM_DEBUG_KMS("gem handle = 0x%x\n", *handle);
118
119 /* drop reference from allocate - handle holds it now. */
120 drm_gem_object_unreference_unlocked(obj);
121
122 return exynos_gem_obj;
123
124err_handle_create:
125 drm_gem_free_mmap_offset(obj);
126
127err_create_mmap_offset:
128 drm_gem_object_release(obj);
129
130err_obj_init:
131 exynos_drm_buf_destroy(dev, exynos_gem_obj->entry);
132
133 kfree(exynos_gem_obj);
134
135 return ERR_PTR(ret);
136}
137
138int exynos_drm_gem_create_ioctl(struct drm_device *dev, void *data,
139 struct drm_file *file_priv)
140{
141 struct drm_exynos_gem_create *args = data;
142 struct exynos_drm_gem_obj *exynos_gem_obj;
143
144 DRM_DEBUG_KMS("%s : size = 0x%x\n", __FILE__, args->size);
145
146 exynos_gem_obj = exynos_drm_gem_create(file_priv, dev, args->size,
147 &args->handle);
148 if (IS_ERR(exynos_gem_obj))
149 return PTR_ERR(exynos_gem_obj);
150
151 return 0;
152}
153
154int exynos_drm_gem_map_offset_ioctl(struct drm_device *dev, void *data,
155 struct drm_file *file_priv)
156{
157 struct drm_exynos_gem_map_off *args = data;
158
159 DRM_DEBUG_KMS("%s\n", __FILE__);
160
161 DRM_DEBUG_KMS("handle = 0x%x, offset = 0x%lx\n",
162 args->handle, (unsigned long)args->offset);
163
164 if (!(dev->driver->driver_features & DRIVER_GEM)) {
165 DRM_ERROR("does not support GEM.\n");
166 return -ENODEV;
167 }
168
169 return exynos_drm_gem_dumb_map_offset(file_priv, dev, args->handle,
170 &args->offset);
171}
172
173static int exynos_drm_gem_mmap_buffer(struct file *filp,
174 struct vm_area_struct *vma)
175{
176 struct drm_gem_object *obj = filp->private_data;
177 struct exynos_drm_gem_obj *exynos_gem_obj = to_exynos_gem_obj(obj);
178 struct exynos_drm_buf_entry *entry;
179 unsigned long pfn, vm_size;
180
181 DRM_DEBUG_KMS("%s\n", __FILE__);
182
183 vma->vm_flags |= (VM_IO | VM_RESERVED);
184
185 vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
186 vma->vm_file = filp;
187
188 vm_size = vma->vm_end - vma->vm_start;
189 /*
190 * a entry contains information to physically continuous memory
191 * allocated by user request or at framebuffer creation.
192 */
193 entry = exynos_gem_obj->entry;
194
195 /* check if user-requested size is valid. */
196 if (vm_size > entry->size)
197 return -EINVAL;
198
199 /*
200 * get page frame number to physical memory to be mapped
201 * to user space.
202 */
203 pfn = exynos_gem_obj->entry->paddr >> PAGE_SHIFT;
204
205 DRM_DEBUG_KMS("pfn = 0x%lx\n", pfn);
206
207 if (remap_pfn_range(vma, vma->vm_start, pfn, vm_size,
208 vma->vm_page_prot)) {
209 DRM_ERROR("failed to remap pfn range.\n");
210 return -EAGAIN;
211 }
212
213 return 0;
214}
215
216static const struct file_operations exynos_drm_gem_fops = {
217 .mmap = exynos_drm_gem_mmap_buffer,
218};
219
220int exynos_drm_gem_mmap_ioctl(struct drm_device *dev, void *data,
221 struct drm_file *file_priv)
222{
223 struct drm_exynos_gem_mmap *args = data;
224 struct drm_gem_object *obj;
225 unsigned int addr;
226
227 DRM_DEBUG_KMS("%s\n", __FILE__);
228
229 if (!(dev->driver->driver_features & DRIVER_GEM)) {
230 DRM_ERROR("does not support GEM.\n");
231 return -ENODEV;
232 }
233
234 obj = drm_gem_object_lookup(dev, file_priv, args->handle);
235 if (!obj) {
236 DRM_ERROR("failed to lookup gem object.\n");
237 return -EINVAL;
238 }
239
240 obj->filp->f_op = &exynos_drm_gem_fops;
241 obj->filp->private_data = obj;
242
243 down_write(&current->mm->mmap_sem);
244 addr = do_mmap(obj->filp, 0, args->size,
245 PROT_READ | PROT_WRITE, MAP_SHARED, 0);
246 up_write(&current->mm->mmap_sem);
247
248 drm_gem_object_unreference_unlocked(obj);
249
250 if (IS_ERR((void *)addr))
251 return PTR_ERR((void *)addr);
252
253 args->mapped = addr;
254
255 DRM_DEBUG_KMS("mapped = 0x%lx\n", (unsigned long)args->mapped);
256
257 return 0;
258}
259
260int exynos_drm_gem_init_object(struct drm_gem_object *obj)
261{
262 DRM_DEBUG_KMS("%s\n", __FILE__);
263
264 return 0;
265}
266
267void exynos_drm_gem_free_object(struct drm_gem_object *gem_obj)
268{
269 struct exynos_drm_gem_obj *exynos_gem_obj;
270
271 DRM_DEBUG_KMS("%s\n", __FILE__);
272
273 DRM_DEBUG_KMS("handle count = %d\n",
274 atomic_read(&gem_obj->handle_count));
275
276 if (gem_obj->map_list.map)
277 drm_gem_free_mmap_offset(gem_obj);
278
279 /* release file pointer to gem object. */
280 drm_gem_object_release(gem_obj);
281
282 exynos_gem_obj = to_exynos_gem_obj(gem_obj);
283
284 exynos_drm_buf_destroy(gem_obj->dev, exynos_gem_obj->entry);
285
286 kfree(exynos_gem_obj);
287}
288
289int exynos_drm_gem_dumb_create(struct drm_file *file_priv,
290 struct drm_device *dev, struct drm_mode_create_dumb *args)
291{
292 struct exynos_drm_gem_obj *exynos_gem_obj;
293
294 DRM_DEBUG_KMS("%s\n", __FILE__);
295
296 /*
297 * alocate memory to be used for framebuffer.
298 * - this callback would be called by user application
299 * with DRM_IOCTL_MODE_CREATE_DUMB command.
300 */
301
302 args->pitch = args->width * args->bpp >> 3;
303 args->size = args->pitch * args->height;
304
305 exynos_gem_obj = exynos_drm_gem_create(file_priv, dev, args->size,
306 &args->handle);
307 if (IS_ERR(exynos_gem_obj))
308 return PTR_ERR(exynos_gem_obj);
309
310 return 0;
311}
312
313int exynos_drm_gem_dumb_map_offset(struct drm_file *file_priv,
314 struct drm_device *dev, uint32_t handle, uint64_t *offset)
315{
316 struct exynos_drm_gem_obj *exynos_gem_obj;
317 struct drm_gem_object *obj;
318
319 DRM_DEBUG_KMS("%s\n", __FILE__);
320
321 mutex_lock(&dev->struct_mutex);
322
323 /*
324 * get offset of memory allocated for drm framebuffer.
325 * - this callback would be called by user application
326 * with DRM_IOCTL_MODE_MAP_DUMB command.
327 */
328
329 obj = drm_gem_object_lookup(dev, file_priv, handle);
330 if (!obj) {
331 DRM_ERROR("failed to lookup gem object.\n");
332 mutex_unlock(&dev->struct_mutex);
333 return -EINVAL;
334 }
335
336 exynos_gem_obj = to_exynos_gem_obj(obj);
337
338 *offset = get_gem_mmap_offset(&exynos_gem_obj->base);
339
340 drm_gem_object_unreference(obj);
341
342 DRM_DEBUG_KMS("offset = 0x%lx\n", (unsigned long)*offset);
343
344 mutex_unlock(&dev->struct_mutex);
345
346 return 0;
347}
348
349int exynos_drm_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
350{
351 struct drm_gem_object *obj = vma->vm_private_data;
352 struct exynos_drm_gem_obj *exynos_gem_obj = to_exynos_gem_obj(obj);
353 struct drm_device *dev = obj->dev;
354 unsigned long pfn;
355 pgoff_t page_offset;
356 int ret;
357
358 page_offset = ((unsigned long)vmf->virtual_address -
359 vma->vm_start) >> PAGE_SHIFT;
360
361 mutex_lock(&dev->struct_mutex);
362
363 pfn = (exynos_gem_obj->entry->paddr >> PAGE_SHIFT) + page_offset;
364
365 ret = vm_insert_mixed(vma, (unsigned long)vmf->virtual_address, pfn);
366
367 mutex_unlock(&dev->struct_mutex);
368
369 return convert_to_vm_err_msg(ret);
370}
371
372int exynos_drm_gem_mmap(struct file *filp, struct vm_area_struct *vma)
373{
374 int ret;
375
376 DRM_DEBUG_KMS("%s\n", __FILE__);
377
378 /* set vm_area_struct. */
379 ret = drm_gem_mmap(filp, vma);
380 if (ret < 0) {
381 DRM_ERROR("failed to mmap.\n");
382 return ret;
383 }
384
385 vma->vm_flags &= ~VM_PFNMAP;
386 vma->vm_flags |= VM_MIXEDMAP;
387
388 return ret;
389}
390
391
392int exynos_drm_gem_dumb_destroy(struct drm_file *file_priv,
393 struct drm_device *dev, unsigned int handle)
394{
395 int ret;
396
397 DRM_DEBUG_KMS("%s\n", __FILE__);
398
399 /*
400 * obj->refcount and obj->handle_count are decreased and
401 * if both them are 0 then exynos_drm_gem_free_object()
402 * would be called by callback to release resources.
403 */
404 ret = drm_gem_handle_delete(file_priv, handle);
405 if (ret < 0) {
406 DRM_ERROR("failed to delete drm_gem_handle.\n");
407 return ret;
408 }
409
410 return 0;
411}
412
413MODULE_AUTHOR("Inki Dae <inki.dae@samsung.com>");
414MODULE_DESCRIPTION("Samsung SoC DRM GEM Module");
415MODULE_LICENSE("GPL");
diff --git a/drivers/gpu/drm/exynos/exynos_drm_gem.h b/drivers/gpu/drm/exynos/exynos_drm_gem.h
new file mode 100644
index 000000000000..e5fc0148277b
--- /dev/null
+++ b/drivers/gpu/drm/exynos/exynos_drm_gem.h
@@ -0,0 +1,107 @@
1/* exynos_drm_gem.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_GEM_H_
27#define _EXYNOS_DRM_GEM_H_
28
29#define to_exynos_gem_obj(x) container_of(x,\
30 struct exynos_drm_gem_obj, base)
31
32/*
33 * exynos drm buffer structure.
34 *
35 * @base: a gem object.
36 * - a new handle to this gem object would be created
37 * by drm_gem_handle_create().
38 * @entry: pointer to exynos drm buffer entry object.
39 * - containing the information to physically
40 * continuous memory region allocated by user request
41 * or at framebuffer creation.
42 *
43 * P.S. this object would be transfered to user as kms_bo.handle so
44 * user can access the buffer through kms_bo.handle.
45 */
46struct exynos_drm_gem_obj {
47 struct drm_gem_object base;
48 struct exynos_drm_buf_entry *entry;
49};
50
51/* create a new buffer and get a new gem handle. */
52struct exynos_drm_gem_obj *exynos_drm_gem_create(struct drm_file *file_priv,
53 struct drm_device *dev, unsigned int size,
54 unsigned int *handle);
55
56/*
57 * request gem object creation and buffer allocation as the size
58 * that it is calculated with framebuffer information such as width,
59 * height and bpp.
60 */
61int exynos_drm_gem_create_ioctl(struct drm_device *dev, void *data,
62 struct drm_file *file_priv);
63
64/* get buffer offset to map to user space. */
65int exynos_drm_gem_map_offset_ioctl(struct drm_device *dev, void *data,
66 struct drm_file *file_priv);
67
68/* unmap a buffer from user space. */
69int exynos_drm_gem_munmap_ioctl(struct drm_device *dev, void *data,
70 struct drm_file *file_priv);
71
72/* initialize gem object. */
73int exynos_drm_gem_init_object(struct drm_gem_object *obj);
74
75/* free gem object. */
76void exynos_drm_gem_free_object(struct drm_gem_object *gem_obj);
77
78/* create memory region for drm framebuffer. */
79int exynos_drm_gem_dumb_create(struct drm_file *file_priv,
80 struct drm_device *dev, struct drm_mode_create_dumb *args);
81
82/* map memory region for drm framebuffer to user space. */
83int exynos_drm_gem_dumb_map_offset(struct drm_file *file_priv,
84 struct drm_device *dev, uint32_t handle, uint64_t *offset);
85
86/* page fault handler and mmap fault address(virtual) to physical memory. */
87int exynos_drm_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf);
88
89/*
90 * mmap the physically continuous memory that a gem object contains
91 * to user space.
92 */
93int exynos_drm_gem_mmap_ioctl(struct drm_device *dev, void *data,
94 struct drm_file *file_priv);
95
96/* set vm_flags and we can change the vm attribute to other one at here. */
97int exynos_drm_gem_mmap(struct file *filp, struct vm_area_struct *vma);
98
99/*
100 * destroy memory region allocated.
101 * - a gem handle and physical memory region pointed by a gem object
102 * would be released by drm_gem_handle_delete().
103 */
104int exynos_drm_gem_dumb_destroy(struct drm_file *file_priv,
105 struct drm_device *dev, unsigned int handle);
106
107#endif
diff --git a/include/drm/exynos_drm.h b/include/drm/exynos_drm.h
new file mode 100644
index 000000000000..874c4d271328
--- /dev/null
+++ b/include/drm/exynos_drm.h
@@ -0,0 +1,104 @@
1/* exynos_drm.h
2 *
3 * Copyright (c) 2011 Samsung Electronics Co., Ltd.
4 * Authors:
5 * Inki Dae <inki.dae@samsung.com>
6 * Joonyoung Shim <jy0922.shim@samsung.com>
7 * Seung-Woo Kim <sw0312.kim@samsung.com>
8 *
9 * Permission is hereby granted, free of charge, to any person obtaining a
10 * copy of this software and associated documentation files (the "Software"),
11 * to deal in the Software without restriction, including without limitation
12 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
13 * and/or sell copies of the Software, and to permit persons to whom the
14 * Software is furnished to do so, subject to the following conditions:
15 *
16 * The above copyright notice and this permission notice (including the next
17 * paragraph) shall be included in all copies or substantial portions of the
18 * Software.
19 *
20 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
23 * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
24 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
25 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
26 * OTHER DEALINGS IN THE SOFTWARE.
27 */
28
29#ifndef _EXYNOS_DRM_H_
30#define _EXYNOS_DRM_H_
31
32/**
33 * User-desired buffer creation information structure.
34 *
35 * @size: requested size for the object.
36 * - this size value would be page-aligned internally.
37 * @flags: user request for setting memory type or cache attributes.
38 * @handle: returned handle for the object.
39 */
40struct drm_exynos_gem_create {
41 unsigned int size;
42 unsigned int flags;
43 unsigned int handle;
44};
45
46/**
47 * A structure for getting buffer offset.
48 *
49 * @handle: a pointer to gem object created.
50 * @pad: just padding to be 64-bit aligned.
51 * @offset: relatived offset value of the memory region allocated.
52 * - this value should be set by user.
53 */
54struct drm_exynos_gem_map_off {
55 unsigned int handle;
56 unsigned int pad;
57 uint64_t offset;
58};
59
60/**
61 * A structure for mapping buffer.
62 *
63 * @handle: a handle to gem object created.
64 * @size: memory size to be mapped.
65 * @mapped: having user virtual address mmaped.
66 * - this variable would be filled by exynos gem module
67 * of kernel side with user virtual address which is allocated
68 * by do_mmap().
69 */
70struct drm_exynos_gem_mmap {
71 unsigned int handle;
72 unsigned int size;
73 uint64_t mapped;
74};
75
76#define DRM_EXYNOS_GEM_CREATE 0x00
77#define DRM_EXYNOS_GEM_MAP_OFFSET 0x01
78#define DRM_EXYNOS_GEM_MMAP 0x02
79
80#define DRM_IOCTL_EXYNOS_GEM_CREATE DRM_IOWR(DRM_COMMAND_BASE + \
81 DRM_EXYNOS_GEM_CREATE, struct drm_exynos_gem_create)
82
83#define DRM_IOCTL_EXYNOS_GEM_MAP_OFFSET DRM_IOWR(DRM_COMMAND_BASE + \
84 DRM_EXYNOS_GEM_MAP_OFFSET, struct drm_exynos_gem_map_off)
85
86#define DRM_IOCTL_EXYNOS_GEM_MMAP DRM_IOWR(DRM_COMMAND_BASE + \
87 DRM_EXYNOS_GEM_MMAP, struct drm_exynos_gem_mmap)
88
89/**
90 * Platform Specific Structure for DRM based FIMD.
91 *
92 * @timing: default video mode for initializing
93 * @default_win: default window layer number to be used for UI.
94 * @bpp: default bit per pixel.
95 */
96struct exynos_drm_fimd_pdata {
97 struct fb_videomode timing;
98 u32 vidcon0;
99 u32 vidcon1;
100 unsigned int default_win;
101 unsigned int bpp;
102};
103
104#endif