summaryrefslogtreecommitdiffstats
path: root/gralloc_drm_radeon.c
diff options
context:
space:
mode:
authorChia-I Wu <olvaffe@gmail.com>2011-06-12 16:21:30 +0800
committerChia-I Wu <olvaffe@gmail.com>2011-06-12 16:21:30 +0800
commit2ec32d4f949f04d0006fff50065c904626c2e581 (patch)
tree7971ee3431e97f7fe7c0bc6ae17948866e10de1e /gralloc_drm_radeon.c
downloadexternal_drm_gralloc-2ec32d4f949f04d0006fff50065c904626c2e581.zip
external_drm_gralloc-2ec32d4f949f04d0006fff50065c904626c2e581.tar.gz
external_drm_gralloc-2ec32d4f949f04d0006fff50065c904626c2e581.tar.bz2
initial commit
Diffstat (limited to 'gralloc_drm_radeon.c')
-rw-r--r--gralloc_drm_radeon.c366
1 files changed, 366 insertions, 0 deletions
diff --git a/gralloc_drm_radeon.c b/gralloc_drm_radeon.c
new file mode 100644
index 0000000..59fb782
--- /dev/null
+++ b/gralloc_drm_radeon.c
@@ -0,0 +1,366 @@
+/*
+ * Copyright (C) 2010-2011 Chia-I Wu <olvaffe@gmail.com>
+ * Copyright (C) 2010-2011 LunarG Inc.
+ *
+ * Based on xf86-video-ati, which has
+ *
+ * Copyright © 2009 Red Hat, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+/* XXX This driver assumes evergreen. */
+
+#define LOG_TAG "GRALLOC-RADEON"
+
+#include <cutils/log.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <drm.h>
+#include <radeon_drm.h>
+#include <radeon_bo_gem.h>
+#include <radeon_bo.h>
+
+#include "gralloc_drm.h"
+#include "gralloc_drm_priv.h"
+
+#define RADEON_GPU_PAGE_SIZE 4096
+
+#define MAX(a, b) (((a) > (b)) ? (a) : (b))
+#define ALIGN(val, align) (((val) + (align) - 1) & ~((align) - 1))
+
+struct radeon_info {
+ struct gralloc_drm_drv_t base;
+
+ int fd;
+ struct radeon_bo_manager *bufmgr;
+
+ uint32_t tile_config;
+ int num_channels;
+ int num_banks;
+ int group_bytes;
+ /* r6xx+ tile config */
+ int have_tiling_info;
+ int allow_color_tiling;
+};
+
+struct radeon_buffer {
+ struct gralloc_drm_bo_t base;
+
+ struct radeon_bo *rbo;
+};
+
+static int eg_init_tile_config(struct radeon_info *info)
+{
+ struct drm_radeon_info ginfo;
+ uint32_t val;
+ int ret;
+
+ memset(&ginfo, 0, sizeof(ginfo));
+ ginfo.request = RADEON_INFO_TILING_CONFIG;
+ ginfo.value = (long) &val;
+ ret = drmCommandWriteRead(info->fd, DRM_RADEON_INFO,
+ &ginfo, sizeof(ginfo));
+ if (ret)
+ return ret;
+
+ info->tile_config = val;
+
+ switch (info->tile_config & 0xf) {
+ case 0:
+ info->num_channels = 1;
+ break;
+ case 1:
+ info->num_channels = 2;
+ break;
+ case 2:
+ info->num_channels = 4;
+ break;
+ case 3:
+ info->num_channels = 8;
+ break;
+ default:
+ return -EINVAL;
+ break;
+ }
+
+ info->num_banks = (info->tile_config & 0xf0) >> 4;
+
+ switch ((info->tile_config & 0xf00) >> 8) {
+ case 0:
+ info->group_bytes = 256;
+ break;
+ case 1:
+ info->group_bytes = 512;
+ break;
+ default:
+ return -EINVAL;
+ break;
+ }
+
+ info->have_tiling_info = 1;
+ info->allow_color_tiling = 0;
+
+ return 0;
+}
+
+/* returns pitch alignment in pixels */
+static int eg_get_pitch_align(struct radeon_info *info, int bpe, uint32_t tiling)
+{
+ int pitch_align = 1;
+
+ if (tiling & RADEON_TILING_MACRO) {
+ /* general surface requirements */
+ pitch_align = (((info->group_bytes / 8) / bpe) *
+ info->num_banks) * 8;
+ /* further restrictions for scanout */
+ pitch_align = MAX(info->num_banks * 8, pitch_align);
+ } else if (tiling & RADEON_TILING_MICRO) {
+ /* general surface requirements */
+ pitch_align = MAX(8, (info->group_bytes / (8 * bpe)));
+ /* further restrictions for scanout */
+ pitch_align = MAX(info->group_bytes / bpe, pitch_align);
+ } else {
+ if (info->have_tiling_info)
+ /* linear aligned requirements */
+ pitch_align = MAX(64, info->group_bytes / bpe);
+ else
+ /* default to 512 elements if we don't know the real
+ * group size otherwise the kernel may reject the CS
+ * if the group sizes don't match as the pitch won't
+ * be aligned properly.
+ */
+ pitch_align = 512;
+ }
+
+ return pitch_align;
+}
+
+/* returns height alignment in pixels */
+static int eg_get_height_align(struct radeon_info *info, uint32_t tiling)
+{
+ int height_align = 1;
+
+ if (tiling & RADEON_TILING_MACRO)
+ height_align = info->num_channels * 8;
+ else if (tiling & RADEON_TILING_MICRO)
+ height_align = 8;
+ else
+ height_align = 8;
+
+ return height_align;
+}
+
+/* returns base alignment in bytes */
+static int eg_get_base_align(struct radeon_info *info,
+ int bpe, uint32_t tiling)
+{
+ int pixel_align = eg_get_pitch_align(info, bpe, tiling);
+ int height_align = eg_get_height_align(info, tiling);
+ int base_align = RADEON_GPU_PAGE_SIZE;
+
+ if (tiling & RADEON_TILING_MACRO) {
+ base_align =
+ MAX(info->num_banks * info->num_channels * 8 * 8 * bpe,
+ pixel_align * bpe * height_align);
+ }
+ else {
+ if (info->have_tiling_info)
+ base_align = info->group_bytes;
+ else
+ /* default to 512 if we don't know the real
+ * group size otherwise the kernel may reject the CS
+ * if the group sizes don't match as the base won't
+ * be aligned properly.
+ */
+ base_align = 512;
+ }
+
+ return base_align;
+}
+
+static uint32_t drm_gem_get_tiling(const struct gralloc_drm_handle_t *handle)
+{
+ return 0;
+}
+
+static struct gralloc_drm_bo_t *
+drm_gem_radeon_alloc(struct gralloc_drm_drv_t *drv, struct gralloc_drm_handle_t *handle)
+{
+ struct radeon_info *info = (struct radeon_info *) drv;
+ struct radeon_buffer *rbuf;
+ uint32_t tiling, domain;
+ int cpp;
+
+ tiling = drm_gem_get_tiling(handle);
+ domain = RADEON_GEM_DOMAIN_VRAM;
+ cpp = gralloc_drm_get_bpp(handle->format);
+ if (!cpp) {
+ LOGE("unrecognized format 0x%x", handle->format);
+ return NULL;
+ }
+
+ rbuf = calloc(1, sizeof(*rbuf));
+ if (!rbuf)
+ return NULL;
+
+
+ if (handle->name) {
+ rbuf->rbo = radeon_bo_open(info->bufmgr, handle->name,
+ 0, 0, domain, 0);
+ if (!rbuf->rbo) {
+ LOGE("failed to create rbo from name %u",
+ handle->name);
+ free(rbuf);
+ return NULL;
+ }
+ }
+ else {
+ int aligned_width, aligned_height;
+ int pitch, size, base_align;
+
+ if (handle->usage & (GRALLOC_USAGE_HW_FB |
+ GRALLOC_USAGE_HW_TEXTURE)) {
+ aligned_width = ALIGN(handle->width,
+ eg_get_pitch_align(info, cpp, tiling));
+ aligned_height = ALIGN(handle->height,
+ eg_get_height_align(info, tiling));
+ }
+ else {
+ aligned_width = handle->width;
+ aligned_height = handle->height;
+ }
+
+ if (!(handle->usage & (GRALLOC_USAGE_HW_FB |
+ GRALLOC_USAGE_HW_RENDER)) &&
+ (handle->usage & GRALLOC_USAGE_SW_READ_OFTEN))
+ domain = RADEON_GEM_DOMAIN_GTT;
+
+ pitch = aligned_width * cpp;
+ size = ALIGN(aligned_height * pitch, RADEON_GPU_PAGE_SIZE);
+ base_align = eg_get_base_align(info, cpp, tiling);
+
+ rbuf->rbo = radeon_bo_open(info->bufmgr, 0,
+ size, base_align, domain, 0);
+ if (!rbuf->rbo) {
+ LOGE("failed to allocate rbo %dx%dx%d",
+ handle->width, handle->height, cpp);
+ free(rbuf);
+ return NULL;
+ }
+
+ if (tiling)
+ radeon_bo_set_tiling(rbuf->rbo, tiling, pitch);
+
+ if (radeon_gem_get_kernel_name(rbuf->rbo,
+ (uint32_t *) &handle->name)) {
+ LOGE("failed to flink rbo");
+ radeon_bo_unref(rbuf->rbo);
+ free(rbuf);
+ return NULL;
+ }
+
+ handle->stride = pitch;
+ }
+
+ if (handle->usage & GRALLOC_USAGE_HW_FB)
+ rbuf->base.fb_handle = rbuf->rbo->handle;
+
+ rbuf->base.handle = handle;
+
+ return &rbuf->base;
+}
+
+static void drm_gem_radeon_free(struct gralloc_drm_drv_t *drv,
+ struct gralloc_drm_bo_t *bo)
+{
+ struct radeon_buffer *rbuf = (struct radeon_buffer *) bo;
+ radeon_bo_unref(rbuf->rbo);
+}
+
+static int drm_gem_radeon_map(struct gralloc_drm_drv_t *drv,
+ struct gralloc_drm_bo_t *bo, int x, int y, int w, int h,
+ int enable_write, void **addr)
+{
+ struct radeon_buffer *rbuf = (struct radeon_buffer *) bo;
+ int err;
+
+ err = radeon_bo_map(rbuf->rbo, enable_write);
+ if (!err)
+ *addr = rbuf->rbo->ptr;
+
+ return err;
+}
+
+static void drm_gem_radeon_unmap(struct gralloc_drm_drv_t *drv,
+ struct gralloc_drm_bo_t *bo)
+{
+ struct radeon_buffer *rbuf = (struct radeon_buffer *) bo;
+ radeon_bo_unmap(rbuf->rbo);
+}
+
+static void drm_gem_radeon_init_kms_features(struct gralloc_drm_drv_t *drv,
+ struct gralloc_drm_t *drm)
+{
+ drm->mode_dirty_fb = 0;
+ drm->swap_mode = DRM_SWAP_FLIP;
+ drm->mode_sync_flip = 1;
+ drm->swap_interval = 1;
+ drm->vblank_secondary = 0;
+}
+
+static void drm_gem_radeon_destroy(struct gralloc_drm_drv_t *drv)
+{
+ struct radeon_info *info = (struct radeon_info *) drv;
+
+ radeon_bo_manager_gem_dtor(info->bufmgr);
+ free(info);
+}
+
+struct gralloc_drm_drv_t *gralloc_drm_drv_create_for_radeon(int fd)
+{
+ struct radeon_info *info;
+
+ info = calloc(1, sizeof(*info));
+ if (!info)
+ return NULL;
+
+ info->fd = fd;
+ info->bufmgr = radeon_bo_manager_gem_ctor(info->fd);
+ if (!info->bufmgr) {
+ LOGE("failed to create buffer manager");
+ free(info);
+ return NULL;
+ }
+
+ if (eg_init_tile_config(info)) {
+ radeon_bo_manager_gem_dtor(info->bufmgr);
+ free(info);
+ return NULL;
+ }
+
+ info->base.destroy = drm_gem_radeon_destroy;
+ info->base.init_kms_features = drm_gem_radeon_init_kms_features;
+ info->base.alloc = drm_gem_radeon_alloc;
+ info->base.free = drm_gem_radeon_free;
+ info->base.map = drm_gem_radeon_map;
+ info->base.unmap = drm_gem_radeon_unmap;
+
+ return &info->base;
+}