2 * Copyright (C) 2011 Chia-I Wu <olvaffe@gmail.com>
3 * Copyright (C) 2011 LunarG Inc.
5 * Based on xf86-video-nouveau, which has
7 * Copyright © 2007 Red Hat, Inc.
8 * Copyright © 2008 Maarten Maathuis
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:
17 * The above copyright notice and this permission notice shall be included
18 * in all copies or substantial portions of the Software.
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.
29 #define LOG_TAG "GRALLOC-NOUVEAU"
31 #include <cutils/log.h>
35 #include <nouveau_drmif.h>
36 #include <nouveau_channel.h>
37 #include <nouveau_bo.h>
39 #include "gralloc_drm.h"
40 #include "gralloc_drm_priv.h"
42 #define MAX(a, b) (((a) > (b)) ? (a) : (b))
43 #define ALIGN(val, align) (((val) + (align) - 1) & ~((align) - 1))
45 #define NVC0_TILE_HEIGHT(m) (8 << ((m) >> 4))
53 struct gralloc_drm_drv_t base;
56 struct nouveau_device *dev;
57 struct nouveau_channel *chan;
62 struct nouveau_buffer {
63 struct gralloc_drm_bo_t base;
65 struct nouveau_bo *bo;
68 static struct nouveau_bo *alloc_bo(struct nouveau_info *info,
69 int width, int height, int cpp, int usage, int *pitch)
71 struct nouveau_bo *bo = NULL;
72 int flags, tile_mode, tile_flags;
76 flags = NOUVEAU_BO_MAP | NOUVEAU_BO_VRAM;
80 scanout = !!(usage & GRALLOC_USAGE_HW_FB);
82 tiled = !(usage & (GRALLOC_USAGE_SW_READ_OFTEN |
83 GRALLOC_USAGE_SW_WRITE_OFTEN));
86 else if (scanout && info->tiled_scanout)
89 /* calculate pitch align */
91 if (info->arch >= 0x50) {
92 if (scanout && !info->tiled_scanout)
98 *pitch = ALIGN(width * cpp, align);
101 if (info->arch >= 0xc0) {
104 else if (height > 32)
106 else if (height > 16)
115 align = NVC0_TILE_HEIGHT(tile_mode);
116 height = ALIGN(height, align);
118 else if (info->arch >= 0x50) {
121 else if (height > 16)
130 tile_flags = (scanout && cpp != 2) ? 0x7a00 : 0x7000;
132 align = 1 << (tile_mode + 2);
133 height = ALIGN(height, align);
138 /* round down to the previous power of two */
144 align |= align >> 16;
147 align = MAX((info->dev->chipset >= 0x40) ? 1024 : 256,
151 *pitch = ALIGN(*pitch, align);
158 tile_flags |= NOUVEAU_BO_TILE_32BPP;
160 tile_flags |= NOUVEAU_BO_TILE_16BPP;
163 tile_flags |= NOUVEAU_BO_TILE_SCANOUT;
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);
175 static struct gralloc_drm_bo_t *
176 nouveau_alloc(struct gralloc_drm_drv_t *drv, struct gralloc_drm_handle_t *handle)
178 struct nouveau_info *info = (struct nouveau_info *) drv;
179 struct nouveau_buffer *nb;
182 cpp = gralloc_drm_get_bpp(handle->format);
184 LOGE("unrecognized format 0x%x", handle->format);
188 nb = calloc(1, sizeof(*nb));
193 if (nouveau_bo_handle_ref(info->dev, handle->name, &nb->bo)) {
194 LOGE("failed to create nouveau bo from name %u",
203 nb->bo = alloc_bo(info, handle->width, handle->height,
204 cpp, handle->usage, &pitch);
206 LOGE("failed to allocate nouveau bo %dx%dx%d",
207 handle->width, handle->height, cpp);
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);
220 handle->stride = pitch;
223 if (handle->usage & GRALLOC_USAGE_HW_FB)
224 nb->base.fb_handle = nb->bo->handle;
226 nb->base.handle = handle;
231 static void nouveau_free(struct gralloc_drm_drv_t *drv,
232 struct gralloc_drm_bo_t *bo)
234 struct nouveau_buffer *nb = (struct nouveau_buffer *) bo;
235 nouveau_bo_ref(NULL, &nb->bo);
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)
243 struct nouveau_buffer *nb = (struct nouveau_buffer *) bo;
247 flags = NOUVEAU_BO_RD;
249 flags |= NOUVEAU_BO_WR;
251 /* TODO if tiled, allocate a linear copy of bo in GART and map it */
252 err = nouveau_bo_map(nb->bo, flags);
259 static void nouveau_unmap(struct gralloc_drm_drv_t *drv,
260 struct gralloc_drm_bo_t *bo)
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);
267 static void nouveau_init_kms_features(struct gralloc_drm_drv_t *drv,
268 struct gralloc_drm_t *drm)
270 struct nouveau_info *info = (struct nouveau_info *) drv;
272 switch (drm->fb_format) {
273 case HAL_PIXEL_FORMAT_BGRA_8888:
274 case HAL_PIXEL_FORMAT_RGB_565:
277 drm->fb_format = HAL_PIXEL_FORMAT_BGRA_8888;
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;
288 static void nouveau_destroy(struct gralloc_drm_drv_t *drv)
290 struct nouveau_info *info = (struct nouveau_info *) drv;
293 nouveau_channel_free(&info->chan);
294 nouveau_device_close(&info->dev);
298 static int nouveau_init(struct nouveau_info *info)
302 switch (info->dev->chipset & 0xf0) {
329 LOGE("unknown nouveau chipset 0x%x", info->dev->chipset);
334 info->tiled_scanout = (info->chan != NULL);
339 struct gralloc_drm_drv_t *gralloc_drm_drv_create_for_nouveau(int fd)
341 struct nouveau_info *info;
344 info = calloc(1, sizeof(*info));
349 err = nouveau_device_open_existing(&info->dev, 0, info->fd, 0);
351 LOGE("failed to create nouveau device");
356 err = nouveau_channel_alloc(info->dev, NvDmaFB, NvDmaTT,
357 24 * 1024, &info->chan);
359 /* make it non-fatal temporarily as it may require firmwares */
360 LOGW("failed to create nouveau channel");
364 err = nouveau_init(info);
367 nouveau_channel_free(&info->chan);
368 nouveau_device_close(&info->dev);
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;