OSDN Git Service

add support for debug.drm.mode
[android-x86/external-drm_gralloc.git] / gralloc_drm_nouveau.c
1 /*
2  * Copyright (C) 2011 Chia-I Wu <olvaffe@gmail.com>
3  * Copyright (C) 2011 LunarG Inc.
4  *
5  * Based on xf86-video-nouveau, which has
6  *
7  * Copyright © 2007 Red Hat, Inc.
8  * Copyright © 2008 Maarten Maathuis
9  *
10  * Permission is hereby granted, free of charge, to any person obtaining a
11  * copy of this software and associated documentation files (the "Software"),
12  * to deal in the Software without restriction, including without limitation
13  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
14  * and/or sell copies of the Software, and to permit persons to whom the
15  * Software is furnished to do so, subject to the following conditions:
16  *
17  * The above copyright notice and this permission notice shall be included
18  * in all copies or substantial portions of the 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  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
25  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
26  * DEALINGS IN THE SOFTWARE.
27  */
28
29 #define LOG_TAG "GRALLOC-NOUVEAU"
30
31 #include <cutils/log.h>
32 #include <stdlib.h>
33 #include <errno.h>
34 #include <drm.h>
35 #include <nouveau_drmif.h>
36 #include <nouveau_channel.h>
37 #include <nouveau_bo.h>
38
39 #include "gralloc_drm.h"
40 #include "gralloc_drm_priv.h"
41
42 #define MAX(a, b) (((a) > (b)) ? (a) : (b))
43 #define ALIGN(val, align) (((val) + (align) - 1) & ~((align) - 1))
44
45 #define NVC0_TILE_HEIGHT(m) (8 << ((m) >> 4))
46
47 enum {
48         NvDmaFB = 0xd8000001,
49         NvDmaTT = 0xd8000002,
50 };
51
52 struct nouveau_info {
53         struct gralloc_drm_drv_t base;
54
55         int fd;
56         struct nouveau_device *dev;
57         struct nouveau_channel *chan;
58         int arch;
59         int tiled_scanout;
60 };
61
62 struct nouveau_buffer {
63         struct gralloc_drm_bo_t base;
64
65         struct nouveau_bo *bo;
66 };
67
68 static struct nouveau_bo *alloc_bo(struct nouveau_info *info,
69                 int width, int height, int cpp, int usage, int *pitch)
70 {
71         struct nouveau_bo *bo = NULL;
72         int flags, tile_mode, tile_flags;
73         int tiled, scanout;
74         unsigned int align;
75
76         flags = NOUVEAU_BO_MAP | NOUVEAU_BO_VRAM;
77         tile_mode = 0;
78         tile_flags = 0;
79
80         scanout = !!(usage & GRALLOC_USAGE_HW_FB);
81
82         tiled = !(usage & (GRALLOC_USAGE_SW_READ_OFTEN |
83                            GRALLOC_USAGE_SW_WRITE_OFTEN));
84         if (!info->chan)
85                 tiled = 0;
86         else if (scanout && info->tiled_scanout)
87                 tiled = 1;
88
89         /* calculate pitch align */
90         align = 64;
91         if (info->arch >= 0x50) {
92                 if (scanout && !info->tiled_scanout)
93                         align = 256;
94                 else
95                         tiled = 1;
96         }
97
98         *pitch = ALIGN(width * cpp, align);
99
100         if (tiled) {
101                 if (info->arch >= 0xc0) {
102                         if (height > 64)
103                                 tile_mode = 0x40;
104                         else if (height > 32)
105                                 tile_mode = 0x30;
106                         else if (height > 16)
107                                 tile_mode = 0x20;
108                         else if (height > 8)
109                                 tile_mode = 0x10;
110                         else
111                                 tile_mode = 0x00;
112
113                         tile_flags = 0xfe00;
114
115                         align = NVC0_TILE_HEIGHT(tile_mode);
116                         height = ALIGN(height, align);
117                 }
118                 else if (info->arch >= 0x50) {
119                         if (height > 32)
120                                 tile_mode = 4;
121                         else if (height > 16)
122                                 tile_mode = 3;
123                         else if (height > 8)
124                                 tile_mode = 2;
125                         else if (height > 4)
126                                 tile_mode = 1;
127                         else
128                                 tile_mode = 0;
129
130                         tile_flags = (scanout && cpp != 2) ? 0x7a00 : 0x7000;
131
132                         align = 1 << (tile_mode + 2);
133                         height = ALIGN(height, align);
134                 }
135                 else {
136                         align = *pitch / 4;
137
138                         /* round down to the previous power of two */
139                         align >>= 1;
140                         align |= align >> 1;
141                         align |= align >> 2;
142                         align |= align >> 4;
143                         align |= align >> 8;
144                         align |= align >> 16;
145                         align++;
146
147                         align = MAX((info->dev->chipset >= 0x40) ? 1024 : 256,
148                                         align);
149
150                         /* adjust pitch */
151                         *pitch = ALIGN(*pitch, align);
152
153                         tile_mode = *pitch;
154                 }
155         }
156
157         if (cpp == 4)
158                 tile_flags |= NOUVEAU_BO_TILE_32BPP;
159         else if (cpp == 2)
160                 tile_flags |= NOUVEAU_BO_TILE_16BPP;
161
162         if (scanout)
163                 tile_flags |= NOUVEAU_BO_TILE_SCANOUT;
164
165         if (nouveau_bo_new_tile(info->dev, flags, 0, *pitch * height,
166                                 tile_mode, tile_flags, &bo)) {
167                 LOGE("failed to allocate bo (flags 0x%x, size %d, tile_mode 0x%x, tile_flags 0x%x)",
168                                 flags, *pitch * height, tile_mode, tile_flags);
169                 bo = NULL;
170         }
171
172         return bo;
173 }
174
175 static struct gralloc_drm_bo_t *
176 nouveau_alloc(struct gralloc_drm_drv_t *drv, struct gralloc_drm_handle_t *handle)
177 {
178         struct nouveau_info *info = (struct nouveau_info *) drv;
179         struct nouveau_buffer *nb;
180         int cpp;
181
182         cpp = gralloc_drm_get_bpp(handle->format);
183         if (!cpp) {
184                 LOGE("unrecognized format 0x%x", handle->format);
185                 return NULL;
186         }
187
188         nb = calloc(1, sizeof(*nb));
189         if (!nb)
190                 return NULL;
191
192         if (handle->name) {
193                 if (nouveau_bo_handle_ref(info->dev, handle->name, &nb->bo)) {
194                         LOGE("failed to create nouveau bo from name %u",
195                                         handle->name);
196                         free(nb);
197                         return NULL;
198                 }
199         }
200         else {
201                 int pitch;
202
203                 nb->bo = alloc_bo(info, handle->width, handle->height,
204                                 cpp, handle->usage, &pitch);
205                 if (!nb->bo) {
206                         LOGE("failed to allocate nouveau bo %dx%dx%d",
207                                         handle->width, handle->height, cpp);
208                         free(nb);
209                         return NULL;
210                 }
211
212                 if (nouveau_bo_handle_get(nb->bo,
213                                         (uint32_t *) &handle->name)) {
214                         LOGE("failed to flink nouveau bo");
215                         nouveau_bo_ref(NULL, &nb->bo);
216                         free(nb);
217                         return NULL;
218                 }
219
220                 handle->stride = pitch;
221         }
222
223         if (handle->usage & GRALLOC_USAGE_HW_FB)
224                 nb->base.fb_handle = nb->bo->handle;
225
226         nb->base.handle = handle;
227
228         return &nb->base;
229 }
230
231 static void nouveau_free(struct gralloc_drm_drv_t *drv,
232                 struct gralloc_drm_bo_t *bo)
233 {
234         struct nouveau_buffer *nb = (struct nouveau_buffer *) bo;
235         nouveau_bo_ref(NULL, &nb->bo);
236         free(nb);
237 }
238
239 static int nouveau_map(struct gralloc_drm_drv_t *drv,
240                 struct gralloc_drm_bo_t *bo, int x, int y, int w, int h,
241                 int enable_write, void **addr)
242 {
243         struct nouveau_buffer *nb = (struct nouveau_buffer *) bo;
244         uint32_t flags;
245         int err;
246
247         flags = NOUVEAU_BO_RD;
248         if (enable_write)
249                 flags |= NOUVEAU_BO_WR;
250
251         /* TODO if tiled, allocate a linear copy of bo in GART and map it */
252         err = nouveau_bo_map(nb->bo, flags);
253         if (!err)
254                 *addr = nb->bo->map;
255
256         return err;
257 }
258
259 static void nouveau_unmap(struct gralloc_drm_drv_t *drv,
260                 struct gralloc_drm_bo_t *bo)
261 {
262         struct nouveau_buffer *nb = (struct nouveau_buffer *) bo;
263         /* TODO if tiled, unmap the linear bo and copy back */
264         nouveau_bo_unmap(nb->bo);
265 }
266
267 static void nouveau_init_kms_features(struct gralloc_drm_drv_t *drv,
268                 struct gralloc_drm_t *drm)
269 {
270         struct nouveau_info *info = (struct nouveau_info *) drv;
271
272         switch (drm->fb_format) {
273         case HAL_PIXEL_FORMAT_BGRA_8888:
274         case HAL_PIXEL_FORMAT_RGB_565:
275                 break;
276         default:
277                 drm->fb_format = HAL_PIXEL_FORMAT_BGRA_8888;
278                 break;
279         }
280
281         drm->mode_dirty_fb = 0;
282         drm->swap_mode = (info->chan) ? DRM_SWAP_FLIP : DRM_SWAP_SETCRTC;
283         drm->mode_sync_flip = 1;
284         drm->swap_interval = 1;
285         drm->vblank_secondary = 0;
286 }
287
288 static void nouveau_destroy(struct gralloc_drm_drv_t *drv)
289 {
290         struct nouveau_info *info = (struct nouveau_info *) drv;
291
292         if (info->chan)
293                 nouveau_channel_free(&info->chan);
294         nouveau_device_close(&info->dev);
295         free(info);
296 }
297
298 static int nouveau_init(struct nouveau_info *info)
299 {
300         int err = 0;
301
302         switch (info->dev->chipset & 0xf0) {
303         case 0x00:
304                 info->arch = 0x04;
305                 break;
306         case 0x10:
307                 info->arch = 0x10;
308                 break;
309         case 0x20:
310                 info->arch = 0x20;
311                 break;
312         case 0x30:
313                 info->arch = 0x30;
314                 break;
315         case 0x40:
316         case 0x60:
317                 info->arch = 0x40;
318                 break;
319         case 0x50:
320         case 0x80:
321         case 0x90:
322         case 0xa0:
323                 info->arch = 0x50;
324                 break;
325         case 0xc0:
326                 info->arch = 0xc0;
327                 break;
328         default:
329                 LOGE("unknown nouveau chipset 0x%x", info->dev->chipset);
330                 err = -EINVAL;
331                 break;
332         }
333
334         info->tiled_scanout = (info->chan != NULL);
335
336         return err;
337 }
338
339 struct gralloc_drm_drv_t *gralloc_drm_drv_create_for_nouveau(int fd)
340 {
341         struct nouveau_info *info;
342         int err;
343
344         info = calloc(1, sizeof(*info));
345         if (!info)
346                 return NULL;
347
348         info->fd = fd;
349         err = nouveau_device_open_existing(&info->dev, 0, info->fd, 0);
350         if (err) {
351                 LOGE("failed to create nouveau device");
352                 free(info);
353                 return NULL;
354         }
355
356         err = nouveau_channel_alloc(info->dev, NvDmaFB, NvDmaTT,
357                         24 * 1024, &info->chan);
358         if (err) {
359                 /* make it non-fatal temporarily as it may require firmwares */
360                 LOGW("failed to create nouveau channel");
361                 info->chan = NULL;
362         }
363
364         err = nouveau_init(info);
365         if (err) {
366                 if (info->chan)
367                         nouveau_channel_free(&info->chan);
368                 nouveau_device_close(&info->dev);
369                 free(info);
370                 return NULL;
371         }
372
373         info->base.destroy = nouveau_destroy;
374         info->base.init_kms_features = nouveau_init_kms_features;
375         info->base.alloc = nouveau_alloc;
376         info->base.free = nouveau_free;
377         info->base.map = nouveau_map;
378         info->base.unmap = nouveau_unmap;
379
380         return &info->base;
381 }