]>
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 | ||
29 | #include "drmP.h" | |
30 | #include "drm_crtc.h" | |
31 | #include "drm_crtc_helper.h" | |
32 | ||
33 | #include "exynos_drm_fb.h" | |
34 | #include "exynos_drm_buf.h" | |
35 | #include "exynos_drm_gem.h" | |
36 | ||
37 | #define to_exynos_fb(x) container_of(x, struct exynos_drm_fb, fb) | |
38 | ||
39 | /* | |
40 | * exynos specific framebuffer structure. | |
41 | * | |
42 | * @fb: drm framebuffer obejct. | |
43 | * @exynos_gem_obj: exynos specific gem object containing a gem object. | |
44 | * @entry: pointer to exynos drm buffer entry object. | |
45 | * - containing only the information to physically continuous memory | |
46 | * region allocated at default framebuffer creation. | |
47 | */ | |
48 | struct exynos_drm_fb { | |
49 | struct drm_framebuffer fb; | |
50 | struct exynos_drm_gem_obj *exynos_gem_obj; | |
51 | struct exynos_drm_buf_entry *entry; | |
52 | }; | |
53 | ||
54 | static void exynos_drm_fb_destroy(struct drm_framebuffer *fb) | |
55 | { | |
56 | struct exynos_drm_fb *exynos_fb = to_exynos_fb(fb); | |
57 | ||
58 | DRM_DEBUG_KMS("%s\n", __FILE__); | |
59 | ||
60 | drm_framebuffer_cleanup(fb); | |
61 | ||
62 | /* | |
63 | * default framebuffer has no gem object so | |
64 | * a buffer of the default framebuffer should be released at here. | |
65 | */ | |
66 | if (!exynos_fb->exynos_gem_obj && exynos_fb->entry) | |
67 | exynos_drm_buf_destroy(fb->dev, exynos_fb->entry); | |
68 | ||
69 | kfree(exynos_fb); | |
70 | exynos_fb = NULL; | |
71 | } | |
72 | ||
73 | static int exynos_drm_fb_create_handle(struct drm_framebuffer *fb, | |
74 | struct drm_file *file_priv, | |
75 | unsigned int *handle) | |
76 | { | |
77 | struct exynos_drm_fb *exynos_fb = to_exynos_fb(fb); | |
78 | ||
79 | DRM_DEBUG_KMS("%s\n", __FILE__); | |
80 | ||
81 | return drm_gem_handle_create(file_priv, | |
82 | &exynos_fb->exynos_gem_obj->base, handle); | |
83 | } | |
84 | ||
85 | static int exynos_drm_fb_dirty(struct drm_framebuffer *fb, | |
86 | struct drm_file *file_priv, unsigned flags, | |
87 | unsigned color, struct drm_clip_rect *clips, | |
88 | unsigned num_clips) | |
89 | { | |
90 | DRM_DEBUG_KMS("%s\n", __FILE__); | |
91 | ||
92 | /* TODO */ | |
93 | ||
94 | return 0; | |
95 | } | |
96 | ||
97 | static struct drm_framebuffer_funcs exynos_drm_fb_funcs = { | |
98 | .destroy = exynos_drm_fb_destroy, | |
99 | .create_handle = exynos_drm_fb_create_handle, | |
100 | .dirty = exynos_drm_fb_dirty, | |
101 | }; | |
102 | ||
103 | static struct drm_framebuffer * | |
104 | exynos_drm_fb_init(struct drm_file *file_priv, struct drm_device *dev, | |
105 | struct drm_mode_fb_cmd *mode_cmd) | |
106 | { | |
107 | struct exynos_drm_fb *exynos_fb; | |
108 | struct drm_framebuffer *fb; | |
109 | struct exynos_drm_gem_obj *exynos_gem_obj = NULL; | |
110 | struct drm_gem_object *obj; | |
111 | unsigned int size; | |
112 | int ret; | |
113 | ||
114 | DRM_DEBUG_KMS("%s\n", __FILE__); | |
115 | ||
116 | mode_cmd->pitch = max(mode_cmd->pitch, | |
117 | mode_cmd->width * (mode_cmd->bpp >> 3)); | |
118 | ||
119 | DRM_LOG_KMS("drm fb create(%dx%d)\n", | |
120 | mode_cmd->width, mode_cmd->height); | |
121 | ||
122 | exynos_fb = kzalloc(sizeof(*exynos_fb), GFP_KERNEL); | |
123 | if (!exynos_fb) { | |
124 | DRM_ERROR("failed to allocate exynos drm framebuffer.\n"); | |
125 | return ERR_PTR(-ENOMEM); | |
126 | } | |
127 | ||
128 | fb = &exynos_fb->fb; | |
129 | ret = drm_framebuffer_init(dev, fb, &exynos_drm_fb_funcs); | |
130 | if (ret) { | |
131 | DRM_ERROR("failed to initialize framebuffer.\n"); | |
132 | goto err_init; | |
133 | } | |
134 | ||
135 | DRM_LOG_KMS("create: fb id: %d\n", fb->base.id); | |
136 | ||
137 | size = mode_cmd->pitch * mode_cmd->height; | |
138 | ||
139 | /* | |
140 | * mode_cmd->handle could be NULL at booting time or | |
141 | * with user request. if NULL, a new buffer or a gem object | |
142 | * would be allocated. | |
143 | */ | |
144 | if (!mode_cmd->handle) { | |
145 | if (!file_priv) { | |
146 | struct exynos_drm_buf_entry *entry; | |
147 | ||
148 | /* | |
149 | * in case that file_priv is NULL, it allocates | |
150 | * only buffer and this buffer would be used | |
151 | * for default framebuffer. | |
152 | */ | |
153 | entry = exynos_drm_buf_create(dev, size); | |
154 | if (IS_ERR(entry)) { | |
155 | ret = PTR_ERR(entry); | |
156 | goto err_buffer; | |
157 | } | |
158 | ||
159 | exynos_fb->entry = entry; | |
160 | ||
161 | DRM_LOG_KMS("default fb: paddr = 0x%lx, size = 0x%x\n", | |
162 | (unsigned long)entry->paddr, size); | |
163 | ||
164 | goto out; | |
165 | } else { | |
166 | exynos_gem_obj = exynos_drm_gem_create(file_priv, dev, | |
167 | size, | |
168 | &mode_cmd->handle); | |
169 | if (IS_ERR(exynos_gem_obj)) { | |
170 | ret = PTR_ERR(exynos_gem_obj); | |
171 | goto err_buffer; | |
172 | } | |
173 | } | |
174 | } else { | |
175 | obj = drm_gem_object_lookup(dev, file_priv, mode_cmd->handle); | |
176 | if (!obj) { | |
177 | DRM_ERROR("failed to lookup gem object.\n"); | |
178 | goto err_buffer; | |
179 | } | |
180 | ||
181 | exynos_gem_obj = to_exynos_gem_obj(obj); | |
182 | ||
183 | drm_gem_object_unreference_unlocked(obj); | |
184 | } | |
185 | ||
186 | /* | |
187 | * if got a exynos_gem_obj from either a handle or | |
188 | * a new creation then exynos_fb->exynos_gem_obj is NULL | |
189 | * so that default framebuffer has no its own gem object, | |
190 | * only its own buffer object. | |
191 | */ | |
192 | exynos_fb->entry = exynos_gem_obj->entry; | |
193 | ||
194 | DRM_LOG_KMS("paddr = 0x%lx, size = 0x%x, gem object = 0x%x\n", | |
195 | (unsigned long)exynos_fb->entry->paddr, size, | |
196 | (unsigned int)&exynos_gem_obj->base); | |
197 | ||
198 | out: | |
199 | exynos_fb->exynos_gem_obj = exynos_gem_obj; | |
200 | ||
201 | drm_helper_mode_fill_fb_struct(fb, mode_cmd); | |
202 | ||
203 | return fb; | |
204 | ||
205 | err_buffer: | |
206 | drm_framebuffer_cleanup(fb); | |
207 | ||
208 | err_init: | |
209 | kfree(exynos_fb); | |
210 | ||
211 | return ERR_PTR(ret); | |
212 | } | |
213 | ||
214 | struct drm_framebuffer *exynos_drm_fb_create(struct drm_device *dev, | |
215 | struct drm_file *file_priv, | |
216 | struct drm_mode_fb_cmd *mode_cmd) | |
217 | { | |
218 | DRM_DEBUG_KMS("%s\n", __FILE__); | |
219 | ||
220 | return exynos_drm_fb_init(file_priv, dev, mode_cmd); | |
221 | } | |
222 | ||
223 | void exynos_drm_fb_update_buf_off(struct drm_framebuffer *fb, | |
224 | unsigned int x, unsigned int y, | |
225 | struct exynos_drm_buffer_info *info) | |
226 | { | |
227 | struct exynos_drm_fb *exynos_fb = to_exynos_fb(fb); | |
228 | struct exynos_drm_buf_entry *entry; | |
229 | unsigned long offset; | |
230 | ||
231 | DRM_DEBUG_KMS("%s\n", __FILE__); | |
232 | ||
233 | offset = x * (fb->bits_per_pixel >> 3); | |
234 | offset += y * fb->pitch; | |
235 | ||
236 | entry = exynos_fb->entry; | |
237 | ||
238 | info->base_addr = entry->paddr; | |
239 | info->vaddr = entry->vaddr + offset; | |
240 | info->paddr = entry->paddr + offset; | |
241 | ||
242 | DRM_DEBUG_KMS("updated vaddr = 0x%lx, paddr = 0x%lx, offset = 0x%x\n", | |
243 | (unsigned long)info->vaddr, (unsigned long)info->paddr, | |
244 | (unsigned int)offset); | |
245 | } | |
246 | ||
247 | static struct drm_mode_config_funcs exynos_drm_mode_config_funcs = { | |
248 | .fb_create = exynos_drm_fb_create, | |
249 | }; | |
250 | ||
251 | void exynos_drm_mode_config_init(struct drm_device *dev) | |
252 | { | |
253 | dev->mode_config.min_width = 0; | |
254 | dev->mode_config.min_height = 0; | |
255 | ||
256 | /* | |
257 | * set max width and height as default value(4096x4096). | |
258 | * this value would be used to check framebuffer size limitation | |
259 | * at drm_mode_addfb(). | |
260 | */ | |
261 | dev->mode_config.max_width = 4096; | |
262 | dev->mode_config.max_height = 4096; | |
263 | ||
264 | dev->mode_config.funcs = &exynos_drm_mode_config_funcs; | |
265 | } | |
266 | ||
267 | MODULE_AUTHOR("Inki Dae <inki.dae@samsung.com>"); | |
268 | MODULE_AUTHOR("Joonyoung Shim <jy0922.shim@samsung.com>"); | |
269 | MODULE_AUTHOR("Seung-Woo Kim <sw0312.kim@samsung.com>"); | |
270 | MODULE_DESCRIPTION("Samsung SoC DRM FB Driver"); | |
271 | MODULE_LICENSE("GPL"); |