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 <drm/drmP.h> 30 #include <drm/drm_crtc.h> 31 #include <drm/drm_crtc_helper.h> 32 #include <drm/drm_fb_helper.h> 33 34 #include "exynos_drm_drv.h" 35 #include "exynos_drm_fb.h" 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. 44 * @buf_cnt: a buffer count to drm framebuffer. 45 * @exynos_gem_obj: array of exynos specific gem object containing a gem object. 46 */ 47 struct exynos_drm_fb { 48 struct drm_framebuffer fb; 49 unsigned int buf_cnt; 50 struct exynos_drm_gem_obj *exynos_gem_obj[MAX_FB_BUFFER]; 51 }; 52 53 static void exynos_drm_fb_destroy(struct drm_framebuffer *fb) 54 { 55 struct exynos_drm_fb *exynos_fb = to_exynos_fb(fb); 56 unsigned int i; 57 58 DRM_DEBUG_KMS("%s\n", __FILE__); 59 60 drm_framebuffer_cleanup(fb); 61 62 for (i = 0; i < ARRAY_SIZE(exynos_fb->exynos_gem_obj); i++) { 63 struct drm_gem_object *obj; 64 65 if (exynos_fb->exynos_gem_obj[i] == NULL) 66 continue; 67 68 obj = &exynos_fb->exynos_gem_obj[i]->base; 69 drm_gem_object_unreference_unlocked(obj); 70 } 71 72 kfree(exynos_fb); 73 exynos_fb = NULL; 74 } 75 76 static int exynos_drm_fb_create_handle(struct drm_framebuffer *fb, 77 struct drm_file *file_priv, 78 unsigned int *handle) 79 { 80 struct exynos_drm_fb *exynos_fb = to_exynos_fb(fb); 81 82 DRM_DEBUG_KMS("%s\n", __FILE__); 83 84 return drm_gem_handle_create(file_priv, 85 &exynos_fb->exynos_gem_obj[0]->base, handle); 86 } 87 88 static int exynos_drm_fb_dirty(struct drm_framebuffer *fb, 89 struct drm_file *file_priv, unsigned flags, 90 unsigned color, struct drm_clip_rect *clips, 91 unsigned num_clips) 92 { 93 DRM_DEBUG_KMS("%s\n", __FILE__); 94 95 /* TODO */ 96 97 return 0; 98 } 99 100 static struct drm_framebuffer_funcs exynos_drm_fb_funcs = { 101 .destroy = exynos_drm_fb_destroy, 102 .create_handle = exynos_drm_fb_create_handle, 103 .dirty = exynos_drm_fb_dirty, 104 }; 105 106 void exynos_drm_fb_set_buf_cnt(struct drm_framebuffer *fb, 107 unsigned int cnt) 108 { 109 struct exynos_drm_fb *exynos_fb; 110 111 exynos_fb = to_exynos_fb(fb); 112 113 exynos_fb->buf_cnt = cnt; 114 } 115 116 unsigned int exynos_drm_fb_get_buf_cnt(struct drm_framebuffer *fb) 117 { 118 struct exynos_drm_fb *exynos_fb; 119 120 exynos_fb = to_exynos_fb(fb); 121 122 return exynos_fb->buf_cnt; 123 } 124 125 struct drm_framebuffer * 126 exynos_drm_framebuffer_init(struct drm_device *dev, 127 struct drm_mode_fb_cmd2 *mode_cmd, 128 struct drm_gem_object *obj) 129 { 130 struct exynos_drm_fb *exynos_fb; 131 int ret; 132 133 exynos_fb = kzalloc(sizeof(*exynos_fb), GFP_KERNEL); 134 if (!exynos_fb) { 135 DRM_ERROR("failed to allocate exynos drm framebuffer\n"); 136 return ERR_PTR(-ENOMEM); 137 } 138 139 ret = drm_framebuffer_init(dev, &exynos_fb->fb, &exynos_drm_fb_funcs); 140 if (ret) { 141 DRM_ERROR("failed to initialize framebuffer\n"); 142 return ERR_PTR(ret); 143 } 144 145 drm_helper_mode_fill_fb_struct(&exynos_fb->fb, mode_cmd); 146 exynos_fb->exynos_gem_obj[0] = to_exynos_gem_obj(obj); 147 148 return &exynos_fb->fb; 149 } 150 151 static u32 exynos_drm_format_num_buffers(struct drm_mode_fb_cmd2 *mode_cmd) 152 { 153 unsigned int cnt = 0; 154 155 if (mode_cmd->pixel_format != DRM_FORMAT_NV12) 156 return drm_format_num_planes(mode_cmd->pixel_format); 157 158 while (cnt != MAX_FB_BUFFER) { 159 if (!mode_cmd->handles[cnt]) 160 break; 161 cnt++; 162 } 163 164 /* 165 * check if NV12 or NV12M. 166 * 167 * NV12 168 * handles[0] = base1, offsets[0] = 0 169 * handles[1] = base1, offsets[1] = Y_size 170 * 171 * NV12M 172 * handles[0] = base1, offsets[0] = 0 173 * handles[1] = base2, offsets[1] = 0 174 */ 175 if (cnt == 2) { 176 /* 177 * in case of NV12 format, offsets[1] is not 0 and 178 * handles[0] is same as handles[1]. 179 */ 180 if (mode_cmd->offsets[1] && 181 mode_cmd->handles[0] == mode_cmd->handles[1]) 182 cnt = 1; 183 } 184 185 return cnt; 186 } 187 188 static struct drm_framebuffer * 189 exynos_user_fb_create(struct drm_device *dev, struct drm_file *file_priv, 190 struct drm_mode_fb_cmd2 *mode_cmd) 191 { 192 struct drm_gem_object *obj; 193 struct drm_framebuffer *fb; 194 struct exynos_drm_fb *exynos_fb; 195 int i; 196 197 DRM_DEBUG_KMS("%s\n", __FILE__); 198 199 obj = drm_gem_object_lookup(dev, file_priv, mode_cmd->handles[0]); 200 if (!obj) { 201 DRM_ERROR("failed to lookup gem object\n"); 202 return ERR_PTR(-ENOENT); 203 } 204 205 fb = exynos_drm_framebuffer_init(dev, mode_cmd, obj); 206 if (IS_ERR(fb)) { 207 drm_gem_object_unreference_unlocked(obj); 208 return fb; 209 } 210 211 exynos_fb = to_exynos_fb(fb); 212 exynos_fb->buf_cnt = exynos_drm_format_num_buffers(mode_cmd); 213 214 DRM_DEBUG_KMS("buf_cnt = %d\n", exynos_fb->buf_cnt); 215 216 for (i = 1; i < exynos_fb->buf_cnt; i++) { 217 obj = drm_gem_object_lookup(dev, file_priv, 218 mode_cmd->handles[i]); 219 if (!obj) { 220 DRM_ERROR("failed to lookup gem object\n"); 221 exynos_drm_fb_destroy(fb); 222 return ERR_PTR(-ENOENT); 223 } 224 225 exynos_fb->exynos_gem_obj[i] = to_exynos_gem_obj(obj); 226 } 227 228 return fb; 229 } 230 231 struct exynos_drm_gem_buf *exynos_drm_fb_buffer(struct drm_framebuffer *fb, 232 int index) 233 { 234 struct exynos_drm_fb *exynos_fb = to_exynos_fb(fb); 235 struct exynos_drm_gem_buf *buffer; 236 237 DRM_DEBUG_KMS("%s\n", __FILE__); 238 239 if (index >= MAX_FB_BUFFER) 240 return NULL; 241 242 buffer = exynos_fb->exynos_gem_obj[index]->buffer; 243 if (!buffer) 244 return NULL; 245 246 DRM_DEBUG_KMS("vaddr = 0x%lx, dma_addr = 0x%lx\n", 247 (unsigned long)buffer->kvaddr, 248 (unsigned long)buffer->dma_addr); 249 250 return buffer; 251 } 252 253 static void exynos_drm_output_poll_changed(struct drm_device *dev) 254 { 255 struct exynos_drm_private *private = dev->dev_private; 256 struct drm_fb_helper *fb_helper = private->fb_helper; 257 258 if (fb_helper) 259 drm_fb_helper_hotplug_event(fb_helper); 260 } 261 262 static const struct drm_mode_config_funcs exynos_drm_mode_config_funcs = { 263 .fb_create = exynos_user_fb_create, 264 .output_poll_changed = exynos_drm_output_poll_changed, 265 }; 266 267 void exynos_drm_mode_config_init(struct drm_device *dev) 268 { 269 dev->mode_config.min_width = 0; 270 dev->mode_config.min_height = 0; 271 272 /* 273 * set max width and height as default value(4096x4096). 274 * this value would be used to check framebuffer size limitation 275 * at drm_mode_addfb(). 276 */ 277 dev->mode_config.max_width = 4096; 278 dev->mode_config.max_height = 4096; 279 280 dev->mode_config.funcs = &exynos_drm_mode_config_funcs; 281 } 282