Commit d7f1642c90ab5eb2d7c48af0581c993094f97e1a
Committed by
Inki Dae
1 parent
8dcb96b628
Exists in
smarc-l5.0.0_1.0.0-ga
and in
5 other branches
drm/exynos: add G2D driver
Changelog v3: - use __u64 instead of pointer in ioctl struct. The G2D is a 2D graphic accelerator that supports Bit Block Transfer. This G2D driver is exynos drm specific and supports only G2D(version 4.1) of later Exynos series from Exynos4X12 because supporting DMA. The G2D is performed by two tasks simply. 1. Configures the rendering parameters, such as foreground color and coordinates data by setting the drawing context registers. 2. Start the rendering process by setting thre relevant command registers accordingly. The G2D version 4.1 supports DMA mode as host interface. User can make command list to reduce HOST(ARM) loads. The contents of The command list is setted to relevant registers of G2D by DMA. The command list is composed Header and command sets and Tail. - Header: The number of command set(4Bytes) - Command set: Register offset(4Bytes) + Register data(4Bytes) - Tail: Pointer of base address of the other command list(4Bytes) By Tail field, the G2D can process many command lists without halt at one go. The G2D has following the rendering pipeline. --> Primitive Drawing --> Rotation --> Clipping --> Bilinear Sampling --> Color Key --> ROP --> Mask Operation --> Alpha Blending --> Dithering --> FrameBuffer And supports various operations from the rendering pipeline. - copy - fast solid color fill - window clipping - rotation - flip - 4 operand raster operation(ROP4) - masking operation - alpha blending - color key - dithering - etc User should make the command list to data and registers needed by operation to use. The Exynos G2D driver only manages the command lists received from user. Some registers needs memory base address(physical address) of image. User doesn't know its physical address, so fills the gem handle of that memory than address to command sets, then G2D driver converts it to memory base address. We adds three ioctls and one event for Exynos G2D. - ioctls DRM_EXYNOS_G2D_GET_VER: get the G2D hardware version DRM_EXYNOS_G2D_SET_CMDLIST: set the command list from user to driver DRM_EXYNOS_G2D_EXEC: execute the command lists setted to driver - event DRM_EXYNOS_G2D_EVENT: event to give notification completion of the command list to user Signed-off-by: Joonyoung Shim <jy0922.shim@samsung.com> Signed-off-by: Inki Dae <inki.dae@samsung.com> Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
Showing 7 changed files with 1079 additions and 0 deletions Inline Diff
drivers/gpu/drm/exynos/Kconfig
1 | config DRM_EXYNOS | 1 | config DRM_EXYNOS |
2 | tristate "DRM Support for Samsung SoC EXYNOS Series" | 2 | tristate "DRM Support for Samsung SoC EXYNOS Series" |
3 | depends on DRM && PLAT_SAMSUNG | 3 | depends on DRM && PLAT_SAMSUNG |
4 | select DRM_KMS_HELPER | 4 | select DRM_KMS_HELPER |
5 | select FB_CFB_FILLRECT | 5 | select FB_CFB_FILLRECT |
6 | select FB_CFB_COPYAREA | 6 | select FB_CFB_COPYAREA |
7 | select FB_CFB_IMAGEBLIT | 7 | select FB_CFB_IMAGEBLIT |
8 | select VT_HW_CONSOLE_BINDING if FRAMEBUFFER_CONSOLE | 8 | select VT_HW_CONSOLE_BINDING if FRAMEBUFFER_CONSOLE |
9 | help | 9 | help |
10 | Choose this option if you have a Samsung SoC EXYNOS chipset. | 10 | Choose this option if you have a Samsung SoC EXYNOS chipset. |
11 | If M is selected the module will be called exynosdrm. | 11 | If M is selected the module will be called exynosdrm. |
12 | 12 | ||
13 | config DRM_EXYNOS_DMABUF | 13 | config DRM_EXYNOS_DMABUF |
14 | bool "EXYNOS DRM DMABUF" | 14 | bool "EXYNOS DRM DMABUF" |
15 | depends on DRM_EXYNOS | 15 | depends on DRM_EXYNOS |
16 | help | 16 | help |
17 | Choose this option if you want to use DMABUF feature for DRM. | 17 | Choose this option if you want to use DMABUF feature for DRM. |
18 | 18 | ||
19 | config DRM_EXYNOS_FIMD | 19 | config DRM_EXYNOS_FIMD |
20 | bool "Exynos DRM FIMD" | 20 | bool "Exynos DRM FIMD" |
21 | depends on DRM_EXYNOS && !FB_S3C | 21 | depends on DRM_EXYNOS && !FB_S3C |
22 | help | 22 | help |
23 | Choose this option if you want to use Exynos FIMD for DRM. | 23 | Choose this option if you want to use Exynos FIMD for DRM. |
24 | 24 | ||
25 | config DRM_EXYNOS_HDMI | 25 | config DRM_EXYNOS_HDMI |
26 | bool "Exynos DRM HDMI" | 26 | bool "Exynos DRM HDMI" |
27 | depends on DRM_EXYNOS && !VIDEO_SAMSUNG_S5P_TV | 27 | depends on DRM_EXYNOS && !VIDEO_SAMSUNG_S5P_TV |
28 | help | 28 | help |
29 | Choose this option if you want to use Exynos HDMI for DRM. | 29 | Choose this option if you want to use Exynos HDMI for DRM. |
30 | 30 | ||
31 | config DRM_EXYNOS_VIDI | 31 | config DRM_EXYNOS_VIDI |
32 | bool "Exynos DRM Virtual Display" | 32 | bool "Exynos DRM Virtual Display" |
33 | depends on DRM_EXYNOS | 33 | depends on DRM_EXYNOS |
34 | help | 34 | help |
35 | Choose this option if you want to use Exynos VIDI for DRM. | 35 | Choose this option if you want to use Exynos VIDI for DRM. |
36 | |||
37 | config DRM_EXYNOS_G2D | ||
38 | bool "Exynos DRM G2D" | ||
39 | depends on DRM_EXYNOS | ||
40 | help | ||
41 | Choose this option if you want to use Exynos G2D for DRM. | ||
36 | 42 |
drivers/gpu/drm/exynos/Makefile
1 | # | 1 | # |
2 | # Makefile for the drm device driver. This driver provides support for the | 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. | 3 | # Direct Rendering Infrastructure (DRI) in XFree86 4.1.0 and higher. |
4 | 4 | ||
5 | ccflags-y := -Iinclude/drm -Idrivers/gpu/drm/exynos | 5 | ccflags-y := -Iinclude/drm -Idrivers/gpu/drm/exynos |
6 | exynosdrm-y := exynos_drm_drv.o exynos_drm_encoder.o exynos_drm_connector.o \ | 6 | exynosdrm-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 \ | 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 \ | 8 | exynos_drm_buf.o exynos_drm_gem.o exynos_drm_core.o \ |
9 | exynos_drm_plane.o | 9 | exynos_drm_plane.o |
10 | 10 | ||
11 | exynosdrm-$(CONFIG_DRM_EXYNOS_DMABUF) += exynos_drm_dmabuf.o | 11 | exynosdrm-$(CONFIG_DRM_EXYNOS_DMABUF) += exynos_drm_dmabuf.o |
12 | exynosdrm-$(CONFIG_DRM_EXYNOS_FIMD) += exynos_drm_fimd.o | 12 | exynosdrm-$(CONFIG_DRM_EXYNOS_FIMD) += exynos_drm_fimd.o |
13 | exynosdrm-$(CONFIG_DRM_EXYNOS_HDMI) += exynos_hdmi.o exynos_mixer.o \ | 13 | exynosdrm-$(CONFIG_DRM_EXYNOS_HDMI) += exynos_hdmi.o exynos_mixer.o \ |
14 | exynos_ddc.o exynos_hdmiphy.o \ | 14 | exynos_ddc.o exynos_hdmiphy.o \ |
15 | exynos_drm_hdmi.o | 15 | exynos_drm_hdmi.o |
16 | exynosdrm-$(CONFIG_DRM_EXYNOS_VIDI) += exynos_drm_vidi.o | 16 | exynosdrm-$(CONFIG_DRM_EXYNOS_VIDI) += exynos_drm_vidi.o |
17 | exynosdrm-$(CONFIG_DRM_EXYNOS_G2D) += exynos_drm_g2d.o | ||
17 | 18 | ||
18 | obj-$(CONFIG_DRM_EXYNOS) += exynosdrm.o | 19 | obj-$(CONFIG_DRM_EXYNOS) += exynosdrm.o |
19 | 20 |
drivers/gpu/drm/exynos/exynos_drm_drv.c
1 | /* | 1 | /* |
2 | * Copyright (c) 2011 Samsung Electronics Co., Ltd. | 2 | * Copyright (c) 2011 Samsung Electronics Co., Ltd. |
3 | * Authors: | 3 | * Authors: |
4 | * Inki Dae <inki.dae@samsung.com> | 4 | * Inki Dae <inki.dae@samsung.com> |
5 | * Joonyoung Shim <jy0922.shim@samsung.com> | 5 | * Joonyoung Shim <jy0922.shim@samsung.com> |
6 | * Seung-Woo Kim <sw0312.kim@samsung.com> | 6 | * Seung-Woo Kim <sw0312.kim@samsung.com> |
7 | * | 7 | * |
8 | * Permission is hereby granted, free of charge, to any person obtaining a | 8 | * Permission is hereby granted, free of charge, to any person obtaining a |
9 | * copy of this software and associated documentation files (the "Software"), | 9 | * copy of this software and associated documentation files (the "Software"), |
10 | * to deal in the Software without restriction, including without limitation | 10 | * to deal in the Software without restriction, including without limitation |
11 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, | 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 | 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: | 13 | * Software is furnished to do so, subject to the following conditions: |
14 | * | 14 | * |
15 | * The above copyright notice and this permission notice (including the next | 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 | 16 | * paragraph) shall be included in all copies or substantial portions of the |
17 | * Software. | 17 | * Software. |
18 | * | 18 | * |
19 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | 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, | 20 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
21 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | 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 | 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, | 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 | 24 | * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR |
25 | * OTHER DEALINGS IN THE SOFTWARE. | 25 | * OTHER DEALINGS IN THE SOFTWARE. |
26 | */ | 26 | */ |
27 | 27 | ||
28 | #include "drmP.h" | 28 | #include "drmP.h" |
29 | #include "drm.h" | 29 | #include "drm.h" |
30 | #include "drm_crtc_helper.h" | 30 | #include "drm_crtc_helper.h" |
31 | 31 | ||
32 | #include <drm/exynos_drm.h> | 32 | #include <drm/exynos_drm.h> |
33 | 33 | ||
34 | #include "exynos_drm_drv.h" | 34 | #include "exynos_drm_drv.h" |
35 | #include "exynos_drm_crtc.h" | 35 | #include "exynos_drm_crtc.h" |
36 | #include "exynos_drm_encoder.h" | 36 | #include "exynos_drm_encoder.h" |
37 | #include "exynos_drm_fbdev.h" | 37 | #include "exynos_drm_fbdev.h" |
38 | #include "exynos_drm_fb.h" | 38 | #include "exynos_drm_fb.h" |
39 | #include "exynos_drm_gem.h" | 39 | #include "exynos_drm_gem.h" |
40 | #include "exynos_drm_plane.h" | 40 | #include "exynos_drm_plane.h" |
41 | #include "exynos_drm_vidi.h" | 41 | #include "exynos_drm_vidi.h" |
42 | #include "exynos_drm_dmabuf.h" | 42 | #include "exynos_drm_dmabuf.h" |
43 | #include "exynos_drm_g2d.h" | ||
43 | 44 | ||
44 | #define DRIVER_NAME "exynos" | 45 | #define DRIVER_NAME "exynos" |
45 | #define DRIVER_DESC "Samsung SoC DRM" | 46 | #define DRIVER_DESC "Samsung SoC DRM" |
46 | #define DRIVER_DATE "20110530" | 47 | #define DRIVER_DATE "20110530" |
47 | #define DRIVER_MAJOR 1 | 48 | #define DRIVER_MAJOR 1 |
48 | #define DRIVER_MINOR 0 | 49 | #define DRIVER_MINOR 0 |
49 | 50 | ||
50 | #define VBLANK_OFF_DELAY 50000 | 51 | #define VBLANK_OFF_DELAY 50000 |
51 | 52 | ||
52 | static int exynos_drm_load(struct drm_device *dev, unsigned long flags) | 53 | static int exynos_drm_load(struct drm_device *dev, unsigned long flags) |
53 | { | 54 | { |
54 | struct exynos_drm_private *private; | 55 | struct exynos_drm_private *private; |
55 | int ret; | 56 | int ret; |
56 | int nr; | 57 | int nr; |
57 | 58 | ||
58 | DRM_DEBUG_DRIVER("%s\n", __FILE__); | 59 | DRM_DEBUG_DRIVER("%s\n", __FILE__); |
59 | 60 | ||
60 | private = kzalloc(sizeof(struct exynos_drm_private), GFP_KERNEL); | 61 | private = kzalloc(sizeof(struct exynos_drm_private), GFP_KERNEL); |
61 | if (!private) { | 62 | if (!private) { |
62 | DRM_ERROR("failed to allocate private\n"); | 63 | DRM_ERROR("failed to allocate private\n"); |
63 | return -ENOMEM; | 64 | return -ENOMEM; |
64 | } | 65 | } |
65 | 66 | ||
66 | INIT_LIST_HEAD(&private->pageflip_event_list); | 67 | INIT_LIST_HEAD(&private->pageflip_event_list); |
67 | dev->dev_private = (void *)private; | 68 | dev->dev_private = (void *)private; |
68 | 69 | ||
69 | drm_mode_config_init(dev); | 70 | drm_mode_config_init(dev); |
70 | 71 | ||
71 | /* init kms poll for handling hpd */ | 72 | /* init kms poll for handling hpd */ |
72 | drm_kms_helper_poll_init(dev); | 73 | drm_kms_helper_poll_init(dev); |
73 | 74 | ||
74 | exynos_drm_mode_config_init(dev); | 75 | exynos_drm_mode_config_init(dev); |
75 | 76 | ||
76 | /* | 77 | /* |
77 | * EXYNOS4 is enough to have two CRTCs and each crtc would be used | 78 | * EXYNOS4 is enough to have two CRTCs and each crtc would be used |
78 | * without dependency of hardware. | 79 | * without dependency of hardware. |
79 | */ | 80 | */ |
80 | for (nr = 0; nr < MAX_CRTC; nr++) { | 81 | for (nr = 0; nr < MAX_CRTC; nr++) { |
81 | ret = exynos_drm_crtc_create(dev, nr); | 82 | ret = exynos_drm_crtc_create(dev, nr); |
82 | if (ret) | 83 | if (ret) |
83 | goto err_crtc; | 84 | goto err_crtc; |
84 | } | 85 | } |
85 | 86 | ||
86 | for (nr = 0; nr < MAX_PLANE; nr++) { | 87 | for (nr = 0; nr < MAX_PLANE; nr++) { |
87 | ret = exynos_plane_init(dev, nr); | 88 | ret = exynos_plane_init(dev, nr); |
88 | if (ret) | 89 | if (ret) |
89 | goto err_crtc; | 90 | goto err_crtc; |
90 | } | 91 | } |
91 | 92 | ||
92 | ret = drm_vblank_init(dev, MAX_CRTC); | 93 | ret = drm_vblank_init(dev, MAX_CRTC); |
93 | if (ret) | 94 | if (ret) |
94 | goto err_crtc; | 95 | goto err_crtc; |
95 | 96 | ||
96 | /* | 97 | /* |
97 | * probe sub drivers such as display controller and hdmi driver, | 98 | * probe sub drivers such as display controller and hdmi driver, |
98 | * that were registered at probe() of platform driver | 99 | * that were registered at probe() of platform driver |
99 | * to the sub driver and create encoder and connector for them. | 100 | * to the sub driver and create encoder and connector for them. |
100 | */ | 101 | */ |
101 | ret = exynos_drm_device_register(dev); | 102 | ret = exynos_drm_device_register(dev); |
102 | if (ret) | 103 | if (ret) |
103 | goto err_vblank; | 104 | goto err_vblank; |
104 | 105 | ||
105 | /* setup possible_clones. */ | 106 | /* setup possible_clones. */ |
106 | exynos_drm_encoder_setup(dev); | 107 | exynos_drm_encoder_setup(dev); |
107 | 108 | ||
108 | /* | 109 | /* |
109 | * create and configure fb helper and also exynos specific | 110 | * create and configure fb helper and also exynos specific |
110 | * fbdev object. | 111 | * fbdev object. |
111 | */ | 112 | */ |
112 | ret = exynos_drm_fbdev_init(dev); | 113 | ret = exynos_drm_fbdev_init(dev); |
113 | if (ret) { | 114 | if (ret) { |
114 | DRM_ERROR("failed to initialize drm fbdev\n"); | 115 | DRM_ERROR("failed to initialize drm fbdev\n"); |
115 | goto err_drm_device; | 116 | goto err_drm_device; |
116 | } | 117 | } |
117 | 118 | ||
118 | drm_vblank_offdelay = VBLANK_OFF_DELAY; | 119 | drm_vblank_offdelay = VBLANK_OFF_DELAY; |
119 | 120 | ||
120 | return 0; | 121 | return 0; |
121 | 122 | ||
122 | err_drm_device: | 123 | err_drm_device: |
123 | exynos_drm_device_unregister(dev); | 124 | exynos_drm_device_unregister(dev); |
124 | err_vblank: | 125 | err_vblank: |
125 | drm_vblank_cleanup(dev); | 126 | drm_vblank_cleanup(dev); |
126 | err_crtc: | 127 | err_crtc: |
127 | drm_mode_config_cleanup(dev); | 128 | drm_mode_config_cleanup(dev); |
128 | kfree(private); | 129 | kfree(private); |
129 | 130 | ||
130 | return ret; | 131 | return ret; |
131 | } | 132 | } |
132 | 133 | ||
133 | static int exynos_drm_unload(struct drm_device *dev) | 134 | static int exynos_drm_unload(struct drm_device *dev) |
134 | { | 135 | { |
135 | DRM_DEBUG_DRIVER("%s\n", __FILE__); | 136 | DRM_DEBUG_DRIVER("%s\n", __FILE__); |
136 | 137 | ||
137 | exynos_drm_fbdev_fini(dev); | 138 | exynos_drm_fbdev_fini(dev); |
138 | exynos_drm_device_unregister(dev); | 139 | exynos_drm_device_unregister(dev); |
139 | drm_vblank_cleanup(dev); | 140 | drm_vblank_cleanup(dev); |
140 | drm_kms_helper_poll_fini(dev); | 141 | drm_kms_helper_poll_fini(dev); |
141 | drm_mode_config_cleanup(dev); | 142 | drm_mode_config_cleanup(dev); |
142 | kfree(dev->dev_private); | 143 | kfree(dev->dev_private); |
143 | 144 | ||
144 | dev->dev_private = NULL; | 145 | dev->dev_private = NULL; |
145 | 146 | ||
146 | return 0; | 147 | return 0; |
147 | } | 148 | } |
148 | 149 | ||
149 | static int exynos_drm_open(struct drm_device *dev, struct drm_file *file) | 150 | static int exynos_drm_open(struct drm_device *dev, struct drm_file *file) |
150 | { | 151 | { |
152 | struct drm_exynos_file_private *file_priv; | ||
153 | |||
151 | DRM_DEBUG_DRIVER("%s\n", __FILE__); | 154 | DRM_DEBUG_DRIVER("%s\n", __FILE__); |
152 | 155 | ||
156 | file_priv = kzalloc(sizeof(*file_priv), GFP_KERNEL); | ||
157 | if (!file_priv) | ||
158 | return -ENOMEM; | ||
159 | |||
153 | drm_prime_init_file_private(&file->prime); | 160 | drm_prime_init_file_private(&file->prime); |
161 | file->driver_priv = file_priv; | ||
154 | 162 | ||
155 | return exynos_drm_subdrv_open(dev, file); | 163 | return exynos_drm_subdrv_open(dev, file); |
156 | } | 164 | } |
157 | 165 | ||
158 | static void exynos_drm_preclose(struct drm_device *dev, | 166 | static void exynos_drm_preclose(struct drm_device *dev, |
159 | struct drm_file *file) | 167 | struct drm_file *file) |
160 | { | 168 | { |
161 | struct exynos_drm_private *private = dev->dev_private; | 169 | struct exynos_drm_private *private = dev->dev_private; |
162 | struct drm_pending_vblank_event *e, *t; | 170 | struct drm_pending_vblank_event *e, *t; |
163 | unsigned long flags; | 171 | unsigned long flags; |
164 | 172 | ||
165 | DRM_DEBUG_DRIVER("%s\n", __FILE__); | 173 | DRM_DEBUG_DRIVER("%s\n", __FILE__); |
166 | 174 | ||
167 | /* release events of current file */ | 175 | /* release events of current file */ |
168 | spin_lock_irqsave(&dev->event_lock, flags); | 176 | spin_lock_irqsave(&dev->event_lock, flags); |
169 | list_for_each_entry_safe(e, t, &private->pageflip_event_list, | 177 | list_for_each_entry_safe(e, t, &private->pageflip_event_list, |
170 | base.link) { | 178 | base.link) { |
171 | if (e->base.file_priv == file) { | 179 | if (e->base.file_priv == file) { |
172 | list_del(&e->base.link); | 180 | list_del(&e->base.link); |
173 | e->base.destroy(&e->base); | 181 | e->base.destroy(&e->base); |
174 | } | 182 | } |
175 | } | 183 | } |
176 | drm_prime_destroy_file_private(&file->prime); | 184 | drm_prime_destroy_file_private(&file->prime); |
177 | spin_unlock_irqrestore(&dev->event_lock, flags); | 185 | spin_unlock_irqrestore(&dev->event_lock, flags); |
178 | 186 | ||
179 | exynos_drm_subdrv_close(dev, file); | 187 | exynos_drm_subdrv_close(dev, file); |
180 | } | 188 | } |
181 | 189 | ||
182 | static void exynos_drm_postclose(struct drm_device *dev, struct drm_file *file) | 190 | static void exynos_drm_postclose(struct drm_device *dev, struct drm_file *file) |
183 | { | 191 | { |
184 | DRM_DEBUG_DRIVER("%s\n", __FILE__); | 192 | DRM_DEBUG_DRIVER("%s\n", __FILE__); |
185 | 193 | ||
186 | if (!file->driver_priv) | 194 | if (!file->driver_priv) |
187 | return; | 195 | return; |
188 | 196 | ||
189 | kfree(file->driver_priv); | 197 | kfree(file->driver_priv); |
190 | file->driver_priv = NULL; | 198 | file->driver_priv = NULL; |
191 | } | 199 | } |
192 | 200 | ||
193 | static void exynos_drm_lastclose(struct drm_device *dev) | 201 | static void exynos_drm_lastclose(struct drm_device *dev) |
194 | { | 202 | { |
195 | DRM_DEBUG_DRIVER("%s\n", __FILE__); | 203 | DRM_DEBUG_DRIVER("%s\n", __FILE__); |
196 | 204 | ||
197 | exynos_drm_fbdev_restore_mode(dev); | 205 | exynos_drm_fbdev_restore_mode(dev); |
198 | } | 206 | } |
199 | 207 | ||
200 | static struct vm_operations_struct exynos_drm_gem_vm_ops = { | 208 | static struct vm_operations_struct exynos_drm_gem_vm_ops = { |
201 | .fault = exynos_drm_gem_fault, | 209 | .fault = exynos_drm_gem_fault, |
202 | .open = drm_gem_vm_open, | 210 | .open = drm_gem_vm_open, |
203 | .close = drm_gem_vm_close, | 211 | .close = drm_gem_vm_close, |
204 | }; | 212 | }; |
205 | 213 | ||
206 | static struct drm_ioctl_desc exynos_ioctls[] = { | 214 | static struct drm_ioctl_desc exynos_ioctls[] = { |
207 | DRM_IOCTL_DEF_DRV(EXYNOS_GEM_CREATE, exynos_drm_gem_create_ioctl, | 215 | DRM_IOCTL_DEF_DRV(EXYNOS_GEM_CREATE, exynos_drm_gem_create_ioctl, |
208 | DRM_UNLOCKED | DRM_AUTH), | 216 | DRM_UNLOCKED | DRM_AUTH), |
209 | DRM_IOCTL_DEF_DRV(EXYNOS_GEM_MAP_OFFSET, | 217 | DRM_IOCTL_DEF_DRV(EXYNOS_GEM_MAP_OFFSET, |
210 | exynos_drm_gem_map_offset_ioctl, DRM_UNLOCKED | | 218 | exynos_drm_gem_map_offset_ioctl, DRM_UNLOCKED | |
211 | DRM_AUTH), | 219 | DRM_AUTH), |
212 | DRM_IOCTL_DEF_DRV(EXYNOS_GEM_MMAP, | 220 | DRM_IOCTL_DEF_DRV(EXYNOS_GEM_MMAP, |
213 | exynos_drm_gem_mmap_ioctl, DRM_UNLOCKED | DRM_AUTH), | 221 | exynos_drm_gem_mmap_ioctl, DRM_UNLOCKED | DRM_AUTH), |
214 | DRM_IOCTL_DEF_DRV(EXYNOS_GEM_GET, | 222 | DRM_IOCTL_DEF_DRV(EXYNOS_GEM_GET, |
215 | exynos_drm_gem_get_ioctl, DRM_UNLOCKED), | 223 | exynos_drm_gem_get_ioctl, DRM_UNLOCKED), |
216 | DRM_IOCTL_DEF_DRV(EXYNOS_PLANE_SET_ZPOS, exynos_plane_set_zpos_ioctl, | 224 | DRM_IOCTL_DEF_DRV(EXYNOS_PLANE_SET_ZPOS, exynos_plane_set_zpos_ioctl, |
217 | DRM_UNLOCKED | DRM_AUTH), | 225 | DRM_UNLOCKED | DRM_AUTH), |
218 | DRM_IOCTL_DEF_DRV(EXYNOS_VIDI_CONNECTION, | 226 | DRM_IOCTL_DEF_DRV(EXYNOS_VIDI_CONNECTION, |
219 | vidi_connection_ioctl, DRM_UNLOCKED | DRM_AUTH), | 227 | vidi_connection_ioctl, DRM_UNLOCKED | DRM_AUTH), |
228 | DRM_IOCTL_DEF_DRV(EXYNOS_G2D_GET_VER, | ||
229 | exynos_g2d_get_ver_ioctl, DRM_UNLOCKED | DRM_AUTH), | ||
230 | DRM_IOCTL_DEF_DRV(EXYNOS_G2D_SET_CMDLIST, | ||
231 | exynos_g2d_set_cmdlist_ioctl, DRM_UNLOCKED | DRM_AUTH), | ||
232 | DRM_IOCTL_DEF_DRV(EXYNOS_G2D_EXEC, | ||
233 | exynos_g2d_exec_ioctl, DRM_UNLOCKED | DRM_AUTH), | ||
220 | }; | 234 | }; |
221 | 235 | ||
222 | static const struct file_operations exynos_drm_driver_fops = { | 236 | static const struct file_operations exynos_drm_driver_fops = { |
223 | .owner = THIS_MODULE, | 237 | .owner = THIS_MODULE, |
224 | .open = drm_open, | 238 | .open = drm_open, |
225 | .mmap = exynos_drm_gem_mmap, | 239 | .mmap = exynos_drm_gem_mmap, |
226 | .poll = drm_poll, | 240 | .poll = drm_poll, |
227 | .read = drm_read, | 241 | .read = drm_read, |
228 | .unlocked_ioctl = drm_ioctl, | 242 | .unlocked_ioctl = drm_ioctl, |
229 | .release = drm_release, | 243 | .release = drm_release, |
230 | }; | 244 | }; |
231 | 245 | ||
232 | static struct drm_driver exynos_drm_driver = { | 246 | static struct drm_driver exynos_drm_driver = { |
233 | .driver_features = DRIVER_HAVE_IRQ | DRIVER_BUS_PLATFORM | | 247 | .driver_features = DRIVER_HAVE_IRQ | DRIVER_BUS_PLATFORM | |
234 | DRIVER_MODESET | DRIVER_GEM | DRIVER_PRIME, | 248 | DRIVER_MODESET | DRIVER_GEM | DRIVER_PRIME, |
235 | .load = exynos_drm_load, | 249 | .load = exynos_drm_load, |
236 | .unload = exynos_drm_unload, | 250 | .unload = exynos_drm_unload, |
237 | .open = exynos_drm_open, | 251 | .open = exynos_drm_open, |
238 | .preclose = exynos_drm_preclose, | 252 | .preclose = exynos_drm_preclose, |
239 | .lastclose = exynos_drm_lastclose, | 253 | .lastclose = exynos_drm_lastclose, |
240 | .postclose = exynos_drm_postclose, | 254 | .postclose = exynos_drm_postclose, |
241 | .get_vblank_counter = drm_vblank_count, | 255 | .get_vblank_counter = drm_vblank_count, |
242 | .enable_vblank = exynos_drm_crtc_enable_vblank, | 256 | .enable_vblank = exynos_drm_crtc_enable_vblank, |
243 | .disable_vblank = exynos_drm_crtc_disable_vblank, | 257 | .disable_vblank = exynos_drm_crtc_disable_vblank, |
244 | .gem_init_object = exynos_drm_gem_init_object, | 258 | .gem_init_object = exynos_drm_gem_init_object, |
245 | .gem_free_object = exynos_drm_gem_free_object, | 259 | .gem_free_object = exynos_drm_gem_free_object, |
246 | .gem_vm_ops = &exynos_drm_gem_vm_ops, | 260 | .gem_vm_ops = &exynos_drm_gem_vm_ops, |
247 | .dumb_create = exynos_drm_gem_dumb_create, | 261 | .dumb_create = exynos_drm_gem_dumb_create, |
248 | .dumb_map_offset = exynos_drm_gem_dumb_map_offset, | 262 | .dumb_map_offset = exynos_drm_gem_dumb_map_offset, |
249 | .dumb_destroy = exynos_drm_gem_dumb_destroy, | 263 | .dumb_destroy = exynos_drm_gem_dumb_destroy, |
250 | .prime_handle_to_fd = drm_gem_prime_handle_to_fd, | 264 | .prime_handle_to_fd = drm_gem_prime_handle_to_fd, |
251 | .prime_fd_to_handle = drm_gem_prime_fd_to_handle, | 265 | .prime_fd_to_handle = drm_gem_prime_fd_to_handle, |
252 | .gem_prime_export = exynos_dmabuf_prime_export, | 266 | .gem_prime_export = exynos_dmabuf_prime_export, |
253 | .gem_prime_import = exynos_dmabuf_prime_import, | 267 | .gem_prime_import = exynos_dmabuf_prime_import, |
254 | .ioctls = exynos_ioctls, | 268 | .ioctls = exynos_ioctls, |
255 | .fops = &exynos_drm_driver_fops, | 269 | .fops = &exynos_drm_driver_fops, |
256 | .name = DRIVER_NAME, | 270 | .name = DRIVER_NAME, |
257 | .desc = DRIVER_DESC, | 271 | .desc = DRIVER_DESC, |
258 | .date = DRIVER_DATE, | 272 | .date = DRIVER_DATE, |
259 | .major = DRIVER_MAJOR, | 273 | .major = DRIVER_MAJOR, |
260 | .minor = DRIVER_MINOR, | 274 | .minor = DRIVER_MINOR, |
261 | }; | 275 | }; |
262 | 276 | ||
263 | static int exynos_drm_platform_probe(struct platform_device *pdev) | 277 | static int exynos_drm_platform_probe(struct platform_device *pdev) |
264 | { | 278 | { |
265 | DRM_DEBUG_DRIVER("%s\n", __FILE__); | 279 | DRM_DEBUG_DRIVER("%s\n", __FILE__); |
266 | 280 | ||
267 | exynos_drm_driver.num_ioctls = DRM_ARRAY_SIZE(exynos_ioctls); | 281 | exynos_drm_driver.num_ioctls = DRM_ARRAY_SIZE(exynos_ioctls); |
268 | 282 | ||
269 | return drm_platform_init(&exynos_drm_driver, pdev); | 283 | return drm_platform_init(&exynos_drm_driver, pdev); |
270 | } | 284 | } |
271 | 285 | ||
272 | static int exynos_drm_platform_remove(struct platform_device *pdev) | 286 | static int exynos_drm_platform_remove(struct platform_device *pdev) |
273 | { | 287 | { |
274 | DRM_DEBUG_DRIVER("%s\n", __FILE__); | 288 | DRM_DEBUG_DRIVER("%s\n", __FILE__); |
275 | 289 | ||
276 | drm_platform_exit(&exynos_drm_driver, pdev); | 290 | drm_platform_exit(&exynos_drm_driver, pdev); |
277 | 291 | ||
278 | return 0; | 292 | return 0; |
279 | } | 293 | } |
280 | 294 | ||
281 | static struct platform_driver exynos_drm_platform_driver = { | 295 | static struct platform_driver exynos_drm_platform_driver = { |
282 | .probe = exynos_drm_platform_probe, | 296 | .probe = exynos_drm_platform_probe, |
283 | .remove = __devexit_p(exynos_drm_platform_remove), | 297 | .remove = __devexit_p(exynos_drm_platform_remove), |
284 | .driver = { | 298 | .driver = { |
285 | .owner = THIS_MODULE, | 299 | .owner = THIS_MODULE, |
286 | .name = "exynos-drm", | 300 | .name = "exynos-drm", |
287 | }, | 301 | }, |
288 | }; | 302 | }; |
289 | 303 | ||
290 | static int __init exynos_drm_init(void) | 304 | static int __init exynos_drm_init(void) |
291 | { | 305 | { |
292 | int ret; | 306 | int ret; |
293 | 307 | ||
294 | DRM_DEBUG_DRIVER("%s\n", __FILE__); | 308 | DRM_DEBUG_DRIVER("%s\n", __FILE__); |
295 | 309 | ||
296 | #ifdef CONFIG_DRM_EXYNOS_FIMD | 310 | #ifdef CONFIG_DRM_EXYNOS_FIMD |
297 | ret = platform_driver_register(&fimd_driver); | 311 | ret = platform_driver_register(&fimd_driver); |
298 | if (ret < 0) | 312 | if (ret < 0) |
299 | goto out_fimd; | 313 | goto out_fimd; |
300 | #endif | 314 | #endif |
301 | 315 | ||
302 | #ifdef CONFIG_DRM_EXYNOS_HDMI | 316 | #ifdef CONFIG_DRM_EXYNOS_HDMI |
303 | ret = platform_driver_register(&hdmi_driver); | 317 | ret = platform_driver_register(&hdmi_driver); |
304 | if (ret < 0) | 318 | if (ret < 0) |
305 | goto out_hdmi; | 319 | goto out_hdmi; |
306 | ret = platform_driver_register(&mixer_driver); | 320 | ret = platform_driver_register(&mixer_driver); |
307 | if (ret < 0) | 321 | if (ret < 0) |
308 | goto out_mixer; | 322 | goto out_mixer; |
309 | ret = platform_driver_register(&exynos_drm_common_hdmi_driver); | 323 | ret = platform_driver_register(&exynos_drm_common_hdmi_driver); |
310 | if (ret < 0) | 324 | if (ret < 0) |
311 | goto out_common_hdmi; | 325 | goto out_common_hdmi; |
312 | #endif | 326 | #endif |
313 | 327 | ||
314 | #ifdef CONFIG_DRM_EXYNOS_VIDI | 328 | #ifdef CONFIG_DRM_EXYNOS_VIDI |
315 | ret = platform_driver_register(&vidi_driver); | 329 | ret = platform_driver_register(&vidi_driver); |
316 | if (ret < 0) | 330 | if (ret < 0) |
317 | goto out_vidi; | 331 | goto out_vidi; |
318 | #endif | 332 | #endif |
319 | 333 | ||
334 | #ifdef CONFIG_DRM_EXYNOS_G2D | ||
335 | ret = platform_driver_register(&g2d_driver); | ||
336 | if (ret < 0) | ||
337 | goto out_g2d; | ||
338 | #endif | ||
339 | |||
320 | ret = platform_driver_register(&exynos_drm_platform_driver); | 340 | ret = platform_driver_register(&exynos_drm_platform_driver); |
321 | if (ret < 0) | 341 | if (ret < 0) |
322 | goto out; | 342 | goto out; |
323 | 343 | ||
324 | return 0; | 344 | return 0; |
325 | 345 | ||
326 | out: | 346 | out: |
347 | #ifdef CONFIG_DRM_EXYNOS_G2D | ||
348 | platform_driver_unregister(&g2d_driver); | ||
349 | out_g2d: | ||
350 | #endif | ||
351 | |||
327 | #ifdef CONFIG_DRM_EXYNOS_VIDI | 352 | #ifdef CONFIG_DRM_EXYNOS_VIDI |
328 | out_vidi: | 353 | out_vidi: |
329 | platform_driver_unregister(&vidi_driver); | 354 | platform_driver_unregister(&vidi_driver); |
330 | #endif | 355 | #endif |
331 | 356 | ||
332 | #ifdef CONFIG_DRM_EXYNOS_HDMI | 357 | #ifdef CONFIG_DRM_EXYNOS_HDMI |
333 | platform_driver_unregister(&exynos_drm_common_hdmi_driver); | 358 | platform_driver_unregister(&exynos_drm_common_hdmi_driver); |
334 | out_common_hdmi: | 359 | out_common_hdmi: |
335 | platform_driver_unregister(&mixer_driver); | 360 | platform_driver_unregister(&mixer_driver); |
336 | out_mixer: | 361 | out_mixer: |
337 | platform_driver_unregister(&hdmi_driver); | 362 | platform_driver_unregister(&hdmi_driver); |
338 | out_hdmi: | 363 | out_hdmi: |
339 | #endif | 364 | #endif |
340 | 365 | ||
341 | #ifdef CONFIG_DRM_EXYNOS_FIMD | 366 | #ifdef CONFIG_DRM_EXYNOS_FIMD |
342 | platform_driver_unregister(&fimd_driver); | 367 | platform_driver_unregister(&fimd_driver); |
343 | out_fimd: | 368 | out_fimd: |
344 | #endif | 369 | #endif |
345 | return ret; | 370 | return ret; |
346 | } | 371 | } |
347 | 372 | ||
348 | static void __exit exynos_drm_exit(void) | 373 | static void __exit exynos_drm_exit(void) |
349 | { | 374 | { |
350 | DRM_DEBUG_DRIVER("%s\n", __FILE__); | 375 | DRM_DEBUG_DRIVER("%s\n", __FILE__); |
351 | 376 | ||
352 | platform_driver_unregister(&exynos_drm_platform_driver); | 377 | platform_driver_unregister(&exynos_drm_platform_driver); |
378 | |||
379 | #ifdef CONFIG_DRM_EXYNOS_G2D | ||
380 | platform_driver_unregister(&g2d_driver); | ||
381 | #endif | ||
353 | 382 | ||
354 | #ifdef CONFIG_DRM_EXYNOS_HDMI | 383 | #ifdef CONFIG_DRM_EXYNOS_HDMI |
355 | platform_driver_unregister(&exynos_drm_common_hdmi_driver); | 384 | platform_driver_unregister(&exynos_drm_common_hdmi_driver); |
356 | platform_driver_unregister(&mixer_driver); | 385 | platform_driver_unregister(&mixer_driver); |
357 | platform_driver_unregister(&hdmi_driver); | 386 | platform_driver_unregister(&hdmi_driver); |
358 | #endif | 387 | #endif |
359 | 388 | ||
360 | #ifdef CONFIG_DRM_EXYNOS_VIDI | 389 | #ifdef CONFIG_DRM_EXYNOS_VIDI |
361 | platform_driver_unregister(&vidi_driver); | 390 | platform_driver_unregister(&vidi_driver); |
362 | #endif | 391 | #endif |
363 | 392 | ||
364 | #ifdef CONFIG_DRM_EXYNOS_FIMD | 393 | #ifdef CONFIG_DRM_EXYNOS_FIMD |
365 | platform_driver_unregister(&fimd_driver); | 394 | platform_driver_unregister(&fimd_driver); |
366 | #endif | 395 | #endif |
367 | } | 396 | } |
368 | 397 | ||
369 | module_init(exynos_drm_init); | 398 | module_init(exynos_drm_init); |
370 | module_exit(exynos_drm_exit); | 399 | module_exit(exynos_drm_exit); |
371 | 400 | ||
372 | MODULE_AUTHOR("Inki Dae <inki.dae@samsung.com>"); | 401 | MODULE_AUTHOR("Inki Dae <inki.dae@samsung.com>"); |
373 | MODULE_AUTHOR("Joonyoung Shim <jy0922.shim@samsung.com>"); | 402 | MODULE_AUTHOR("Joonyoung Shim <jy0922.shim@samsung.com>"); |
374 | MODULE_AUTHOR("Seung-Woo Kim <sw0312.kim@samsung.com>"); | 403 | MODULE_AUTHOR("Seung-Woo Kim <sw0312.kim@samsung.com>"); |
375 | MODULE_DESCRIPTION("Samsung SoC DRM Driver"); | 404 | MODULE_DESCRIPTION("Samsung SoC DRM Driver"); |
376 | MODULE_LICENSE("GPL"); | 405 | MODULE_LICENSE("GPL"); |
377 | 406 |
drivers/gpu/drm/exynos/exynos_drm_drv.h
1 | /* exynos_drm_drv.h | 1 | /* exynos_drm_drv.h |
2 | * | 2 | * |
3 | * Copyright (c) 2011 Samsung Electronics Co., Ltd. | 3 | * Copyright (c) 2011 Samsung Electronics Co., Ltd. |
4 | * Authors: | 4 | * Authors: |
5 | * Inki Dae <inki.dae@samsung.com> | 5 | * Inki Dae <inki.dae@samsung.com> |
6 | * Joonyoung Shim <jy0922.shim@samsung.com> | 6 | * Joonyoung Shim <jy0922.shim@samsung.com> |
7 | * Seung-Woo Kim <sw0312.kim@samsung.com> | 7 | * Seung-Woo Kim <sw0312.kim@samsung.com> |
8 | * | 8 | * |
9 | * Permission is hereby granted, free of charge, to any person obtaining a | 9 | * Permission is hereby granted, free of charge, to any person obtaining a |
10 | * copy of this software and associated documentation files (the "Software"), | 10 | * copy of this software and associated documentation files (the "Software"), |
11 | * to deal in the Software without restriction, including without limitation | 11 | * to deal in the Software without restriction, including without limitation |
12 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, | 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 | 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: | 14 | * Software is furnished to do so, subject to the following conditions: |
15 | * | 15 | * |
16 | * The above copyright notice and this permission notice (including the next | 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 | 17 | * paragraph) shall be included in all copies or substantial portions of the |
18 | * Software. | 18 | * Software. |
19 | * | 19 | * |
20 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | 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, | 21 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
22 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | 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 | 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, | 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 | 25 | * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR |
26 | * OTHER DEALINGS IN THE SOFTWARE. | 26 | * OTHER DEALINGS IN THE SOFTWARE. |
27 | */ | 27 | */ |
28 | 28 | ||
29 | #ifndef _EXYNOS_DRM_DRV_H_ | 29 | #ifndef _EXYNOS_DRM_DRV_H_ |
30 | #define _EXYNOS_DRM_DRV_H_ | 30 | #define _EXYNOS_DRM_DRV_H_ |
31 | 31 | ||
32 | #include <linux/module.h> | 32 | #include <linux/module.h> |
33 | #include "drm.h" | 33 | #include "drm.h" |
34 | 34 | ||
35 | #define MAX_CRTC 3 | 35 | #define MAX_CRTC 3 |
36 | #define MAX_PLANE 5 | 36 | #define MAX_PLANE 5 |
37 | #define MAX_FB_BUFFER 4 | 37 | #define MAX_FB_BUFFER 4 |
38 | #define DEFAULT_ZPOS -1 | 38 | #define DEFAULT_ZPOS -1 |
39 | 39 | ||
40 | struct drm_device; | 40 | struct drm_device; |
41 | struct exynos_drm_overlay; | 41 | struct exynos_drm_overlay; |
42 | struct drm_connector; | 42 | struct drm_connector; |
43 | 43 | ||
44 | extern unsigned int drm_vblank_offdelay; | 44 | extern unsigned int drm_vblank_offdelay; |
45 | 45 | ||
46 | /* this enumerates display type. */ | 46 | /* this enumerates display type. */ |
47 | enum exynos_drm_output_type { | 47 | enum exynos_drm_output_type { |
48 | EXYNOS_DISPLAY_TYPE_NONE, | 48 | EXYNOS_DISPLAY_TYPE_NONE, |
49 | /* RGB or CPU Interface. */ | 49 | /* RGB or CPU Interface. */ |
50 | EXYNOS_DISPLAY_TYPE_LCD, | 50 | EXYNOS_DISPLAY_TYPE_LCD, |
51 | /* HDMI Interface. */ | 51 | /* HDMI Interface. */ |
52 | EXYNOS_DISPLAY_TYPE_HDMI, | 52 | EXYNOS_DISPLAY_TYPE_HDMI, |
53 | /* Virtual Display Interface. */ | 53 | /* Virtual Display Interface. */ |
54 | EXYNOS_DISPLAY_TYPE_VIDI, | 54 | EXYNOS_DISPLAY_TYPE_VIDI, |
55 | }; | 55 | }; |
56 | 56 | ||
57 | /* | 57 | /* |
58 | * Exynos drm overlay ops structure. | 58 | * Exynos drm overlay ops structure. |
59 | * | 59 | * |
60 | * @mode_set: copy drm overlay info to hw specific overlay info. | 60 | * @mode_set: copy drm overlay info to hw specific overlay info. |
61 | * @commit: apply hardware specific overlay data to registers. | 61 | * @commit: apply hardware specific overlay data to registers. |
62 | * @disable: disable hardware specific overlay. | 62 | * @disable: disable hardware specific overlay. |
63 | */ | 63 | */ |
64 | struct exynos_drm_overlay_ops { | 64 | struct exynos_drm_overlay_ops { |
65 | void (*mode_set)(struct device *subdrv_dev, | 65 | void (*mode_set)(struct device *subdrv_dev, |
66 | struct exynos_drm_overlay *overlay); | 66 | struct exynos_drm_overlay *overlay); |
67 | void (*commit)(struct device *subdrv_dev, int zpos); | 67 | void (*commit)(struct device *subdrv_dev, int zpos); |
68 | void (*disable)(struct device *subdrv_dev, int zpos); | 68 | void (*disable)(struct device *subdrv_dev, int zpos); |
69 | }; | 69 | }; |
70 | 70 | ||
71 | /* | 71 | /* |
72 | * Exynos drm common overlay structure. | 72 | * Exynos drm common overlay structure. |
73 | * | 73 | * |
74 | * @fb_x: offset x on a framebuffer to be displayed. | 74 | * @fb_x: offset x on a framebuffer to be displayed. |
75 | * - the unit is screen coordinates. | 75 | * - the unit is screen coordinates. |
76 | * @fb_y: offset y on a framebuffer to be displayed. | 76 | * @fb_y: offset y on a framebuffer to be displayed. |
77 | * - the unit is screen coordinates. | 77 | * - the unit is screen coordinates. |
78 | * @fb_width: width of a framebuffer. | 78 | * @fb_width: width of a framebuffer. |
79 | * @fb_height: height of a framebuffer. | 79 | * @fb_height: height of a framebuffer. |
80 | * @src_width: width of a partial image to be displayed from framebuffer. | 80 | * @src_width: width of a partial image to be displayed from framebuffer. |
81 | * @src_height: height of a partial image to be displayed from framebuffer. | 81 | * @src_height: height of a partial image to be displayed from framebuffer. |
82 | * @crtc_x: offset x on hardware screen. | 82 | * @crtc_x: offset x on hardware screen. |
83 | * @crtc_y: offset y on hardware screen. | 83 | * @crtc_y: offset y on hardware screen. |
84 | * @crtc_width: window width to be displayed (hardware screen). | 84 | * @crtc_width: window width to be displayed (hardware screen). |
85 | * @crtc_height: window height to be displayed (hardware screen). | 85 | * @crtc_height: window height to be displayed (hardware screen). |
86 | * @mode_width: width of screen mode. | 86 | * @mode_width: width of screen mode. |
87 | * @mode_height: height of screen mode. | 87 | * @mode_height: height of screen mode. |
88 | * @refresh: refresh rate. | 88 | * @refresh: refresh rate. |
89 | * @scan_flag: interlace or progressive way. | 89 | * @scan_flag: interlace or progressive way. |
90 | * (it could be DRM_MODE_FLAG_*) | 90 | * (it could be DRM_MODE_FLAG_*) |
91 | * @bpp: pixel size.(in bit) | 91 | * @bpp: pixel size.(in bit) |
92 | * @pixel_format: fourcc pixel format of this overlay | 92 | * @pixel_format: fourcc pixel format of this overlay |
93 | * @dma_addr: array of bus(accessed by dma) address to the memory region | 93 | * @dma_addr: array of bus(accessed by dma) address to the memory region |
94 | * allocated for a overlay. | 94 | * allocated for a overlay. |
95 | * @vaddr: array of virtual memory addresss to this overlay. | 95 | * @vaddr: array of virtual memory addresss to this overlay. |
96 | * @zpos: order of overlay layer(z position). | 96 | * @zpos: order of overlay layer(z position). |
97 | * @default_win: a window to be enabled. | 97 | * @default_win: a window to be enabled. |
98 | * @color_key: color key on or off. | 98 | * @color_key: color key on or off. |
99 | * @index_color: if using color key feature then this value would be used | 99 | * @index_color: if using color key feature then this value would be used |
100 | * as index color. | 100 | * as index color. |
101 | * @local_path: in case of lcd type, local path mode on or off. | 101 | * @local_path: in case of lcd type, local path mode on or off. |
102 | * @transparency: transparency on or off. | 102 | * @transparency: transparency on or off. |
103 | * @activated: activated or not. | 103 | * @activated: activated or not. |
104 | * | 104 | * |
105 | * this structure is common to exynos SoC and its contents would be copied | 105 | * this structure is common to exynos SoC and its contents would be copied |
106 | * to hardware specific overlay info. | 106 | * to hardware specific overlay info. |
107 | */ | 107 | */ |
108 | struct exynos_drm_overlay { | 108 | struct exynos_drm_overlay { |
109 | unsigned int fb_x; | 109 | unsigned int fb_x; |
110 | unsigned int fb_y; | 110 | unsigned int fb_y; |
111 | unsigned int fb_width; | 111 | unsigned int fb_width; |
112 | unsigned int fb_height; | 112 | unsigned int fb_height; |
113 | unsigned int src_width; | 113 | unsigned int src_width; |
114 | unsigned int src_height; | 114 | unsigned int src_height; |
115 | unsigned int crtc_x; | 115 | unsigned int crtc_x; |
116 | unsigned int crtc_y; | 116 | unsigned int crtc_y; |
117 | unsigned int crtc_width; | 117 | unsigned int crtc_width; |
118 | unsigned int crtc_height; | 118 | unsigned int crtc_height; |
119 | unsigned int mode_width; | 119 | unsigned int mode_width; |
120 | unsigned int mode_height; | 120 | unsigned int mode_height; |
121 | unsigned int refresh; | 121 | unsigned int refresh; |
122 | unsigned int scan_flag; | 122 | unsigned int scan_flag; |
123 | unsigned int bpp; | 123 | unsigned int bpp; |
124 | unsigned int pitch; | 124 | unsigned int pitch; |
125 | uint32_t pixel_format; | 125 | uint32_t pixel_format; |
126 | dma_addr_t dma_addr[MAX_FB_BUFFER]; | 126 | dma_addr_t dma_addr[MAX_FB_BUFFER]; |
127 | void __iomem *vaddr[MAX_FB_BUFFER]; | 127 | void __iomem *vaddr[MAX_FB_BUFFER]; |
128 | int zpos; | 128 | int zpos; |
129 | 129 | ||
130 | bool default_win; | 130 | bool default_win; |
131 | bool color_key; | 131 | bool color_key; |
132 | unsigned int index_color; | 132 | unsigned int index_color; |
133 | bool local_path; | 133 | bool local_path; |
134 | bool transparency; | 134 | bool transparency; |
135 | bool activated; | 135 | bool activated; |
136 | }; | 136 | }; |
137 | 137 | ||
138 | /* | 138 | /* |
139 | * Exynos DRM Display Structure. | 139 | * Exynos DRM Display Structure. |
140 | * - this structure is common to analog tv, digital tv and lcd panel. | 140 | * - this structure is common to analog tv, digital tv and lcd panel. |
141 | * | 141 | * |
142 | * @type: one of EXYNOS_DISPLAY_TYPE_LCD and HDMI. | 142 | * @type: one of EXYNOS_DISPLAY_TYPE_LCD and HDMI. |
143 | * @is_connected: check for that display is connected or not. | 143 | * @is_connected: check for that display is connected or not. |
144 | * @get_edid: get edid modes from display driver. | 144 | * @get_edid: get edid modes from display driver. |
145 | * @get_panel: get panel object from display driver. | 145 | * @get_panel: get panel object from display driver. |
146 | * @check_timing: check if timing is valid or not. | 146 | * @check_timing: check if timing is valid or not. |
147 | * @power_on: display device on or off. | 147 | * @power_on: display device on or off. |
148 | */ | 148 | */ |
149 | struct exynos_drm_display_ops { | 149 | struct exynos_drm_display_ops { |
150 | enum exynos_drm_output_type type; | 150 | enum exynos_drm_output_type type; |
151 | bool (*is_connected)(struct device *dev); | 151 | bool (*is_connected)(struct device *dev); |
152 | int (*get_edid)(struct device *dev, struct drm_connector *connector, | 152 | int (*get_edid)(struct device *dev, struct drm_connector *connector, |
153 | u8 *edid, int len); | 153 | u8 *edid, int len); |
154 | void *(*get_panel)(struct device *dev); | 154 | void *(*get_panel)(struct device *dev); |
155 | int (*check_timing)(struct device *dev, void *timing); | 155 | int (*check_timing)(struct device *dev, void *timing); |
156 | int (*power_on)(struct device *dev, int mode); | 156 | int (*power_on)(struct device *dev, int mode); |
157 | }; | 157 | }; |
158 | 158 | ||
159 | /* | 159 | /* |
160 | * Exynos drm manager ops | 160 | * Exynos drm manager ops |
161 | * | 161 | * |
162 | * @dpms: control device power. | 162 | * @dpms: control device power. |
163 | * @apply: set timing, vblank and overlay data to registers. | 163 | * @apply: set timing, vblank and overlay data to registers. |
164 | * @mode_fixup: fix mode data comparing to hw specific display mode. | 164 | * @mode_fixup: fix mode data comparing to hw specific display mode. |
165 | * @mode_set: convert drm_display_mode to hw specific display mode and | 165 | * @mode_set: convert drm_display_mode to hw specific display mode and |
166 | * would be called by encoder->mode_set(). | 166 | * would be called by encoder->mode_set(). |
167 | * @get_max_resol: get maximum resolution to specific hardware. | 167 | * @get_max_resol: get maximum resolution to specific hardware. |
168 | * @commit: set current hw specific display mode to hw. | 168 | * @commit: set current hw specific display mode to hw. |
169 | * @enable_vblank: specific driver callback for enabling vblank interrupt. | 169 | * @enable_vblank: specific driver callback for enabling vblank interrupt. |
170 | * @disable_vblank: specific driver callback for disabling vblank interrupt. | 170 | * @disable_vblank: specific driver callback for disabling vblank interrupt. |
171 | */ | 171 | */ |
172 | struct exynos_drm_manager_ops { | 172 | struct exynos_drm_manager_ops { |
173 | void (*dpms)(struct device *subdrv_dev, int mode); | 173 | void (*dpms)(struct device *subdrv_dev, int mode); |
174 | void (*apply)(struct device *subdrv_dev); | 174 | void (*apply)(struct device *subdrv_dev); |
175 | void (*mode_fixup)(struct device *subdrv_dev, | 175 | void (*mode_fixup)(struct device *subdrv_dev, |
176 | struct drm_connector *connector, | 176 | struct drm_connector *connector, |
177 | struct drm_display_mode *mode, | 177 | struct drm_display_mode *mode, |
178 | struct drm_display_mode *adjusted_mode); | 178 | struct drm_display_mode *adjusted_mode); |
179 | void (*mode_set)(struct device *subdrv_dev, void *mode); | 179 | void (*mode_set)(struct device *subdrv_dev, void *mode); |
180 | void (*get_max_resol)(struct device *subdrv_dev, unsigned int *width, | 180 | void (*get_max_resol)(struct device *subdrv_dev, unsigned int *width, |
181 | unsigned int *height); | 181 | unsigned int *height); |
182 | void (*commit)(struct device *subdrv_dev); | 182 | void (*commit)(struct device *subdrv_dev); |
183 | int (*enable_vblank)(struct device *subdrv_dev); | 183 | int (*enable_vblank)(struct device *subdrv_dev); |
184 | void (*disable_vblank)(struct device *subdrv_dev); | 184 | void (*disable_vblank)(struct device *subdrv_dev); |
185 | }; | 185 | }; |
186 | 186 | ||
187 | /* | 187 | /* |
188 | * Exynos drm common manager structure. | 188 | * Exynos drm common manager structure. |
189 | * | 189 | * |
190 | * @dev: pointer to device object for subdrv device driver. | 190 | * @dev: pointer to device object for subdrv device driver. |
191 | * sub drivers such as display controller or hdmi driver, | 191 | * sub drivers such as display controller or hdmi driver, |
192 | * have their own device object. | 192 | * have their own device object. |
193 | * @ops: pointer to callbacks for exynos drm specific framebuffer. | 193 | * @ops: pointer to callbacks for exynos drm specific framebuffer. |
194 | * these callbacks should be set by specific drivers such fimd | 194 | * these callbacks should be set by specific drivers such fimd |
195 | * or hdmi driver and are used to control hardware global registers. | 195 | * or hdmi driver and are used to control hardware global registers. |
196 | * @overlay_ops: pointer to callbacks for exynos drm specific framebuffer. | 196 | * @overlay_ops: pointer to callbacks for exynos drm specific framebuffer. |
197 | * these callbacks should be set by specific drivers such fimd | 197 | * these callbacks should be set by specific drivers such fimd |
198 | * or hdmi driver and are used to control hardware overlay reigsters. | 198 | * or hdmi driver and are used to control hardware overlay reigsters. |
199 | * @display: pointer to callbacks for exynos drm specific framebuffer. | 199 | * @display: pointer to callbacks for exynos drm specific framebuffer. |
200 | * these callbacks should be set by specific drivers such fimd | 200 | * these callbacks should be set by specific drivers such fimd |
201 | * or hdmi driver and are used to control display devices such as | 201 | * or hdmi driver and are used to control display devices such as |
202 | * analog tv, digital tv and lcd panel and also get timing data for them. | 202 | * analog tv, digital tv and lcd panel and also get timing data for them. |
203 | */ | 203 | */ |
204 | struct exynos_drm_manager { | 204 | struct exynos_drm_manager { |
205 | struct device *dev; | 205 | struct device *dev; |
206 | int pipe; | 206 | int pipe; |
207 | struct exynos_drm_manager_ops *ops; | 207 | struct exynos_drm_manager_ops *ops; |
208 | struct exynos_drm_overlay_ops *overlay_ops; | 208 | struct exynos_drm_overlay_ops *overlay_ops; |
209 | struct exynos_drm_display_ops *display_ops; | 209 | struct exynos_drm_display_ops *display_ops; |
210 | }; | 210 | }; |
211 | 211 | ||
212 | struct exynos_drm_g2d_private { | ||
213 | struct device *dev; | ||
214 | struct list_head inuse_cmdlist; | ||
215 | struct list_head event_list; | ||
216 | struct list_head gem_list; | ||
217 | unsigned int gem_nr; | ||
218 | }; | ||
219 | |||
220 | struct drm_exynos_file_private { | ||
221 | struct exynos_drm_g2d_private *g2d_priv; | ||
222 | }; | ||
223 | |||
212 | /* | 224 | /* |
213 | * Exynos drm private structure. | 225 | * Exynos drm private structure. |
214 | */ | 226 | */ |
215 | struct exynos_drm_private { | 227 | struct exynos_drm_private { |
216 | struct drm_fb_helper *fb_helper; | 228 | struct drm_fb_helper *fb_helper; |
217 | 229 | ||
218 | /* list head for new event to be added. */ | 230 | /* list head for new event to be added. */ |
219 | struct list_head pageflip_event_list; | 231 | struct list_head pageflip_event_list; |
220 | 232 | ||
221 | /* | 233 | /* |
222 | * created crtc object would be contained at this array and | 234 | * created crtc object would be contained at this array and |
223 | * this array is used to be aware of which crtc did it request vblank. | 235 | * this array is used to be aware of which crtc did it request vblank. |
224 | */ | 236 | */ |
225 | struct drm_crtc *crtc[MAX_CRTC]; | 237 | struct drm_crtc *crtc[MAX_CRTC]; |
226 | }; | 238 | }; |
227 | 239 | ||
228 | /* | 240 | /* |
229 | * Exynos drm sub driver structure. | 241 | * Exynos drm sub driver structure. |
230 | * | 242 | * |
231 | * @list: sub driver has its own list object to register to exynos drm driver. | 243 | * @list: sub driver has its own list object to register to exynos drm driver. |
232 | * @dev: pointer to device object for subdrv device driver. | 244 | * @dev: pointer to device object for subdrv device driver. |
233 | * @drm_dev: pointer to drm_device and this pointer would be set | 245 | * @drm_dev: pointer to drm_device and this pointer would be set |
234 | * when sub driver calls exynos_drm_subdrv_register(). | 246 | * when sub driver calls exynos_drm_subdrv_register(). |
235 | * @manager: subdrv has its own manager to control a hardware appropriately | 247 | * @manager: subdrv has its own manager to control a hardware appropriately |
236 | * and we can access a hardware drawing on this manager. | 248 | * and we can access a hardware drawing on this manager. |
237 | * @probe: this callback would be called by exynos drm driver after | 249 | * @probe: this callback would be called by exynos drm driver after |
238 | * subdrv is registered to it. | 250 | * subdrv is registered to it. |
239 | * @remove: this callback is used to release resources created | 251 | * @remove: this callback is used to release resources created |
240 | * by probe callback. | 252 | * by probe callback. |
241 | * @open: this would be called with drm device file open. | 253 | * @open: this would be called with drm device file open. |
242 | * @close: this would be called with drm device file close. | 254 | * @close: this would be called with drm device file close. |
243 | * @encoder: encoder object owned by this sub driver. | 255 | * @encoder: encoder object owned by this sub driver. |
244 | * @connector: connector object owned by this sub driver. | 256 | * @connector: connector object owned by this sub driver. |
245 | */ | 257 | */ |
246 | struct exynos_drm_subdrv { | 258 | struct exynos_drm_subdrv { |
247 | struct list_head list; | 259 | struct list_head list; |
248 | struct device *dev; | 260 | struct device *dev; |
249 | struct drm_device *drm_dev; | 261 | struct drm_device *drm_dev; |
250 | struct exynos_drm_manager *manager; | 262 | struct exynos_drm_manager *manager; |
251 | 263 | ||
252 | int (*probe)(struct drm_device *drm_dev, struct device *dev); | 264 | int (*probe)(struct drm_device *drm_dev, struct device *dev); |
253 | void (*remove)(struct drm_device *dev); | 265 | void (*remove)(struct drm_device *dev); |
254 | int (*open)(struct drm_device *drm_dev, struct device *dev, | 266 | int (*open)(struct drm_device *drm_dev, struct device *dev, |
255 | struct drm_file *file); | 267 | struct drm_file *file); |
256 | void (*close)(struct drm_device *drm_dev, struct device *dev, | 268 | void (*close)(struct drm_device *drm_dev, struct device *dev, |
257 | struct drm_file *file); | 269 | struct drm_file *file); |
258 | 270 | ||
259 | struct drm_encoder *encoder; | 271 | struct drm_encoder *encoder; |
260 | struct drm_connector *connector; | 272 | struct drm_connector *connector; |
261 | }; | 273 | }; |
262 | 274 | ||
263 | /* | 275 | /* |
264 | * this function calls a probe callback registered to sub driver list and | 276 | * this function calls a probe callback registered to sub driver list and |
265 | * create its own encoder and connector and then set drm_device object | 277 | * create its own encoder and connector and then set drm_device object |
266 | * to global one. | 278 | * to global one. |
267 | */ | 279 | */ |
268 | int exynos_drm_device_register(struct drm_device *dev); | 280 | int exynos_drm_device_register(struct drm_device *dev); |
269 | /* | 281 | /* |
270 | * this function calls a remove callback registered to sub driver list and | 282 | * this function calls a remove callback registered to sub driver list and |
271 | * destroy its own encoder and connetor. | 283 | * destroy its own encoder and connetor. |
272 | */ | 284 | */ |
273 | int exynos_drm_device_unregister(struct drm_device *dev); | 285 | int exynos_drm_device_unregister(struct drm_device *dev); |
274 | 286 | ||
275 | /* | 287 | /* |
276 | * this function would be called by sub drivers such as display controller | 288 | * this function would be called by sub drivers such as display controller |
277 | * or hdmi driver to register this sub driver object to exynos drm driver | 289 | * or hdmi driver to register this sub driver object to exynos drm driver |
278 | * and when a sub driver is registered to exynos drm driver a probe callback | 290 | * and when a sub driver is registered to exynos drm driver a probe callback |
279 | * of the sub driver is called and creates its own encoder and connector. | 291 | * of the sub driver is called and creates its own encoder and connector. |
280 | */ | 292 | */ |
281 | int exynos_drm_subdrv_register(struct exynos_drm_subdrv *drm_subdrv); | 293 | int exynos_drm_subdrv_register(struct exynos_drm_subdrv *drm_subdrv); |
282 | 294 | ||
283 | /* this function removes subdrv list from exynos drm driver */ | 295 | /* this function removes subdrv list from exynos drm driver */ |
284 | int exynos_drm_subdrv_unregister(struct exynos_drm_subdrv *drm_subdrv); | 296 | int exynos_drm_subdrv_unregister(struct exynos_drm_subdrv *drm_subdrv); |
285 | 297 | ||
286 | int exynos_drm_subdrv_open(struct drm_device *dev, struct drm_file *file); | 298 | int exynos_drm_subdrv_open(struct drm_device *dev, struct drm_file *file); |
287 | void exynos_drm_subdrv_close(struct drm_device *dev, struct drm_file *file); | 299 | void exynos_drm_subdrv_close(struct drm_device *dev, struct drm_file *file); |
288 | 300 | ||
289 | extern struct platform_driver fimd_driver; | 301 | extern struct platform_driver fimd_driver; |
290 | extern struct platform_driver hdmi_driver; | 302 | extern struct platform_driver hdmi_driver; |
291 | extern struct platform_driver mixer_driver; | 303 | extern struct platform_driver mixer_driver; |
292 | extern struct platform_driver exynos_drm_common_hdmi_driver; | 304 | extern struct platform_driver exynos_drm_common_hdmi_driver; |
293 | extern struct platform_driver vidi_driver; | 305 | extern struct platform_driver vidi_driver; |
306 | extern struct platform_driver g2d_driver; | ||
294 | #endif | 307 | #endif |
295 | 308 |
drivers/gpu/drm/exynos/exynos_drm_g2d.c
File was created | 1 | /* | |
2 | * Copyright (C) 2012 Samsung Electronics Co.Ltd | ||
3 | * Authors: Joonyoung Shim <jy0922.shim@samsung.com> | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify | ||
6 | * it under the terms of the GNU General Public License version 2 as | ||
7 | * published by the Free Software Foundationr | ||
8 | */ | ||
9 | |||
10 | #include <linux/kernel.h> | ||
11 | #include <linux/module.h> | ||
12 | #include <linux/clk.h> | ||
13 | #include <linux/err.h> | ||
14 | #include <linux/interrupt.h> | ||
15 | #include <linux/io.h> | ||
16 | #include <linux/platform_device.h> | ||
17 | #include <linux/pm_runtime.h> | ||
18 | #include <linux/slab.h> | ||
19 | #include <linux/workqueue.h> | ||
20 | |||
21 | #include "drmP.h" | ||
22 | #include "exynos_drm.h" | ||
23 | #include "exynos_drm_drv.h" | ||
24 | #include "exynos_drm_gem.h" | ||
25 | |||
26 | #define G2D_HW_MAJOR_VER 4 | ||
27 | #define G2D_HW_MINOR_VER 1 | ||
28 | |||
29 | /* vaild register range set from user: 0x0104 ~ 0x0880 */ | ||
30 | #define G2D_VALID_START 0x0104 | ||
31 | #define G2D_VALID_END 0x0880 | ||
32 | |||
33 | /* general registers */ | ||
34 | #define G2D_SOFT_RESET 0x0000 | ||
35 | #define G2D_INTEN 0x0004 | ||
36 | #define G2D_INTC_PEND 0x000C | ||
37 | #define G2D_DMA_SFR_BASE_ADDR 0x0080 | ||
38 | #define G2D_DMA_COMMAND 0x0084 | ||
39 | #define G2D_DMA_STATUS 0x008C | ||
40 | #define G2D_DMA_HOLD_CMD 0x0090 | ||
41 | |||
42 | /* command registers */ | ||
43 | #define G2D_BITBLT_START 0x0100 | ||
44 | |||
45 | /* registers for base address */ | ||
46 | #define G2D_SRC_BASE_ADDR 0x0304 | ||
47 | #define G2D_SRC_PLANE2_BASE_ADDR 0x0318 | ||
48 | #define G2D_DST_BASE_ADDR 0x0404 | ||
49 | #define G2D_DST_PLANE2_BASE_ADDR 0x0418 | ||
50 | #define G2D_PAT_BASE_ADDR 0x0500 | ||
51 | #define G2D_MSK_BASE_ADDR 0x0520 | ||
52 | |||
53 | /* G2D_SOFT_RESET */ | ||
54 | #define G2D_SFRCLEAR (1 << 1) | ||
55 | #define G2D_R (1 << 0) | ||
56 | |||
57 | /* G2D_INTEN */ | ||
58 | #define G2D_INTEN_ACF (1 << 3) | ||
59 | #define G2D_INTEN_UCF (1 << 2) | ||
60 | #define G2D_INTEN_GCF (1 << 1) | ||
61 | #define G2D_INTEN_SCF (1 << 0) | ||
62 | |||
63 | /* G2D_INTC_PEND */ | ||
64 | #define G2D_INTP_ACMD_FIN (1 << 3) | ||
65 | #define G2D_INTP_UCMD_FIN (1 << 2) | ||
66 | #define G2D_INTP_GCMD_FIN (1 << 1) | ||
67 | #define G2D_INTP_SCMD_FIN (1 << 0) | ||
68 | |||
69 | /* G2D_DMA_COMMAND */ | ||
70 | #define G2D_DMA_HALT (1 << 2) | ||
71 | #define G2D_DMA_CONTINUE (1 << 1) | ||
72 | #define G2D_DMA_START (1 << 0) | ||
73 | |||
74 | /* G2D_DMA_STATUS */ | ||
75 | #define G2D_DMA_LIST_DONE_COUNT (0xFF << 17) | ||
76 | #define G2D_DMA_BITBLT_DONE_COUNT (0xFFFF << 1) | ||
77 | #define G2D_DMA_DONE (1 << 0) | ||
78 | #define G2D_DMA_LIST_DONE_COUNT_OFFSET 17 | ||
79 | |||
80 | /* G2D_DMA_HOLD_CMD */ | ||
81 | #define G2D_USET_HOLD (1 << 2) | ||
82 | #define G2D_LIST_HOLD (1 << 1) | ||
83 | #define G2D_BITBLT_HOLD (1 << 0) | ||
84 | |||
85 | /* G2D_BITBLT_START */ | ||
86 | #define G2D_START_CASESEL (1 << 2) | ||
87 | #define G2D_START_NHOLT (1 << 1) | ||
88 | #define G2D_START_BITBLT (1 << 0) | ||
89 | |||
90 | #define G2D_CMDLIST_SIZE (PAGE_SIZE / 4) | ||
91 | #define G2D_CMDLIST_NUM 64 | ||
92 | #define G2D_CMDLIST_POOL_SIZE (G2D_CMDLIST_SIZE * G2D_CMDLIST_NUM) | ||
93 | #define G2D_CMDLIST_DATA_NUM (G2D_CMDLIST_SIZE / sizeof(u32) - 2) | ||
94 | |||
95 | /* cmdlist data structure */ | ||
96 | struct g2d_cmdlist { | ||
97 | u32 head; | ||
98 | u32 data[G2D_CMDLIST_DATA_NUM]; | ||
99 | u32 last; /* last data offset */ | ||
100 | }; | ||
101 | |||
102 | struct drm_exynos_pending_g2d_event { | ||
103 | struct drm_pending_event base; | ||
104 | struct drm_exynos_g2d_event event; | ||
105 | }; | ||
106 | |||
107 | struct g2d_gem_node { | ||
108 | struct list_head list; | ||
109 | unsigned int handle; | ||
110 | }; | ||
111 | |||
112 | struct g2d_cmdlist_node { | ||
113 | struct list_head list; | ||
114 | struct g2d_cmdlist *cmdlist; | ||
115 | unsigned int gem_nr; | ||
116 | dma_addr_t dma_addr; | ||
117 | |||
118 | struct drm_exynos_pending_g2d_event *event; | ||
119 | }; | ||
120 | |||
121 | struct g2d_runqueue_node { | ||
122 | struct list_head list; | ||
123 | struct list_head run_cmdlist; | ||
124 | struct list_head event_list; | ||
125 | struct completion complete; | ||
126 | int async; | ||
127 | }; | ||
128 | |||
129 | struct g2d_data { | ||
130 | struct device *dev; | ||
131 | struct clk *gate_clk; | ||
132 | struct resource *regs_res; | ||
133 | void __iomem *regs; | ||
134 | int irq; | ||
135 | struct workqueue_struct *g2d_workq; | ||
136 | struct work_struct runqueue_work; | ||
137 | struct exynos_drm_subdrv subdrv; | ||
138 | bool suspended; | ||
139 | |||
140 | /* cmdlist */ | ||
141 | struct g2d_cmdlist_node *cmdlist_node; | ||
142 | struct list_head free_cmdlist; | ||
143 | struct mutex cmdlist_mutex; | ||
144 | dma_addr_t cmdlist_pool; | ||
145 | void *cmdlist_pool_virt; | ||
146 | |||
147 | /* runqueue*/ | ||
148 | struct g2d_runqueue_node *runqueue_node; | ||
149 | struct list_head runqueue; | ||
150 | struct mutex runqueue_mutex; | ||
151 | struct kmem_cache *runqueue_slab; | ||
152 | }; | ||
153 | |||
154 | static int g2d_init_cmdlist(struct g2d_data *g2d) | ||
155 | { | ||
156 | struct device *dev = g2d->dev; | ||
157 | struct g2d_cmdlist_node *node = g2d->cmdlist_node; | ||
158 | int nr; | ||
159 | int ret; | ||
160 | |||
161 | g2d->cmdlist_pool_virt = dma_alloc_coherent(dev, G2D_CMDLIST_POOL_SIZE, | ||
162 | &g2d->cmdlist_pool, GFP_KERNEL); | ||
163 | if (!g2d->cmdlist_pool_virt) { | ||
164 | dev_err(dev, "failed to allocate dma memory\n"); | ||
165 | return -ENOMEM; | ||
166 | } | ||
167 | |||
168 | node = kcalloc(G2D_CMDLIST_NUM, G2D_CMDLIST_NUM * sizeof(*node), | ||
169 | GFP_KERNEL); | ||
170 | if (!node) { | ||
171 | dev_err(dev, "failed to allocate memory\n"); | ||
172 | ret = -ENOMEM; | ||
173 | goto err; | ||
174 | } | ||
175 | |||
176 | for (nr = 0; nr < G2D_CMDLIST_NUM; nr++) { | ||
177 | node[nr].cmdlist = | ||
178 | g2d->cmdlist_pool_virt + nr * G2D_CMDLIST_SIZE; | ||
179 | node[nr].dma_addr = | ||
180 | g2d->cmdlist_pool + nr * G2D_CMDLIST_SIZE; | ||
181 | |||
182 | list_add_tail(&node[nr].list, &g2d->free_cmdlist); | ||
183 | } | ||
184 | |||
185 | return 0; | ||
186 | |||
187 | err: | ||
188 | dma_free_coherent(dev, G2D_CMDLIST_POOL_SIZE, g2d->cmdlist_pool_virt, | ||
189 | g2d->cmdlist_pool); | ||
190 | return ret; | ||
191 | } | ||
192 | |||
193 | static void g2d_fini_cmdlist(struct g2d_data *g2d) | ||
194 | { | ||
195 | struct device *dev = g2d->dev; | ||
196 | |||
197 | kfree(g2d->cmdlist_node); | ||
198 | dma_free_coherent(dev, G2D_CMDLIST_POOL_SIZE, g2d->cmdlist_pool_virt, | ||
199 | g2d->cmdlist_pool); | ||
200 | } | ||
201 | |||
202 | static struct g2d_cmdlist_node *g2d_get_cmdlist(struct g2d_data *g2d) | ||
203 | { | ||
204 | struct device *dev = g2d->dev; | ||
205 | struct g2d_cmdlist_node *node; | ||
206 | |||
207 | mutex_lock(&g2d->cmdlist_mutex); | ||
208 | if (list_empty(&g2d->free_cmdlist)) { | ||
209 | dev_err(dev, "there is no free cmdlist\n"); | ||
210 | mutex_unlock(&g2d->cmdlist_mutex); | ||
211 | return NULL; | ||
212 | } | ||
213 | |||
214 | node = list_first_entry(&g2d->free_cmdlist, struct g2d_cmdlist_node, | ||
215 | list); | ||
216 | list_del_init(&node->list); | ||
217 | mutex_unlock(&g2d->cmdlist_mutex); | ||
218 | |||
219 | return node; | ||
220 | } | ||
221 | |||
222 | static void g2d_put_cmdlist(struct g2d_data *g2d, struct g2d_cmdlist_node *node) | ||
223 | { | ||
224 | mutex_lock(&g2d->cmdlist_mutex); | ||
225 | list_move_tail(&node->list, &g2d->free_cmdlist); | ||
226 | mutex_unlock(&g2d->cmdlist_mutex); | ||
227 | } | ||
228 | |||
229 | static void g2d_add_cmdlist_to_inuse(struct exynos_drm_g2d_private *g2d_priv, | ||
230 | struct g2d_cmdlist_node *node) | ||
231 | { | ||
232 | struct g2d_cmdlist_node *lnode; | ||
233 | |||
234 | if (list_empty(&g2d_priv->inuse_cmdlist)) | ||
235 | goto add_to_list; | ||
236 | |||
237 | /* this links to base address of new cmdlist */ | ||
238 | lnode = list_entry(g2d_priv->inuse_cmdlist.prev, | ||
239 | struct g2d_cmdlist_node, list); | ||
240 | lnode->cmdlist->data[lnode->cmdlist->last] = node->dma_addr; | ||
241 | |||
242 | add_to_list: | ||
243 | list_add_tail(&node->list, &g2d_priv->inuse_cmdlist); | ||
244 | |||
245 | if (node->event) | ||
246 | list_add_tail(&node->event->base.link, &g2d_priv->event_list); | ||
247 | } | ||
248 | |||
249 | static int g2d_get_cmdlist_gem(struct drm_device *drm_dev, | ||
250 | struct drm_file *file, | ||
251 | struct g2d_cmdlist_node *node) | ||
252 | { | ||
253 | struct drm_exynos_file_private *file_priv = file->driver_priv; | ||
254 | struct exynos_drm_g2d_private *g2d_priv = file_priv->g2d_priv; | ||
255 | struct g2d_cmdlist *cmdlist = node->cmdlist; | ||
256 | dma_addr_t *addr; | ||
257 | int offset; | ||
258 | int i; | ||
259 | |||
260 | for (i = 0; i < node->gem_nr; i++) { | ||
261 | struct g2d_gem_node *gem_node; | ||
262 | |||
263 | gem_node = kzalloc(sizeof(*gem_node), GFP_KERNEL); | ||
264 | if (!gem_node) { | ||
265 | dev_err(g2d_priv->dev, "failed to allocate gem node\n"); | ||
266 | return -ENOMEM; | ||
267 | } | ||
268 | |||
269 | offset = cmdlist->last - (i * 2 + 1); | ||
270 | gem_node->handle = cmdlist->data[offset]; | ||
271 | |||
272 | addr = exynos_drm_gem_get_dma_addr(drm_dev, gem_node->handle, | ||
273 | file); | ||
274 | if (IS_ERR(addr)) { | ||
275 | node->gem_nr = i; | ||
276 | kfree(gem_node); | ||
277 | return PTR_ERR(addr); | ||
278 | } | ||
279 | |||
280 | cmdlist->data[offset] = *addr; | ||
281 | list_add_tail(&gem_node->list, &g2d_priv->gem_list); | ||
282 | g2d_priv->gem_nr++; | ||
283 | } | ||
284 | |||
285 | return 0; | ||
286 | } | ||
287 | |||
288 | static void g2d_put_cmdlist_gem(struct drm_device *drm_dev, | ||
289 | struct drm_file *file, | ||
290 | unsigned int nr) | ||
291 | { | ||
292 | struct drm_exynos_file_private *file_priv = file->driver_priv; | ||
293 | struct exynos_drm_g2d_private *g2d_priv = file_priv->g2d_priv; | ||
294 | struct g2d_gem_node *node, *n; | ||
295 | |||
296 | list_for_each_entry_safe_reverse(node, n, &g2d_priv->gem_list, list) { | ||
297 | if (!nr) | ||
298 | break; | ||
299 | |||
300 | exynos_drm_gem_put_dma_addr(drm_dev, node->handle, file); | ||
301 | list_del_init(&node->list); | ||
302 | kfree(node); | ||
303 | nr--; | ||
304 | } | ||
305 | } | ||
306 | |||
307 | static void g2d_dma_start(struct g2d_data *g2d, | ||
308 | struct g2d_runqueue_node *runqueue_node) | ||
309 | { | ||
310 | struct g2d_cmdlist_node *node = | ||
311 | list_first_entry(&runqueue_node->run_cmdlist, | ||
312 | struct g2d_cmdlist_node, list); | ||
313 | |||
314 | pm_runtime_get_sync(g2d->dev); | ||
315 | clk_enable(g2d->gate_clk); | ||
316 | |||
317 | /* interrupt enable */ | ||
318 | writel_relaxed(G2D_INTEN_ACF | G2D_INTEN_UCF | G2D_INTEN_GCF, | ||
319 | g2d->regs + G2D_INTEN); | ||
320 | |||
321 | writel_relaxed(node->dma_addr, g2d->regs + G2D_DMA_SFR_BASE_ADDR); | ||
322 | writel_relaxed(G2D_DMA_START, g2d->regs + G2D_DMA_COMMAND); | ||
323 | } | ||
324 | |||
325 | static struct g2d_runqueue_node *g2d_get_runqueue_node(struct g2d_data *g2d) | ||
326 | { | ||
327 | struct g2d_runqueue_node *runqueue_node; | ||
328 | |||
329 | if (list_empty(&g2d->runqueue)) | ||
330 | return NULL; | ||
331 | |||
332 | runqueue_node = list_first_entry(&g2d->runqueue, | ||
333 | struct g2d_runqueue_node, list); | ||
334 | list_del_init(&runqueue_node->list); | ||
335 | return runqueue_node; | ||
336 | } | ||
337 | |||
338 | static void g2d_free_runqueue_node(struct g2d_data *g2d, | ||
339 | struct g2d_runqueue_node *runqueue_node) | ||
340 | { | ||
341 | if (!runqueue_node) | ||
342 | return; | ||
343 | |||
344 | mutex_lock(&g2d->cmdlist_mutex); | ||
345 | list_splice_tail_init(&runqueue_node->run_cmdlist, &g2d->free_cmdlist); | ||
346 | mutex_unlock(&g2d->cmdlist_mutex); | ||
347 | |||
348 | kmem_cache_free(g2d->runqueue_slab, runqueue_node); | ||
349 | } | ||
350 | |||
351 | static void g2d_exec_runqueue(struct g2d_data *g2d) | ||
352 | { | ||
353 | g2d->runqueue_node = g2d_get_runqueue_node(g2d); | ||
354 | if (g2d->runqueue_node) | ||
355 | g2d_dma_start(g2d, g2d->runqueue_node); | ||
356 | } | ||
357 | |||
358 | static void g2d_runqueue_worker(struct work_struct *work) | ||
359 | { | ||
360 | struct g2d_data *g2d = container_of(work, struct g2d_data, | ||
361 | runqueue_work); | ||
362 | |||
363 | |||
364 | mutex_lock(&g2d->runqueue_mutex); | ||
365 | clk_disable(g2d->gate_clk); | ||
366 | pm_runtime_put_sync(g2d->dev); | ||
367 | |||
368 | complete(&g2d->runqueue_node->complete); | ||
369 | if (g2d->runqueue_node->async) | ||
370 | g2d_free_runqueue_node(g2d, g2d->runqueue_node); | ||
371 | |||
372 | if (g2d->suspended) | ||
373 | g2d->runqueue_node = NULL; | ||
374 | else | ||
375 | g2d_exec_runqueue(g2d); | ||
376 | mutex_unlock(&g2d->runqueue_mutex); | ||
377 | } | ||
378 | |||
379 | static void g2d_finish_event(struct g2d_data *g2d, u32 cmdlist_no) | ||
380 | { | ||
381 | struct drm_device *drm_dev = g2d->subdrv.drm_dev; | ||
382 | struct g2d_runqueue_node *runqueue_node = g2d->runqueue_node; | ||
383 | struct drm_exynos_pending_g2d_event *e; | ||
384 | struct timeval now; | ||
385 | unsigned long flags; | ||
386 | |||
387 | if (list_empty(&runqueue_node->event_list)) | ||
388 | return; | ||
389 | |||
390 | e = list_first_entry(&runqueue_node->event_list, | ||
391 | struct drm_exynos_pending_g2d_event, base.link); | ||
392 | |||
393 | do_gettimeofday(&now); | ||
394 | e->event.tv_sec = now.tv_sec; | ||
395 | e->event.tv_usec = now.tv_usec; | ||
396 | e->event.cmdlist_no = cmdlist_no; | ||
397 | |||
398 | spin_lock_irqsave(&drm_dev->event_lock, flags); | ||
399 | list_move_tail(&e->base.link, &e->base.file_priv->event_list); | ||
400 | wake_up_interruptible(&e->base.file_priv->event_wait); | ||
401 | spin_unlock_irqrestore(&drm_dev->event_lock, flags); | ||
402 | } | ||
403 | |||
404 | static irqreturn_t g2d_irq_handler(int irq, void *dev_id) | ||
405 | { | ||
406 | struct g2d_data *g2d = dev_id; | ||
407 | u32 pending; | ||
408 | |||
409 | pending = readl_relaxed(g2d->regs + G2D_INTC_PEND); | ||
410 | if (pending) | ||
411 | writel_relaxed(pending, g2d->regs + G2D_INTC_PEND); | ||
412 | |||
413 | if (pending & G2D_INTP_GCMD_FIN) { | ||
414 | u32 cmdlist_no = readl_relaxed(g2d->regs + G2D_DMA_STATUS); | ||
415 | |||
416 | cmdlist_no = (cmdlist_no & G2D_DMA_LIST_DONE_COUNT) >> | ||
417 | G2D_DMA_LIST_DONE_COUNT_OFFSET; | ||
418 | |||
419 | g2d_finish_event(g2d, cmdlist_no); | ||
420 | |||
421 | writel_relaxed(0, g2d->regs + G2D_DMA_HOLD_CMD); | ||
422 | if (!(pending & G2D_INTP_ACMD_FIN)) { | ||
423 | writel_relaxed(G2D_DMA_CONTINUE, | ||
424 | g2d->regs + G2D_DMA_COMMAND); | ||
425 | } | ||
426 | } | ||
427 | |||
428 | if (pending & G2D_INTP_ACMD_FIN) | ||
429 | queue_work(g2d->g2d_workq, &g2d->runqueue_work); | ||
430 | |||
431 | return IRQ_HANDLED; | ||
432 | } | ||
433 | |||
434 | static int g2d_check_reg_offset(struct device *dev, struct g2d_cmdlist *cmdlist, | ||
435 | int nr, bool for_addr) | ||
436 | { | ||
437 | int reg_offset; | ||
438 | int index; | ||
439 | int i; | ||
440 | |||
441 | for (i = 0; i < nr; i++) { | ||
442 | index = cmdlist->last - 2 * (i + 1); | ||
443 | reg_offset = cmdlist->data[index] & ~0xfffff000; | ||
444 | |||
445 | if (reg_offset < G2D_VALID_START || reg_offset > G2D_VALID_END) | ||
446 | goto err; | ||
447 | if (reg_offset % 4) | ||
448 | goto err; | ||
449 | |||
450 | switch (reg_offset) { | ||
451 | case G2D_SRC_BASE_ADDR: | ||
452 | case G2D_SRC_PLANE2_BASE_ADDR: | ||
453 | case G2D_DST_BASE_ADDR: | ||
454 | case G2D_DST_PLANE2_BASE_ADDR: | ||
455 | case G2D_PAT_BASE_ADDR: | ||
456 | case G2D_MSK_BASE_ADDR: | ||
457 | if (!for_addr) | ||
458 | goto err; | ||
459 | break; | ||
460 | default: | ||
461 | if (for_addr) | ||
462 | goto err; | ||
463 | break; | ||
464 | } | ||
465 | } | ||
466 | |||
467 | return 0; | ||
468 | |||
469 | err: | ||
470 | dev_err(dev, "Bad register offset: 0x%x\n", cmdlist->data[index]); | ||
471 | return -EINVAL; | ||
472 | } | ||
473 | |||
474 | /* ioctl functions */ | ||
475 | int exynos_g2d_get_ver_ioctl(struct drm_device *drm_dev, void *data, | ||
476 | struct drm_file *file) | ||
477 | { | ||
478 | struct drm_exynos_g2d_get_ver *ver = data; | ||
479 | |||
480 | ver->major = G2D_HW_MAJOR_VER; | ||
481 | ver->minor = G2D_HW_MINOR_VER; | ||
482 | |||
483 | return 0; | ||
484 | } | ||
485 | EXPORT_SYMBOL_GPL(exynos_g2d_get_ver_ioctl); | ||
486 | |||
487 | int exynos_g2d_set_cmdlist_ioctl(struct drm_device *drm_dev, void *data, | ||
488 | struct drm_file *file) | ||
489 | { | ||
490 | struct drm_exynos_file_private *file_priv = file->driver_priv; | ||
491 | struct exynos_drm_g2d_private *g2d_priv = file_priv->g2d_priv; | ||
492 | struct device *dev = g2d_priv->dev; | ||
493 | struct g2d_data *g2d; | ||
494 | struct drm_exynos_g2d_set_cmdlist *req = data; | ||
495 | struct drm_exynos_g2d_cmd *cmd; | ||
496 | struct drm_exynos_pending_g2d_event *e; | ||
497 | struct g2d_cmdlist_node *node; | ||
498 | struct g2d_cmdlist *cmdlist; | ||
499 | unsigned long flags; | ||
500 | int size; | ||
501 | int ret; | ||
502 | |||
503 | if (!dev) | ||
504 | return -ENODEV; | ||
505 | |||
506 | g2d = dev_get_drvdata(dev); | ||
507 | if (!g2d) | ||
508 | return -EFAULT; | ||
509 | |||
510 | node = g2d_get_cmdlist(g2d); | ||
511 | if (!node) | ||
512 | return -ENOMEM; | ||
513 | |||
514 | node->event = NULL; | ||
515 | |||
516 | if (req->event_type != G2D_EVENT_NOT) { | ||
517 | spin_lock_irqsave(&drm_dev->event_lock, flags); | ||
518 | if (file->event_space < sizeof(e->event)) { | ||
519 | spin_unlock_irqrestore(&drm_dev->event_lock, flags); | ||
520 | ret = -ENOMEM; | ||
521 | goto err; | ||
522 | } | ||
523 | file->event_space -= sizeof(e->event); | ||
524 | spin_unlock_irqrestore(&drm_dev->event_lock, flags); | ||
525 | |||
526 | e = kzalloc(sizeof(*node->event), GFP_KERNEL); | ||
527 | if (!e) { | ||
528 | dev_err(dev, "failed to allocate event\n"); | ||
529 | |||
530 | spin_lock_irqsave(&drm_dev->event_lock, flags); | ||
531 | file->event_space += sizeof(e->event); | ||
532 | spin_unlock_irqrestore(&drm_dev->event_lock, flags); | ||
533 | |||
534 | ret = -ENOMEM; | ||
535 | goto err; | ||
536 | } | ||
537 | |||
538 | e->event.base.type = DRM_EXYNOS_G2D_EVENT; | ||
539 | e->event.base.length = sizeof(e->event); | ||
540 | e->event.user_data = req->user_data; | ||
541 | e->base.event = &e->event.base; | ||
542 | e->base.file_priv = file; | ||
543 | e->base.destroy = (void (*) (struct drm_pending_event *)) kfree; | ||
544 | |||
545 | node->event = e; | ||
546 | } | ||
547 | |||
548 | cmdlist = node->cmdlist; | ||
549 | |||
550 | cmdlist->last = 0; | ||
551 | |||
552 | /* | ||
553 | * If don't clear SFR registers, the cmdlist is affected by register | ||
554 | * values of previous cmdlist. G2D hw executes SFR clear command and | ||
555 | * a next command at the same time then the next command is ignored and | ||
556 | * is executed rightly from next next command, so needs a dummy command | ||
557 | * to next command of SFR clear command. | ||
558 | */ | ||
559 | cmdlist->data[cmdlist->last++] = G2D_SOFT_RESET; | ||
560 | cmdlist->data[cmdlist->last++] = G2D_SFRCLEAR; | ||
561 | cmdlist->data[cmdlist->last++] = G2D_SRC_BASE_ADDR; | ||
562 | cmdlist->data[cmdlist->last++] = 0; | ||
563 | |||
564 | if (node->event) { | ||
565 | cmdlist->data[cmdlist->last++] = G2D_DMA_HOLD_CMD; | ||
566 | cmdlist->data[cmdlist->last++] = G2D_LIST_HOLD; | ||
567 | } | ||
568 | |||
569 | /* Check size of cmdlist: last 2 is about G2D_BITBLT_START */ | ||
570 | size = cmdlist->last + req->cmd_nr * 2 + req->cmd_gem_nr * 2 + 2; | ||
571 | if (size > G2D_CMDLIST_DATA_NUM) { | ||
572 | dev_err(dev, "cmdlist size is too big\n"); | ||
573 | ret = -EINVAL; | ||
574 | goto err_free_event; | ||
575 | } | ||
576 | |||
577 | cmd = (struct drm_exynos_g2d_cmd *)(uint32_t)req->cmd; | ||
578 | |||
579 | if (copy_from_user(cmdlist->data + cmdlist->last, | ||
580 | (void __user *)cmd, | ||
581 | sizeof(*cmd) * req->cmd_nr)) { | ||
582 | ret = -EFAULT; | ||
583 | goto err_free_event; | ||
584 | } | ||
585 | cmdlist->last += req->cmd_nr * 2; | ||
586 | |||
587 | ret = g2d_check_reg_offset(dev, cmdlist, req->cmd_nr, false); | ||
588 | if (ret < 0) | ||
589 | goto err_free_event; | ||
590 | |||
591 | node->gem_nr = req->cmd_gem_nr; | ||
592 | if (req->cmd_gem_nr) { | ||
593 | struct drm_exynos_g2d_cmd *cmd_gem; | ||
594 | |||
595 | cmd_gem = (struct drm_exynos_g2d_cmd *)(uint32_t)req->cmd_gem; | ||
596 | |||
597 | if (copy_from_user(cmdlist->data + cmdlist->last, | ||
598 | (void __user *)cmd_gem, | ||
599 | sizeof(*cmd_gem) * req->cmd_gem_nr)) { | ||
600 | ret = -EFAULT; | ||
601 | goto err_free_event; | ||
602 | } | ||
603 | cmdlist->last += req->cmd_gem_nr * 2; | ||
604 | |||
605 | ret = g2d_check_reg_offset(dev, cmdlist, req->cmd_gem_nr, true); | ||
606 | if (ret < 0) | ||
607 | goto err_free_event; | ||
608 | |||
609 | ret = g2d_get_cmdlist_gem(drm_dev, file, node); | ||
610 | if (ret < 0) | ||
611 | goto err_unmap; | ||
612 | } | ||
613 | |||
614 | cmdlist->data[cmdlist->last++] = G2D_BITBLT_START; | ||
615 | cmdlist->data[cmdlist->last++] = G2D_START_BITBLT; | ||
616 | |||
617 | /* head */ | ||
618 | cmdlist->head = cmdlist->last / 2; | ||
619 | |||
620 | /* tail */ | ||
621 | cmdlist->data[cmdlist->last] = 0; | ||
622 | |||
623 | g2d_add_cmdlist_to_inuse(g2d_priv, node); | ||
624 | |||
625 | return 0; | ||
626 | |||
627 | err_unmap: | ||
628 | g2d_put_cmdlist_gem(drm_dev, file, node->gem_nr); | ||
629 | err_free_event: | ||
630 | if (node->event) { | ||
631 | spin_lock_irqsave(&drm_dev->event_lock, flags); | ||
632 | file->event_space += sizeof(e->event); | ||
633 | spin_unlock_irqrestore(&drm_dev->event_lock, flags); | ||
634 | kfree(node->event); | ||
635 | } | ||
636 | err: | ||
637 | g2d_put_cmdlist(g2d, node); | ||
638 | return ret; | ||
639 | } | ||
640 | EXPORT_SYMBOL_GPL(exynos_g2d_set_cmdlist_ioctl); | ||
641 | |||
642 | int exynos_g2d_exec_ioctl(struct drm_device *drm_dev, void *data, | ||
643 | struct drm_file *file) | ||
644 | { | ||
645 | struct drm_exynos_file_private *file_priv = file->driver_priv; | ||
646 | struct exynos_drm_g2d_private *g2d_priv = file_priv->g2d_priv; | ||
647 | struct device *dev = g2d_priv->dev; | ||
648 | struct g2d_data *g2d; | ||
649 | struct drm_exynos_g2d_exec *req = data; | ||
650 | struct g2d_runqueue_node *runqueue_node; | ||
651 | struct list_head *run_cmdlist; | ||
652 | struct list_head *event_list; | ||
653 | |||
654 | if (!dev) | ||
655 | return -ENODEV; | ||
656 | |||
657 | g2d = dev_get_drvdata(dev); | ||
658 | if (!g2d) | ||
659 | return -EFAULT; | ||
660 | |||
661 | runqueue_node = kmem_cache_alloc(g2d->runqueue_slab, GFP_KERNEL); | ||
662 | if (!runqueue_node) { | ||
663 | dev_err(dev, "failed to allocate memory\n"); | ||
664 | return -ENOMEM; | ||
665 | } | ||
666 | run_cmdlist = &runqueue_node->run_cmdlist; | ||
667 | event_list = &runqueue_node->event_list; | ||
668 | INIT_LIST_HEAD(run_cmdlist); | ||
669 | INIT_LIST_HEAD(event_list); | ||
670 | init_completion(&runqueue_node->complete); | ||
671 | runqueue_node->async = req->async; | ||
672 | |||
673 | list_splice_init(&g2d_priv->inuse_cmdlist, run_cmdlist); | ||
674 | list_splice_init(&g2d_priv->event_list, event_list); | ||
675 | |||
676 | if (list_empty(run_cmdlist)) { | ||
677 | dev_err(dev, "there is no inuse cmdlist\n"); | ||
678 | kmem_cache_free(g2d->runqueue_slab, runqueue_node); | ||
679 | return -EPERM; | ||
680 | } | ||
681 | |||
682 | mutex_lock(&g2d->runqueue_mutex); | ||
683 | list_add_tail(&runqueue_node->list, &g2d->runqueue); | ||
684 | if (!g2d->runqueue_node) | ||
685 | g2d_exec_runqueue(g2d); | ||
686 | mutex_unlock(&g2d->runqueue_mutex); | ||
687 | |||
688 | if (runqueue_node->async) | ||
689 | goto out; | ||
690 | |||
691 | wait_for_completion(&runqueue_node->complete); | ||
692 | g2d_free_runqueue_node(g2d, runqueue_node); | ||
693 | |||
694 | out: | ||
695 | return 0; | ||
696 | } | ||
697 | EXPORT_SYMBOL_GPL(exynos_g2d_exec_ioctl); | ||
698 | |||
699 | static int g2d_open(struct drm_device *drm_dev, struct device *dev, | ||
700 | struct drm_file *file) | ||
701 | { | ||
702 | struct drm_exynos_file_private *file_priv = file->driver_priv; | ||
703 | struct exynos_drm_g2d_private *g2d_priv; | ||
704 | |||
705 | g2d_priv = kzalloc(sizeof(*g2d_priv), GFP_KERNEL); | ||
706 | if (!g2d_priv) { | ||
707 | dev_err(dev, "failed to allocate g2d private data\n"); | ||
708 | return -ENOMEM; | ||
709 | } | ||
710 | |||
711 | g2d_priv->dev = dev; | ||
712 | file_priv->g2d_priv = g2d_priv; | ||
713 | |||
714 | INIT_LIST_HEAD(&g2d_priv->inuse_cmdlist); | ||
715 | INIT_LIST_HEAD(&g2d_priv->event_list); | ||
716 | INIT_LIST_HEAD(&g2d_priv->gem_list); | ||
717 | |||
718 | return 0; | ||
719 | } | ||
720 | |||
721 | static void g2d_close(struct drm_device *drm_dev, struct device *dev, | ||
722 | struct drm_file *file) | ||
723 | { | ||
724 | struct drm_exynos_file_private *file_priv = file->driver_priv; | ||
725 | struct exynos_drm_g2d_private *g2d_priv = file_priv->g2d_priv; | ||
726 | struct g2d_data *g2d; | ||
727 | struct g2d_cmdlist_node *node, *n; | ||
728 | |||
729 | if (!dev) | ||
730 | return; | ||
731 | |||
732 | g2d = dev_get_drvdata(dev); | ||
733 | if (!g2d) | ||
734 | return; | ||
735 | |||
736 | mutex_lock(&g2d->cmdlist_mutex); | ||
737 | list_for_each_entry_safe(node, n, &g2d_priv->inuse_cmdlist, list) | ||
738 | list_move_tail(&node->list, &g2d->free_cmdlist); | ||
739 | mutex_unlock(&g2d->cmdlist_mutex); | ||
740 | |||
741 | g2d_put_cmdlist_gem(drm_dev, file, g2d_priv->gem_nr); | ||
742 | |||
743 | kfree(file_priv->g2d_priv); | ||
744 | } | ||
745 | |||
746 | static int __devinit g2d_probe(struct platform_device *pdev) | ||
747 | { | ||
748 | struct device *dev = &pdev->dev; | ||
749 | struct resource *res; | ||
750 | struct g2d_data *g2d; | ||
751 | struct exynos_drm_subdrv *subdrv; | ||
752 | int ret; | ||
753 | |||
754 | g2d = kzalloc(sizeof(*g2d), GFP_KERNEL); | ||
755 | if (!g2d) { | ||
756 | dev_err(dev, "failed to allocate driver data\n"); | ||
757 | return -ENOMEM; | ||
758 | } | ||
759 | |||
760 | g2d->runqueue_slab = kmem_cache_create("g2d_runqueue_slab", | ||
761 | sizeof(struct g2d_runqueue_node), 0, 0, NULL); | ||
762 | if (!g2d->runqueue_slab) { | ||
763 | ret = -ENOMEM; | ||
764 | goto err_free_mem; | ||
765 | } | ||
766 | |||
767 | g2d->dev = dev; | ||
768 | |||
769 | g2d->g2d_workq = create_singlethread_workqueue("g2d"); | ||
770 | if (!g2d->g2d_workq) { | ||
771 | dev_err(dev, "failed to create workqueue\n"); | ||
772 | ret = -EINVAL; | ||
773 | goto err_destroy_slab; | ||
774 | } | ||
775 | |||
776 | INIT_WORK(&g2d->runqueue_work, g2d_runqueue_worker); | ||
777 | INIT_LIST_HEAD(&g2d->free_cmdlist); | ||
778 | INIT_LIST_HEAD(&g2d->runqueue); | ||
779 | |||
780 | mutex_init(&g2d->cmdlist_mutex); | ||
781 | mutex_init(&g2d->runqueue_mutex); | ||
782 | |||
783 | ret = g2d_init_cmdlist(g2d); | ||
784 | if (ret < 0) | ||
785 | goto err_destroy_workqueue; | ||
786 | |||
787 | g2d->gate_clk = clk_get(dev, "fimg2d"); | ||
788 | if (IS_ERR(g2d->gate_clk)) { | ||
789 | dev_err(dev, "failed to get gate clock\n"); | ||
790 | ret = PTR_ERR(g2d->gate_clk); | ||
791 | goto err_fini_cmdlist; | ||
792 | } | ||
793 | |||
794 | pm_runtime_enable(dev); | ||
795 | |||
796 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
797 | if (!res) { | ||
798 | dev_err(dev, "failed to get I/O memory\n"); | ||
799 | ret = -ENOENT; | ||
800 | goto err_put_clk; | ||
801 | } | ||
802 | |||
803 | g2d->regs_res = request_mem_region(res->start, resource_size(res), | ||
804 | dev_name(dev)); | ||
805 | if (!g2d->regs_res) { | ||
806 | dev_err(dev, "failed to request I/O memory\n"); | ||
807 | ret = -ENOENT; | ||
808 | goto err_put_clk; | ||
809 | } | ||
810 | |||
811 | g2d->regs = ioremap(res->start, resource_size(res)); | ||
812 | if (!g2d->regs) { | ||
813 | dev_err(dev, "failed to remap I/O memory\n"); | ||
814 | ret = -ENXIO; | ||
815 | goto err_release_res; | ||
816 | } | ||
817 | |||
818 | g2d->irq = platform_get_irq(pdev, 0); | ||
819 | if (g2d->irq < 0) { | ||
820 | dev_err(dev, "failed to get irq\n"); | ||
821 | ret = g2d->irq; | ||
822 | goto err_unmap_base; | ||
823 | } | ||
824 | |||
825 | ret = request_irq(g2d->irq, g2d_irq_handler, 0, "drm_g2d", g2d); | ||
826 | if (ret < 0) { | ||
827 | dev_err(dev, "irq request failed\n"); | ||
828 | goto err_unmap_base; | ||
829 | } | ||
830 | |||
831 | platform_set_drvdata(pdev, g2d); | ||
832 | |||
833 | subdrv = &g2d->subdrv; | ||
834 | subdrv->dev = dev; | ||
835 | subdrv->open = g2d_open; | ||
836 | subdrv->close = g2d_close; | ||
837 | |||
838 | ret = exynos_drm_subdrv_register(subdrv); | ||
839 | if (ret < 0) { | ||
840 | dev_err(dev, "failed to register drm g2d device\n"); | ||
841 | goto err_free_irq; | ||
842 | } | ||
843 | |||
844 | dev_info(dev, "The exynos g2d(ver %d.%d) successfully probed\n", | ||
845 | G2D_HW_MAJOR_VER, G2D_HW_MINOR_VER); | ||
846 | |||
847 | return 0; | ||
848 | |||
849 | err_free_irq: | ||
850 | free_irq(g2d->irq, g2d); | ||
851 | err_unmap_base: | ||
852 | iounmap(g2d->regs); | ||
853 | err_release_res: | ||
854 | release_resource(g2d->regs_res); | ||
855 | kfree(g2d->regs_res); | ||
856 | err_put_clk: | ||
857 | pm_runtime_disable(dev); | ||
858 | clk_put(g2d->gate_clk); | ||
859 | err_fini_cmdlist: | ||
860 | g2d_fini_cmdlist(g2d); | ||
861 | err_destroy_workqueue: | ||
862 | destroy_workqueue(g2d->g2d_workq); | ||
863 | err_destroy_slab: | ||
864 | kmem_cache_destroy(g2d->runqueue_slab); | ||
865 | err_free_mem: | ||
866 | kfree(g2d); | ||
867 | return ret; | ||
868 | } | ||
869 | |||
870 | static int __devexit g2d_remove(struct platform_device *pdev) | ||
871 | { | ||
872 | struct g2d_data *g2d = platform_get_drvdata(pdev); | ||
873 | |||
874 | cancel_work_sync(&g2d->runqueue_work); | ||
875 | exynos_drm_subdrv_unregister(&g2d->subdrv); | ||
876 | free_irq(g2d->irq, g2d); | ||
877 | |||
878 | while (g2d->runqueue_node) { | ||
879 | g2d_free_runqueue_node(g2d, g2d->runqueue_node); | ||
880 | g2d->runqueue_node = g2d_get_runqueue_node(g2d); | ||
881 | } | ||
882 | |||
883 | iounmap(g2d->regs); | ||
884 | release_resource(g2d->regs_res); | ||
885 | kfree(g2d->regs_res); | ||
886 | |||
887 | pm_runtime_disable(&pdev->dev); | ||
888 | clk_put(g2d->gate_clk); | ||
889 | |||
890 | g2d_fini_cmdlist(g2d); | ||
891 | destroy_workqueue(g2d->g2d_workq); | ||
892 | kmem_cache_destroy(g2d->runqueue_slab); | ||
893 | kfree(g2d); | ||
894 | |||
895 | return 0; | ||
896 | } | ||
897 | |||
898 | #ifdef CONFIG_PM_SLEEP | ||
899 | static int g2d_suspend(struct device *dev) | ||
900 | { | ||
901 | struct g2d_data *g2d = dev_get_drvdata(dev); | ||
902 | |||
903 | mutex_lock(&g2d->runqueue_mutex); | ||
904 | g2d->suspended = true; | ||
905 | mutex_unlock(&g2d->runqueue_mutex); | ||
906 | |||
907 | while (g2d->runqueue_node) | ||
908 | /* FIXME: good range? */ | ||
909 | usleep_range(500, 1000); | ||
910 | |||
911 | flush_work_sync(&g2d->runqueue_work); | ||
912 | |||
913 | return 0; | ||
914 | } | ||
915 | |||
916 | static int g2d_resume(struct device *dev) | ||
917 | { | ||
918 | struct g2d_data *g2d = dev_get_drvdata(dev); | ||
919 | |||
920 | g2d->suspended = false; | ||
921 | g2d_exec_runqueue(g2d); | ||
922 | |||
923 | return 0; | ||
924 | } | ||
925 | #endif | ||
926 | |||
927 | SIMPLE_DEV_PM_OPS(g2d_pm_ops, g2d_suspend, g2d_resume); | ||
928 | |||
929 | struct platform_driver g2d_driver = { | ||
930 | .probe = g2d_probe, | ||
931 | .remove = __devexit_p(g2d_remove), | ||
932 | .driver = { | ||
933 | .name = "s5p-g2d", | ||
934 | .owner = THIS_MODULE, | ||
935 | .pm = &g2d_pm_ops, | ||
936 | }, | ||
937 | }; | ||
938 |
drivers/gpu/drm/exynos/exynos_drm_g2d.h
File was created | 1 | /* | |
2 | * Copyright (C) 2012 Samsung Electronics Co.Ltd | ||
3 | * Authors: Joonyoung Shim <jy0922.shim@samsung.com> | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify | ||
6 | * it under the terms of the GNU General Public License version 2 as | ||
7 | * published by the Free Software Foundationr | ||
8 | */ | ||
9 | |||
10 | #ifdef CONFIG_DRM_EXYNOS_G2D | ||
11 | extern int exynos_g2d_get_ver_ioctl(struct drm_device *dev, void *data, | ||
12 | struct drm_file *file_priv); | ||
13 | extern int exynos_g2d_set_cmdlist_ioctl(struct drm_device *dev, void *data, | ||
14 | struct drm_file *file_priv); | ||
15 | extern int exynos_g2d_exec_ioctl(struct drm_device *dev, void *data, | ||
16 | struct drm_file *file_priv); | ||
17 | #else | ||
18 | static inline int exynos_g2d_get_ver_ioctl(struct drm_device *dev, void *data, | ||
19 | struct drm_file *file_priv) | ||
20 | { | ||
21 | return -ENODEV; | ||
22 | } | ||
23 | |||
24 | static inline int exynos_g2d_set_cmdlist_ioctl(struct drm_device *dev, | ||
25 | void *data, | ||
26 | struct drm_file *file_priv) | ||
27 | { | ||
28 | return -ENODEV; | ||
29 | } | ||
30 | |||
31 | static inline int exynos_g2d_exec_ioctl(struct drm_device *dev, void *data, | ||
32 | struct drm_file *file_priv) | ||
33 | { | ||
34 | return -ENODEV; | ||
35 | } | ||
36 | #endif | ||
37 |
include/drm/exynos_drm.h
1 | /* exynos_drm.h | 1 | /* exynos_drm.h |
2 | * | 2 | * |
3 | * Copyright (c) 2011 Samsung Electronics Co., Ltd. | 3 | * Copyright (c) 2011 Samsung Electronics Co., Ltd. |
4 | * Authors: | 4 | * Authors: |
5 | * Inki Dae <inki.dae@samsung.com> | 5 | * Inki Dae <inki.dae@samsung.com> |
6 | * Joonyoung Shim <jy0922.shim@samsung.com> | 6 | * Joonyoung Shim <jy0922.shim@samsung.com> |
7 | * Seung-Woo Kim <sw0312.kim@samsung.com> | 7 | * Seung-Woo Kim <sw0312.kim@samsung.com> |
8 | * | 8 | * |
9 | * Permission is hereby granted, free of charge, to any person obtaining a | 9 | * Permission is hereby granted, free of charge, to any person obtaining a |
10 | * copy of this software and associated documentation files (the "Software"), | 10 | * copy of this software and associated documentation files (the "Software"), |
11 | * to deal in the Software without restriction, including without limitation | 11 | * to deal in the Software without restriction, including without limitation |
12 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, | 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 | 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: | 14 | * Software is furnished to do so, subject to the following conditions: |
15 | * | 15 | * |
16 | * The above copyright notice and this permission notice (including the next | 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 | 17 | * paragraph) shall be included in all copies or substantial portions of the |
18 | * Software. | 18 | * Software. |
19 | * | 19 | * |
20 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | 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, | 21 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
22 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | 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 | 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, | 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 | 25 | * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR |
26 | * OTHER DEALINGS IN THE SOFTWARE. | 26 | * OTHER DEALINGS IN THE SOFTWARE. |
27 | */ | 27 | */ |
28 | 28 | ||
29 | #ifndef _EXYNOS_DRM_H_ | 29 | #ifndef _EXYNOS_DRM_H_ |
30 | #define _EXYNOS_DRM_H_ | 30 | #define _EXYNOS_DRM_H_ |
31 | 31 | ||
32 | #include "drm.h" | ||
33 | |||
32 | /** | 34 | /** |
33 | * User-desired buffer creation information structure. | 35 | * User-desired buffer creation information structure. |
34 | * | 36 | * |
35 | * @size: user-desired memory allocation size. | 37 | * @size: user-desired memory allocation size. |
36 | * - this size value would be page-aligned internally. | 38 | * - this size value would be page-aligned internally. |
37 | * @flags: user request for setting memory type or cache attributes. | 39 | * @flags: user request for setting memory type or cache attributes. |
38 | * @handle: returned a handle to created gem object. | 40 | * @handle: returned a handle to created gem object. |
39 | * - this handle will be set by gem module of kernel side. | 41 | * - this handle will be set by gem module of kernel side. |
40 | */ | 42 | */ |
41 | struct drm_exynos_gem_create { | 43 | struct drm_exynos_gem_create { |
42 | uint64_t size; | 44 | uint64_t size; |
43 | unsigned int flags; | 45 | unsigned int flags; |
44 | unsigned int handle; | 46 | unsigned int handle; |
45 | }; | 47 | }; |
46 | 48 | ||
47 | /** | 49 | /** |
48 | * A structure for getting buffer offset. | 50 | * A structure for getting buffer offset. |
49 | * | 51 | * |
50 | * @handle: a pointer to gem object created. | 52 | * @handle: a pointer to gem object created. |
51 | * @pad: just padding to be 64-bit aligned. | 53 | * @pad: just padding to be 64-bit aligned. |
52 | * @offset: relatived offset value of the memory region allocated. | 54 | * @offset: relatived offset value of the memory region allocated. |
53 | * - this value should be set by user. | 55 | * - this value should be set by user. |
54 | */ | 56 | */ |
55 | struct drm_exynos_gem_map_off { | 57 | struct drm_exynos_gem_map_off { |
56 | unsigned int handle; | 58 | unsigned int handle; |
57 | unsigned int pad; | 59 | unsigned int pad; |
58 | uint64_t offset; | 60 | uint64_t offset; |
59 | }; | 61 | }; |
60 | 62 | ||
61 | /** | 63 | /** |
62 | * A structure for mapping buffer. | 64 | * A structure for mapping buffer. |
63 | * | 65 | * |
64 | * @handle: a handle to gem object created. | 66 | * @handle: a handle to gem object created. |
65 | * @size: memory size to be mapped. | 67 | * @size: memory size to be mapped. |
66 | * @mapped: having user virtual address mmaped. | 68 | * @mapped: having user virtual address mmaped. |
67 | * - this variable would be filled by exynos gem module | 69 | * - this variable would be filled by exynos gem module |
68 | * of kernel side with user virtual address which is allocated | 70 | * of kernel side with user virtual address which is allocated |
69 | * by do_mmap(). | 71 | * by do_mmap(). |
70 | */ | 72 | */ |
71 | struct drm_exynos_gem_mmap { | 73 | struct drm_exynos_gem_mmap { |
72 | unsigned int handle; | 74 | unsigned int handle; |
73 | unsigned int size; | 75 | unsigned int size; |
74 | uint64_t mapped; | 76 | uint64_t mapped; |
75 | }; | 77 | }; |
76 | 78 | ||
77 | /** | 79 | /** |
78 | * A structure to gem information. | 80 | * A structure to gem information. |
79 | * | 81 | * |
80 | * @handle: a handle to gem object created. | 82 | * @handle: a handle to gem object created. |
81 | * @flags: flag value including memory type and cache attribute and | 83 | * @flags: flag value including memory type and cache attribute and |
82 | * this value would be set by driver. | 84 | * this value would be set by driver. |
83 | * @size: size to memory region allocated by gem and this size would | 85 | * @size: size to memory region allocated by gem and this size would |
84 | * be set by driver. | 86 | * be set by driver. |
85 | */ | 87 | */ |
86 | struct drm_exynos_gem_info { | 88 | struct drm_exynos_gem_info { |
87 | unsigned int handle; | 89 | unsigned int handle; |
88 | unsigned int flags; | 90 | unsigned int flags; |
89 | uint64_t size; | 91 | uint64_t size; |
90 | }; | 92 | }; |
91 | 93 | ||
92 | /** | 94 | /** |
93 | * A structure for user connection request of virtual display. | 95 | * A structure for user connection request of virtual display. |
94 | * | 96 | * |
95 | * @connection: indicate whether doing connetion or not by user. | 97 | * @connection: indicate whether doing connetion or not by user. |
96 | * @extensions: if this value is 1 then the vidi driver would need additional | 98 | * @extensions: if this value is 1 then the vidi driver would need additional |
97 | * 128bytes edid data. | 99 | * 128bytes edid data. |
98 | * @edid: the edid data pointer from user side. | 100 | * @edid: the edid data pointer from user side. |
99 | */ | 101 | */ |
100 | struct drm_exynos_vidi_connection { | 102 | struct drm_exynos_vidi_connection { |
101 | unsigned int connection; | 103 | unsigned int connection; |
102 | unsigned int extensions; | 104 | unsigned int extensions; |
103 | uint64_t edid; | 105 | uint64_t edid; |
104 | }; | 106 | }; |
105 | 107 | ||
106 | struct drm_exynos_plane_set_zpos { | 108 | struct drm_exynos_plane_set_zpos { |
107 | __u32 plane_id; | 109 | __u32 plane_id; |
108 | __s32 zpos; | 110 | __s32 zpos; |
109 | }; | 111 | }; |
110 | 112 | ||
111 | /* memory type definitions. */ | 113 | /* memory type definitions. */ |
112 | enum e_drm_exynos_gem_mem_type { | 114 | enum e_drm_exynos_gem_mem_type { |
113 | /* Physically Continuous memory and used as default. */ | 115 | /* Physically Continuous memory and used as default. */ |
114 | EXYNOS_BO_CONTIG = 0 << 0, | 116 | EXYNOS_BO_CONTIG = 0 << 0, |
115 | /* Physically Non-Continuous memory. */ | 117 | /* Physically Non-Continuous memory. */ |
116 | EXYNOS_BO_NONCONTIG = 1 << 0, | 118 | EXYNOS_BO_NONCONTIG = 1 << 0, |
117 | /* non-cachable mapping and used as default. */ | 119 | /* non-cachable mapping and used as default. */ |
118 | EXYNOS_BO_NONCACHABLE = 0 << 1, | 120 | EXYNOS_BO_NONCACHABLE = 0 << 1, |
119 | /* cachable mapping. */ | 121 | /* cachable mapping. */ |
120 | EXYNOS_BO_CACHABLE = 1 << 1, | 122 | EXYNOS_BO_CACHABLE = 1 << 1, |
121 | /* write-combine mapping. */ | 123 | /* write-combine mapping. */ |
122 | EXYNOS_BO_WC = 1 << 2, | 124 | EXYNOS_BO_WC = 1 << 2, |
123 | EXYNOS_BO_MASK = EXYNOS_BO_NONCONTIG | EXYNOS_BO_CACHABLE | | 125 | EXYNOS_BO_MASK = EXYNOS_BO_NONCONTIG | EXYNOS_BO_CACHABLE | |
124 | EXYNOS_BO_WC | 126 | EXYNOS_BO_WC |
125 | }; | 127 | }; |
126 | 128 | ||
129 | struct drm_exynos_g2d_get_ver { | ||
130 | __u32 major; | ||
131 | __u32 minor; | ||
132 | }; | ||
133 | |||
134 | struct drm_exynos_g2d_cmd { | ||
135 | __u32 offset; | ||
136 | __u32 data; | ||
137 | }; | ||
138 | |||
139 | enum drm_exynos_g2d_event_type { | ||
140 | G2D_EVENT_NOT, | ||
141 | G2D_EVENT_NONSTOP, | ||
142 | G2D_EVENT_STOP, /* not yet */ | ||
143 | }; | ||
144 | |||
145 | struct drm_exynos_g2d_set_cmdlist { | ||
146 | __u64 cmd; | ||
147 | __u64 cmd_gem; | ||
148 | __u32 cmd_nr; | ||
149 | __u32 cmd_gem_nr; | ||
150 | |||
151 | /* for g2d event */ | ||
152 | __u64 event_type; | ||
153 | __u64 user_data; | ||
154 | }; | ||
155 | |||
156 | struct drm_exynos_g2d_exec { | ||
157 | __u64 async; | ||
158 | }; | ||
159 | |||
127 | #define DRM_EXYNOS_GEM_CREATE 0x00 | 160 | #define DRM_EXYNOS_GEM_CREATE 0x00 |
128 | #define DRM_EXYNOS_GEM_MAP_OFFSET 0x01 | 161 | #define DRM_EXYNOS_GEM_MAP_OFFSET 0x01 |
129 | #define DRM_EXYNOS_GEM_MMAP 0x02 | 162 | #define DRM_EXYNOS_GEM_MMAP 0x02 |
130 | /* Reserved 0x03 ~ 0x05 for exynos specific gem ioctl */ | 163 | /* Reserved 0x03 ~ 0x05 for exynos specific gem ioctl */ |
131 | #define DRM_EXYNOS_GEM_GET 0x04 | 164 | #define DRM_EXYNOS_GEM_GET 0x04 |
132 | #define DRM_EXYNOS_PLANE_SET_ZPOS 0x06 | 165 | #define DRM_EXYNOS_PLANE_SET_ZPOS 0x06 |
133 | #define DRM_EXYNOS_VIDI_CONNECTION 0x07 | 166 | #define DRM_EXYNOS_VIDI_CONNECTION 0x07 |
134 | 167 | ||
168 | /* G2D */ | ||
169 | #define DRM_EXYNOS_G2D_GET_VER 0x20 | ||
170 | #define DRM_EXYNOS_G2D_SET_CMDLIST 0x21 | ||
171 | #define DRM_EXYNOS_G2D_EXEC 0x22 | ||
172 | |||
135 | #define DRM_IOCTL_EXYNOS_GEM_CREATE DRM_IOWR(DRM_COMMAND_BASE + \ | 173 | #define DRM_IOCTL_EXYNOS_GEM_CREATE DRM_IOWR(DRM_COMMAND_BASE + \ |
136 | DRM_EXYNOS_GEM_CREATE, struct drm_exynos_gem_create) | 174 | DRM_EXYNOS_GEM_CREATE, struct drm_exynos_gem_create) |
137 | 175 | ||
138 | #define DRM_IOCTL_EXYNOS_GEM_MAP_OFFSET DRM_IOWR(DRM_COMMAND_BASE + \ | 176 | #define DRM_IOCTL_EXYNOS_GEM_MAP_OFFSET DRM_IOWR(DRM_COMMAND_BASE + \ |
139 | DRM_EXYNOS_GEM_MAP_OFFSET, struct drm_exynos_gem_map_off) | 177 | DRM_EXYNOS_GEM_MAP_OFFSET, struct drm_exynos_gem_map_off) |
140 | 178 | ||
141 | #define DRM_IOCTL_EXYNOS_GEM_MMAP DRM_IOWR(DRM_COMMAND_BASE + \ | 179 | #define DRM_IOCTL_EXYNOS_GEM_MMAP DRM_IOWR(DRM_COMMAND_BASE + \ |
142 | DRM_EXYNOS_GEM_MMAP, struct drm_exynos_gem_mmap) | 180 | DRM_EXYNOS_GEM_MMAP, struct drm_exynos_gem_mmap) |
143 | 181 | ||
144 | #define DRM_IOCTL_EXYNOS_GEM_GET DRM_IOWR(DRM_COMMAND_BASE + \ | 182 | #define DRM_IOCTL_EXYNOS_GEM_GET DRM_IOWR(DRM_COMMAND_BASE + \ |
145 | DRM_EXYNOS_GEM_GET, struct drm_exynos_gem_info) | 183 | DRM_EXYNOS_GEM_GET, struct drm_exynos_gem_info) |
146 | 184 | ||
147 | #define DRM_IOCTL_EXYNOS_PLANE_SET_ZPOS DRM_IOWR(DRM_COMMAND_BASE + \ | 185 | #define DRM_IOCTL_EXYNOS_PLANE_SET_ZPOS DRM_IOWR(DRM_COMMAND_BASE + \ |
148 | DRM_EXYNOS_PLANE_SET_ZPOS, struct drm_exynos_plane_set_zpos) | 186 | DRM_EXYNOS_PLANE_SET_ZPOS, struct drm_exynos_plane_set_zpos) |
149 | 187 | ||
150 | #define DRM_IOCTL_EXYNOS_VIDI_CONNECTION DRM_IOWR(DRM_COMMAND_BASE + \ | 188 | #define DRM_IOCTL_EXYNOS_VIDI_CONNECTION DRM_IOWR(DRM_COMMAND_BASE + \ |
151 | DRM_EXYNOS_VIDI_CONNECTION, struct drm_exynos_vidi_connection) | 189 | DRM_EXYNOS_VIDI_CONNECTION, struct drm_exynos_vidi_connection) |
190 | |||
191 | #define DRM_IOCTL_EXYNOS_G2D_GET_VER DRM_IOWR(DRM_COMMAND_BASE + \ | ||
192 | DRM_EXYNOS_G2D_GET_VER, struct drm_exynos_g2d_get_ver) | ||
193 | #define DRM_IOCTL_EXYNOS_G2D_SET_CMDLIST DRM_IOWR(DRM_COMMAND_BASE + \ | ||
194 | DRM_EXYNOS_G2D_SET_CMDLIST, struct drm_exynos_g2d_set_cmdlist) | ||
195 | #define DRM_IOCTL_EXYNOS_G2D_EXEC DRM_IOWR(DRM_COMMAND_BASE + \ | ||
196 | DRM_EXYNOS_G2D_EXEC, struct drm_exynos_g2d_exec) | ||
197 | |||
198 | /* EXYNOS specific events */ | ||
199 | #define DRM_EXYNOS_G2D_EVENT 0x80000000 | ||
200 | |||
201 | struct drm_exynos_g2d_event { | ||
202 | struct drm_event base; | ||
203 | __u64 user_data; | ||
204 | __u32 tv_sec; | ||
205 | __u32 tv_usec; | ||
206 | __u32 cmdlist_no; | ||
207 | __u32 reserved; | ||
208 | }; | ||
152 | 209 | ||
153 | #ifdef __KERNEL__ | 210 | #ifdef __KERNEL__ |
154 | 211 | ||
155 | /** | 212 | /** |
156 | * A structure for lcd panel information. | 213 | * A structure for lcd panel information. |
157 | * | 214 | * |
158 | * @timing: default video mode for initializing | 215 | * @timing: default video mode for initializing |
159 | * @width_mm: physical size of lcd width. | 216 | * @width_mm: physical size of lcd width. |
160 | * @height_mm: physical size of lcd height. | 217 | * @height_mm: physical size of lcd height. |
161 | */ | 218 | */ |
162 | struct exynos_drm_panel_info { | 219 | struct exynos_drm_panel_info { |
163 | struct fb_videomode timing; | 220 | struct fb_videomode timing; |
164 | u32 width_mm; | 221 | u32 width_mm; |
165 | u32 height_mm; | 222 | u32 height_mm; |
166 | }; | 223 | }; |
167 | 224 | ||
168 | /** | 225 | /** |
169 | * Platform Specific Structure for DRM based FIMD. | 226 | * Platform Specific Structure for DRM based FIMD. |
170 | * | 227 | * |
171 | * @panel: default panel info for initializing | 228 | * @panel: default panel info for initializing |
172 | * @default_win: default window layer number to be used for UI. | 229 | * @default_win: default window layer number to be used for UI. |
173 | * @bpp: default bit per pixel. | 230 | * @bpp: default bit per pixel. |
174 | */ | 231 | */ |
175 | struct exynos_drm_fimd_pdata { | 232 | struct exynos_drm_fimd_pdata { |
176 | struct exynos_drm_panel_info panel; | 233 | struct exynos_drm_panel_info panel; |
177 | u32 vidcon0; | 234 | u32 vidcon0; |
178 | u32 vidcon1; | 235 | u32 vidcon1; |
179 | unsigned int default_win; | 236 | unsigned int default_win; |
180 | unsigned int bpp; | 237 | unsigned int bpp; |
181 | }; | 238 | }; |
182 | 239 | ||
183 | /** | 240 | /** |
184 | * Platform Specific Structure for DRM based HDMI. | 241 | * Platform Specific Structure for DRM based HDMI. |
185 | * | 242 | * |
186 | * @hdmi_dev: device point to specific hdmi driver. | 243 | * @hdmi_dev: device point to specific hdmi driver. |
187 | * @mixer_dev: device point to specific mixer driver. | 244 | * @mixer_dev: device point to specific mixer driver. |
188 | * | 245 | * |
189 | * this structure is used for common hdmi driver and each device object | 246 | * this structure is used for common hdmi driver and each device object |
190 | * would be used to access specific device driver(hdmi or mixer driver) | 247 | * would be used to access specific device driver(hdmi or mixer driver) |
191 | */ | 248 | */ |
192 | struct exynos_drm_common_hdmi_pd { | 249 | struct exynos_drm_common_hdmi_pd { |
193 | struct device *hdmi_dev; | 250 | struct device *hdmi_dev; |
194 | struct device *mixer_dev; | 251 | struct device *mixer_dev; |
195 | }; | 252 | }; |
196 | 253 | ||
197 | /** | 254 | /** |
198 | * Platform Specific Structure for DRM based HDMI core. | 255 | * Platform Specific Structure for DRM based HDMI core. |
199 | * | 256 | * |
200 | * @is_v13: set if hdmi version 13 is. | 257 | * @is_v13: set if hdmi version 13 is. |
201 | * @cfg_hpd: function pointer to configure hdmi hotplug detection pin | 258 | * @cfg_hpd: function pointer to configure hdmi hotplug detection pin |
202 | * @get_hpd: function pointer to get value of hdmi hotplug detection pin | 259 | * @get_hpd: function pointer to get value of hdmi hotplug detection pin |
203 | */ | 260 | */ |
204 | struct exynos_drm_hdmi_pdata { | 261 | struct exynos_drm_hdmi_pdata { |
205 | bool is_v13; | 262 | bool is_v13; |
206 | void (*cfg_hpd)(bool external); | 263 | void (*cfg_hpd)(bool external); |
207 | int (*get_hpd)(void); | 264 | int (*get_hpd)(void); |
208 | }; | 265 | }; |
209 | 266 | ||
210 | #endif /* __KERNEL__ */ | 267 | #endif /* __KERNEL__ */ |
211 | #endif /* _EXYNOS_DRM_H_ */ | 268 | #endif /* _EXYNOS_DRM_H_ */ |
212 | 269 |