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>
37 #include "gralloc_drm.h"
38 #include "gralloc_drm_priv.h"
40 #define NV_ARCH_03 0x03
41 #define NV_ARCH_04 0x04
42 #define NV_ARCH_10 0x10
43 #define NV_ARCH_20 0x20
44 #define NV_ARCH_30 0x30
45 #define NV_ARCH_40 0x40
48 #define NV_KEPLER 0xe0
49 #define NV_MAXWELL 0x110
51 #define NV50_TILE_HEIGHT(m) (4 << ((m) >> 4))
52 #define NVC0_TILE_HEIGHT(m) (8 << ((m) >> 4))
55 // Comment out the following to switch between the "sw_indicator disables all
56 // tiling" and "sw_indicator zeroes the tile|surf_flags (object tiling?)".
57 // Does the latter even make sense ... ? Going through the kernel on the
58 // topic is slightly annoying :\
60 #undef SW_INDICATOR_FULLY_DISABLES_TILING
63 struct gralloc_drm_drv_t base;
67 struct nouveau_device *dev;
68 struct nouveau_client *client;
69 struct nouveau_object *channel;
70 struct nouveau_pushbuf *pushbuf;
73 struct nouveau_buffer {
74 struct gralloc_drm_bo_t base;
76 struct nouveau_bo *bo;
79 static struct nouveau_bo *alloc_bo(struct nouveau_info *info,
80 int width, int height, int cpp, int usage, int *pitch)
82 struct nouveau_bo *bo = NULL;
83 union nouveau_bo_config cfg = {};
85 int tiled, scanout, sw_indicator;
88 flags = NOUVEAU_BO_MAP | NOUVEAU_BO_VRAM;
90 scanout = !!(usage & GRALLOC_USAGE_HW_FB);
92 tiled = !(usage & (GRALLOC_USAGE_SW_READ_OFTEN |
93 GRALLOC_USAGE_SW_WRITE_OFTEN));
95 sw_indicator = (usage & (GRALLOC_USAGE_SW_READ_OFTEN |
96 GRALLOC_USAGE_SW_WRITE_OFTEN));
98 if (info->arch >= NV_TESLA) {
108 *pitch = ALIGN(width * cpp, align);
111 if (info->arch >= NV_FERMI) {
113 cfg.nvc0.tile_mode = 0x0040;
114 else if (height > 32)
115 cfg.nvc0.tile_mode = 0x0030;
116 else if (height > 16)
117 cfg.nvc0.tile_mode = 0x0020;
119 cfg.nvc0.tile_mode = 0x0010;
121 cfg.nvc0.tile_mode = 0x0000;
123 #ifndef SW_INDICATOR_FULLY_DISABLES_TILING
125 cfg.nvc0.memtype = 0x0000;
128 cfg.nvc0.memtype = 0x00fe;
130 align = NVC0_TILE_HEIGHT(cfg.nvc0.tile_mode);
131 height = ALIGN(height, align);
133 else if (info->arch >= NV_TESLA) {
135 cfg.nv50.tile_mode = 0x0040;
136 else if (height > 16)
137 cfg.nv50.tile_mode = 0x0030;
139 cfg.nv50.tile_mode = 0x0020;
141 cfg.nv50.tile_mode = 0x0010;
143 cfg.nv50.tile_mode = 0x0000;
145 #ifndef SW_INDICATOR_FULLY_DISABLES_TILING
147 cfg.nv50.memtype = 0x0000;
150 cfg.nv50.memtype = (scanout && cpp != 2) ?
153 align = NV50_TILE_HEIGHT(cfg.nv50.tile_mode);
154 height = ALIGN(height, align);
159 /* round down to the previous power of two */
165 align |= align >> 16;
168 align = MAX((info->dev->chipset >= NV_ARCH_40) ?
172 *pitch = ALIGN(*pitch, align);
173 cfg.nv04.surf_pitch = *pitch;
177 if (info->arch < NV_TESLA) {
178 #ifndef SW_INDICATOR_FULLY_DISABLES_TILING
180 cfg.nv04.surf_flags = 0x0000;
184 cfg.nv04.surf_flags |= NV04_BO_32BPP;
186 cfg.nv04.surf_flags |= NV04_BO_16BPP;
190 flags |= NOUVEAU_BO_CONTIG;
192 #ifdef SW_INDICATOR_FULLY_DISABLES_TILING
193 if (nouveau_bo_new(info->dev, flags, 0, *pitch * height, NULL, &bo)) {
195 if (nouveau_bo_new(info->dev, flags, 0, *pitch * height, &cfg, &bo)) {
197 ALOGE("failed to allocate bo (flags 0x%x, size %d)",
198 flags, *pitch * height);
205 static struct gralloc_drm_bo_t *nouveau_alloc(struct gralloc_drm_drv_t *drv,
206 struct gralloc_drm_handle_t *handle)
208 struct nouveau_info *info = (struct nouveau_info *) drv;
209 struct nouveau_buffer *nb;
212 cpp = gralloc_drm_get_bpp(handle->format);
214 ALOGE("unrecognized format 0x%x", handle->format);
218 nb = calloc(1, sizeof(*nb));
223 if (nouveau_bo_name_ref(info->dev, handle->name, &nb->bo)) {
224 ALOGE("failed to create nouveau bo from name %u",
231 int width, height, pitch;
233 width = handle->width;
234 height = handle->height;
235 gralloc_drm_align_geometry(handle->format, &width, &height);
237 nb->bo = alloc_bo(info, width, height, cpp,
238 handle->usage, &pitch);
240 ALOGE("failed to allocate nouveau bo %dx%dx%d",
241 handle->width, handle->height, cpp);
246 if (nouveau_bo_name_get(nb->bo,
247 (uint32_t *) &handle->name)) {
248 ALOGE("failed to flink nouveau bo");
249 nouveau_bo_ref(NULL, &nb->bo);
254 handle->stride = pitch;
257 if (handle->usage & GRALLOC_USAGE_HW_FB)
258 nb->base.fb_handle = nb->bo->handle;
260 nb->base.handle = handle;
265 static void nouveau_free(struct gralloc_drm_drv_t *drv,
266 struct gralloc_drm_bo_t *bo)
268 struct nouveau_buffer *nb = (struct nouveau_buffer *) bo;
269 nouveau_bo_ref(NULL, &nb->bo);
273 static int nouveau_map(struct gralloc_drm_drv_t *drv,
274 struct gralloc_drm_bo_t *bo, int x, int y, int w, int h,
275 int enable_write, void **addr)
277 struct nouveau_info *info = (struct nouveau_info *) drv;
278 struct nouveau_buffer *nb = (struct nouveau_buffer *) bo;
282 flags = NOUVEAU_BO_RD;
284 flags |= NOUVEAU_BO_WR;
286 /* TODO if tiled, allocate a linear copy of bo in GART and map it */
287 err = nouveau_bo_map(nb->bo, flags, info->client);
294 static void nouveau_unmap(struct gralloc_drm_drv_t *drv,
295 struct gralloc_drm_bo_t *bo)
297 /* The bo is implicitly unmapped at nouveau_bo_ref(NULL, bo) */
300 static void nouveau_init_kms_features(struct gralloc_drm_drv_t *drv,
301 struct gralloc_drm_t *drm)
303 struct nouveau_info *info = (struct nouveau_info *) drv;
305 switch (drm->primary.fb_format) {
306 case HAL_PIXEL_FORMAT_BGRA_8888:
307 case HAL_PIXEL_FORMAT_RGB_565:
310 drm->primary.fb_format = HAL_PIXEL_FORMAT_BGRA_8888;
314 drm->mode_quirk_vmwgfx = 0;
315 drm->swap_mode = DRM_SWAP_FLIP;
316 drm->mode_sync_flip = 1;
317 drm->swap_interval = 1;
318 drm->vblank_secondary = 0;
321 static void nouveau_destroy(struct gralloc_drm_drv_t *drv)
323 struct nouveau_info *info = (struct nouveau_info *) drv;
325 nouveau_pushbuf_del(&info->pushbuf);
326 nouveau_object_del(&info->channel);
327 nouveau_client_del(&info->client);
328 nouveau_device_del(&info->dev);
332 static int nouveau_init(struct nouveau_info *info)
336 switch (info->dev->chipset & ~0xf) {
338 info->arch = NV_ARCH_04;
341 info->arch = NV_ARCH_10;
344 info->arch = NV_ARCH_20;
347 info->arch = NV_ARCH_30;
351 info->arch = NV_ARCH_40;
357 info->arch = NV_TESLA;
361 info->arch = NV_FERMI;
365 info->arch = NV_KEPLER;
368 info->arch = NV_MAXWELL;
371 ALOGE("unknown nouveau chipset 0x%x", info->dev->chipset);
376 if (info->dev->drm_version < 0x01000000 && info->dev->chipset >= 0xc0) {
377 ALOGE("nouveau kernel module is too old 0x%x",
378 info->dev->drm_version);
385 struct gralloc_drm_drv_t *
386 gralloc_drm_drv_create_for_nouveau(int fd)
388 struct nouveau_info *info;
389 struct nv04_fifo nv04_data = { .vram = 0xbeef0201, .gart = 0xbeef0202 };
390 struct nvc0_fifo nvc0_data = { };
394 info = calloc(1, sizeof(*info));
399 err = nouveau_device_wrap(fd, 0, &info->dev);
401 ALOGE("failed to wrap existing nouveau device");
406 err = nouveau_init(info);
412 err = nouveau_client_new(info->dev, &info->client);
414 ALOGW("failed to create nouveau client: %d", err);
415 nouveau_device_del(&info->dev);
420 if (info->dev->chipset < 0xc0) {
422 size = sizeof(nv04_data);
426 size = sizeof(nvc0_data);
429 err = nouveau_object_new(&info->dev->object, 0,
430 NOUVEAU_FIFO_CHANNEL_CLASS, data, size,
434 ALOGE("failed to create nouveau channel: %d", err);
435 nouveau_client_del(&info->client);
436 nouveau_device_del(&info->dev);
441 err = nouveau_pushbuf_new(info->client, info->channel,
442 4, 32 * 1024, true, &info->pushbuf);
444 ALOGE("failed to allocate DMA push buffer: %d", err);
445 nouveau_object_del(&info->channel);
446 nouveau_client_del(&info->client);
447 nouveau_device_del(&info->dev);
452 info->base.destroy = nouveau_destroy;
453 info->base.init_kms_features = nouveau_init_kms_features;
454 info->base.alloc = nouveau_alloc;
455 info->base.free = nouveau_free;
456 info->base.map = nouveau_map;
457 info->base.unmap = nouveau_unmap;