Commit | Line | Data |
---|---|---|
1c248b7d ID |
1 | /* exynos_drm_fb.c |
2 | * | |
3 | * Copyright (c) 2011 Samsung Electronics Co., Ltd. | |
4 | * Authors: | |
5 | * Inki Dae <inki.dae@samsung.com> | |
6 | * Joonyoung Shim <jy0922.shim@samsung.com> | |
7 | * Seung-Woo Kim <sw0312.kim@samsung.com> | |
8 | * | |
9 | * Permission is hereby granted, free of charge, to any person obtaining a | |
10 | * copy of this software and associated documentation files (the "Software"), | |
11 | * to deal in the Software without restriction, including without limitation | |
12 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, | |
13 | * and/or sell copies of the Software, and to permit persons to whom the | |
14 | * Software is furnished to do so, subject to the following conditions: | |
15 | * | |
16 | * The above copyright notice and this permission notice (including the next | |
17 | * paragraph) shall be included in all copies or substantial portions of the | |
18 | * Software. | |
19 | * | |
20 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
21 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
22 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | |
23 | * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR | |
24 | * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, | |
25 | * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR | |
26 | * OTHER DEALINGS IN THE SOFTWARE. | |
27 | */ | |
28 | ||
760285e7 DH |
29 | #include <drm/drmP.h> |
30 | #include <drm/drm_crtc.h> | |
31 | #include <drm/drm_crtc_helper.h> | |
32 | #include <drm/drm_fb_helper.h> | |
1c248b7d | 33 | |
7db3eba6 | 34 | #include "exynos_drm_drv.h" |
1c248b7d | 35 | #include "exynos_drm_fb.h" |
1c248b7d ID |
36 | #include "exynos_drm_gem.h" |
37 | ||
38 | #define to_exynos_fb(x) container_of(x, struct exynos_drm_fb, fb) | |
39 | ||
40 | /* | |
41 | * exynos specific framebuffer structure. | |
42 | * | |
43 | * @fb: drm framebuffer obejct. | |
229d3534 | 44 | * @exynos_gem_obj: array of exynos specific gem object containing a gem object. |
1c248b7d ID |
45 | */ |
46 | struct exynos_drm_fb { | |
47 | struct drm_framebuffer fb; | |
229d3534 | 48 | struct exynos_drm_gem_obj *exynos_gem_obj[MAX_FB_BUFFER]; |
1c248b7d ID |
49 | }; |
50 | ||
51 | static void exynos_drm_fb_destroy(struct drm_framebuffer *fb) | |
52 | { | |
53 | struct exynos_drm_fb *exynos_fb = to_exynos_fb(fb); | |
07b6835f | 54 | unsigned int i; |
1c248b7d ID |
55 | |
56 | DRM_DEBUG_KMS("%s\n", __FILE__); | |
57 | ||
58 | drm_framebuffer_cleanup(fb); | |
59 | ||
07b6835f LP |
60 | for (i = 0; i < ARRAY_SIZE(exynos_fb->exynos_gem_obj); i++) { |
61 | struct drm_gem_object *obj; | |
62 | ||
63 | if (exynos_fb->exynos_gem_obj[i] == NULL) | |
64 | continue; | |
65 | ||
66 | obj = &exynos_fb->exynos_gem_obj[i]->base; | |
67 | drm_gem_object_unreference_unlocked(obj); | |
68 | } | |
69 | ||
1c248b7d ID |
70 | kfree(exynos_fb); |
71 | exynos_fb = NULL; | |
72 | } | |
73 | ||
74 | static int exynos_drm_fb_create_handle(struct drm_framebuffer *fb, | |
75 | struct drm_file *file_priv, | |
76 | unsigned int *handle) | |
77 | { | |
78 | struct exynos_drm_fb *exynos_fb = to_exynos_fb(fb); | |
79 | ||
80 | DRM_DEBUG_KMS("%s\n", __FILE__); | |
81 | ||
82 | return drm_gem_handle_create(file_priv, | |
229d3534 | 83 | &exynos_fb->exynos_gem_obj[0]->base, handle); |
1c248b7d ID |
84 | } |
85 | ||
86 | static int exynos_drm_fb_dirty(struct drm_framebuffer *fb, | |
87 | struct drm_file *file_priv, unsigned flags, | |
88 | unsigned color, struct drm_clip_rect *clips, | |
89 | unsigned num_clips) | |
90 | { | |
91 | DRM_DEBUG_KMS("%s\n", __FILE__); | |
92 | ||
93 | /* TODO */ | |
94 | ||
95 | return 0; | |
96 | } | |
97 | ||
98 | static struct drm_framebuffer_funcs exynos_drm_fb_funcs = { | |
99 | .destroy = exynos_drm_fb_destroy, | |
100 | .create_handle = exynos_drm_fb_create_handle, | |
101 | .dirty = exynos_drm_fb_dirty, | |
102 | }; | |
103 | ||
e1533c08 JS |
104 | struct drm_framebuffer * |
105 | exynos_drm_framebuffer_init(struct drm_device *dev, | |
106 | struct drm_mode_fb_cmd2 *mode_cmd, | |
107 | struct drm_gem_object *obj) | |
1c248b7d ID |
108 | { |
109 | struct exynos_drm_fb *exynos_fb; | |
1c248b7d ID |
110 | int ret; |
111 | ||
1c248b7d ID |
112 | exynos_fb = kzalloc(sizeof(*exynos_fb), GFP_KERNEL); |
113 | if (!exynos_fb) { | |
e1533c08 | 114 | DRM_ERROR("failed to allocate exynos drm framebuffer\n"); |
1c248b7d ID |
115 | return ERR_PTR(-ENOMEM); |
116 | } | |
117 | ||
e1533c08 | 118 | ret = drm_framebuffer_init(dev, &exynos_fb->fb, &exynos_drm_fb_funcs); |
1c248b7d | 119 | if (ret) { |
e1533c08 JS |
120 | DRM_ERROR("failed to initialize framebuffer\n"); |
121 | return ERR_PTR(ret); | |
1c248b7d ID |
122 | } |
123 | ||
e1533c08 | 124 | drm_helper_mode_fill_fb_struct(&exynos_fb->fb, mode_cmd); |
229d3534 | 125 | exynos_fb->exynos_gem_obj[0] = to_exynos_gem_obj(obj); |
1c248b7d | 126 | |
e1533c08 | 127 | return &exynos_fb->fb; |
1c248b7d ID |
128 | } |
129 | ||
e1533c08 JS |
130 | static struct drm_framebuffer * |
131 | exynos_user_fb_create(struct drm_device *dev, struct drm_file *file_priv, | |
132 | struct drm_mode_fb_cmd2 *mode_cmd) | |
1c248b7d | 133 | { |
e1533c08 | 134 | struct drm_gem_object *obj; |
229d3534 SWK |
135 | struct drm_framebuffer *fb; |
136 | struct exynos_drm_fb *exynos_fb; | |
137 | int nr; | |
138 | int i; | |
e1533c08 | 139 | |
1c248b7d ID |
140 | DRM_DEBUG_KMS("%s\n", __FILE__); |
141 | ||
e1533c08 JS |
142 | obj = drm_gem_object_lookup(dev, file_priv, mode_cmd->handles[0]); |
143 | if (!obj) { | |
144 | DRM_ERROR("failed to lookup gem object\n"); | |
145 | return ERR_PTR(-ENOENT); | |
146 | } | |
147 | ||
229d3534 | 148 | fb = exynos_drm_framebuffer_init(dev, mode_cmd, obj); |
07b6835f LP |
149 | if (IS_ERR(fb)) { |
150 | drm_gem_object_unreference_unlocked(obj); | |
229d3534 | 151 | return fb; |
07b6835f | 152 | } |
229d3534 SWK |
153 | |
154 | exynos_fb = to_exynos_fb(fb); | |
155 | nr = exynos_drm_format_num_buffers(fb->pixel_format); | |
156 | ||
157 | for (i = 1; i < nr; i++) { | |
158 | obj = drm_gem_object_lookup(dev, file_priv, | |
159 | mode_cmd->handles[i]); | |
160 | if (!obj) { | |
161 | DRM_ERROR("failed to lookup gem object\n"); | |
162 | exynos_drm_fb_destroy(fb); | |
163 | return ERR_PTR(-ENOENT); | |
164 | } | |
165 | ||
229d3534 SWK |
166 | exynos_fb->exynos_gem_obj[i] = to_exynos_gem_obj(obj); |
167 | } | |
168 | ||
169 | return fb; | |
1c248b7d ID |
170 | } |
171 | ||
229d3534 SWK |
172 | struct exynos_drm_gem_buf *exynos_drm_fb_buffer(struct drm_framebuffer *fb, |
173 | int index) | |
1c248b7d ID |
174 | { |
175 | struct exynos_drm_fb *exynos_fb = to_exynos_fb(fb); | |
2c871127 | 176 | struct exynos_drm_gem_buf *buffer; |
1c248b7d ID |
177 | |
178 | DRM_DEBUG_KMS("%s\n", __FILE__); | |
179 | ||
229d3534 SWK |
180 | if (index >= MAX_FB_BUFFER) |
181 | return NULL; | |
182 | ||
183 | buffer = exynos_fb->exynos_gem_obj[index]->buffer; | |
2c871127 | 184 | if (!buffer) |
19c8b834 | 185 | return NULL; |
1c248b7d | 186 | |
2c871127 ID |
187 | DRM_DEBUG_KMS("vaddr = 0x%lx, dma_addr = 0x%lx\n", |
188 | (unsigned long)buffer->kvaddr, | |
189 | (unsigned long)buffer->dma_addr); | |
1c248b7d | 190 | |
2c871127 | 191 | return buffer; |
1c248b7d ID |
192 | } |
193 | ||
7db3eba6 SWK |
194 | static void exynos_drm_output_poll_changed(struct drm_device *dev) |
195 | { | |
196 | struct exynos_drm_private *private = dev->dev_private; | |
197 | struct drm_fb_helper *fb_helper = private->fb_helper; | |
198 | ||
199 | if (fb_helper) | |
200 | drm_fb_helper_hotplug_event(fb_helper); | |
201 | } | |
202 | ||
e6ecefaa | 203 | static const struct drm_mode_config_funcs exynos_drm_mode_config_funcs = { |
e1533c08 | 204 | .fb_create = exynos_user_fb_create, |
7db3eba6 | 205 | .output_poll_changed = exynos_drm_output_poll_changed, |
1c248b7d ID |
206 | }; |
207 | ||
208 | void exynos_drm_mode_config_init(struct drm_device *dev) | |
209 | { | |
210 | dev->mode_config.min_width = 0; | |
211 | dev->mode_config.min_height = 0; | |
212 | ||
213 | /* | |
214 | * set max width and height as default value(4096x4096). | |
215 | * this value would be used to check framebuffer size limitation | |
216 | * at drm_mode_addfb(). | |
217 | */ | |
218 | dev->mode_config.max_width = 4096; | |
219 | dev->mode_config.max_height = 4096; | |
220 | ||
221 | dev->mode_config.funcs = &exynos_drm_mode_config_funcs; | |
222 | } |