OSDN Git Service

Change all occurances of LOGE to ALOGE, LOGW to ALOGW and LOGI to ALOGI due to change...
[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                 ALOGE("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                 ALOGE("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                         ALOGE("failed to create nouveau bo from name %u",
195                                         handle->name);
196                         free(nb);
197                         return NULL;
198                 }
199         }
200         else {
201                 int width, height, pitch;
202
203                 width = handle->width;
204                 height = handle->height;
205                 gralloc_drm_align_geometry(handle->format, &width, &height);
206
207                 nb->bo = alloc_bo(info, width, height,
208                                 cpp, handle->usage, &pitch);
209                 if (!nb->bo) {
210                         ALOGE("failed to allocate nouveau bo %dx%dx%d",
211                                         handle->width, handle->height, cpp);
212                         free(nb);
213                         return NULL;
214                 }
215
216                 if (nouveau_bo_handle_get(nb->bo,
217                                         (uint32_t *) &handle->name)) {
218                         ALOGE("failed to flink nouveau bo");
219                         nouveau_bo_ref(NULL, &nb->bo);
220                         free(nb);
221                         return NULL;
222                 }
223
224                 handle->stride = pitch;
225         }
226
227         if (handle->usage & GRALLOC_USAGE_HW_FB)
228                 nb->base.fb_handle = nb->bo->handle;
229
230         nb->base.handle = handle;
231
232         return &nb->base;
233 }
234
235 static void nouveau_free(struct gralloc_drm_drv_t *drv,
236                 struct gralloc_drm_bo_t *bo)
237 {
238         struct nouveau_buffer *nb = (struct nouveau_buffer *) bo;
239         nouveau_bo_ref(NULL, &nb->bo);
240         free(nb);
241 }
242
243 static int nouveau_map(struct gralloc_drm_drv_t *drv,
244                 struct gralloc_drm_bo_t *bo, int x, int y, int w, int h,
245                 int enable_write, void **addr)
246 {
247         struct nouveau_buffer *nb = (struct nouveau_buffer *) bo;
248         uint32_t flags;
249         int err;
250
251         flags = NOUVEAU_BO_RD;
252         if (enable_write)
253                 flags |= NOUVEAU_BO_WR;
254
255         /* TODO if tiled, allocate a linear copy of bo in GART and map it */
256         err = nouveau_bo_map(nb->bo, flags);
257         if (!err)
258                 *addr = nb->bo->map;
259
260         return err;
261 }
262
263 static void nouveau_unmap(struct gralloc_drm_drv_t *drv,
264                 struct gralloc_drm_bo_t *bo)
265 {
266         struct nouveau_buffer *nb = (struct nouveau_buffer *) bo;
267         /* TODO if tiled, unmap the linear bo and copy back */
268         nouveau_bo_unmap(nb->bo);
269 }
270
271 static void nouveau_init_kms_features(struct gralloc_drm_drv_t *drv,
272                 struct gralloc_drm_t *drm)
273 {
274         struct nouveau_info *info = (struct nouveau_info *) drv;
275
276         switch (drm->fb_format) {
277         case HAL_PIXEL_FORMAT_BGRA_8888:
278         case HAL_PIXEL_FORMAT_RGB_565:
279                 break;
280         default:
281                 drm->fb_format = HAL_PIXEL_FORMAT_BGRA_8888;
282                 break;
283         }
284
285         drm->mode_quirk_vmwgfx = 0;
286         drm->swap_mode = (info->chan) ? DRM_SWAP_FLIP : DRM_SWAP_SETCRTC;
287         drm->mode_sync_flip = 1;
288         drm->swap_interval = 1;
289         drm->vblank_secondary = 0;
290 }
291
292 static void nouveau_destroy(struct gralloc_drm_drv_t *drv)
293 {
294         struct nouveau_info *info = (struct nouveau_info *) drv;
295
296         if (info->chan)
297                 nouveau_channel_free(&info->chan);
298         nouveau_device_close(&info->dev);
299         free(info);
300 }
301
302 static int nouveau_init(struct nouveau_info *info)
303 {
304         int err = 0;
305
306         switch (info->dev->chipset & 0xf0) {
307         case 0x00:
308                 info->arch = 0x04;
309                 break;
310         case 0x10:
311                 info->arch = 0x10;
312                 break;
313         case 0x20:
314                 info->arch = 0x20;
315                 break;
316         case 0x30:
317                 info->arch = 0x30;
318                 break;
319         case 0x40:
320         case 0x60:
321                 info->arch = 0x40;
322                 break;
323         case 0x50:
324         case 0x80:
325         case 0x90:
326         case 0xa0:
327                 info->arch = 0x50;
328                 break;
329         case 0xc0:
330                 info->arch = 0xc0;
331                 break;
332         default:
333                 ALOGE("unknown nouveau chipset 0x%x", info->dev->chipset);
334                 err = -EINVAL;
335                 break;
336         }
337
338         info->tiled_scanout = (info->chan != NULL);
339
340         return err;
341 }
342
343 struct gralloc_drm_drv_t *gralloc_drm_drv_create_for_nouveau(int fd)
344 {
345         struct nouveau_info *info;
346         int err;
347
348         info = calloc(1, sizeof(*info));
349         if (!info)
350                 return NULL;
351
352         info->fd = fd;
353         err = nouveau_device_open_existing(&info->dev, 0, info->fd, 0);
354         if (err) {
355                 ALOGE("failed to create nouveau device");
356                 free(info);
357                 return NULL;
358         }
359
360         err = nouveau_channel_alloc(info->dev, NvDmaFB, NvDmaTT,
361                         24 * 1024, &info->chan);
362         if (err) {
363                 /* make it non-fatal temporarily as it may require firmwares */
364                 ALOGW("failed to create nouveau channel");
365                 info->chan = NULL;
366         }
367
368         err = nouveau_init(info);
369         if (err) {
370                 if (info->chan)
371                         nouveau_channel_free(&info->chan);
372                 nouveau_device_close(&info->dev);
373                 free(info);
374                 return NULL;
375         }
376
377         info->base.destroy = nouveau_destroy;
378         info->base.init_kms_features = nouveau_init_kms_features;
379         info->base.alloc = nouveau_alloc;
380         info->base.free = nouveau_free;
381         info->base.map = nouveau_map;
382         info->base.unmap = nouveau_unmap;
383
384         return &info->base;
385 }