From dd4929b30b6a11149852785754b99b93714bdf88 Mon Sep 17 00:00:00 2001 From: Chia-I Wu Date: Sat, 19 Mar 2011 22:53:50 +0800 Subject: gralloc: add radeon support --- src/gralloc/gralloc_gem.c | 4 + src/gralloc/gralloc_gem.h | 1 + src/gralloc/gralloc_gem_radeon.c | 353 +++++++++++++++++++++++++++++++++++++++ src/gralloc/gralloc_kms.c | 2 +- 4 files changed, 359 insertions(+), 1 deletion(-) create mode 100644 src/gralloc/gralloc_gem_radeon.c diff --git a/src/gralloc/gralloc_gem.c b/src/gralloc/gralloc_gem.c index 5b2ddebe55..3276335159 100644 --- a/src/gralloc/gralloc_gem.c +++ b/src/gralloc/gralloc_gem.c @@ -135,6 +135,10 @@ get_drv_from_fd(int fd) if (!drv && !strcmp(version->name, "intel")) drv = &drm_gem_drv_intel; #endif +#ifdef ENABLE_RADEON + if (!drv && !strcmp(version->name, "radeon")) + drv = &drm_gem_drv_radeon; +#endif #ifdef ENABLE_VMWGFX if (!drv && !strcmp(version->name, "vmwgfx")) drv = &drm_gem_drv_pipe; diff --git a/src/gralloc/gralloc_gem.h b/src/gralloc/gralloc_gem.h index c82ea2b720..f8fa1e069d 100644 --- a/src/gralloc/gralloc_gem.h +++ b/src/gralloc/gralloc_gem.h @@ -75,6 +75,7 @@ struct drm_gem_drv { }; extern const struct drm_gem_drv drm_gem_drv_intel; +extern const struct drm_gem_drv drm_gem_drv_radeon; extern const struct drm_gem_drv drm_gem_drv_pipe; static inline struct drm_bo_t * diff --git a/src/gralloc/gralloc_gem_radeon.c b/src/gralloc/gralloc_gem_radeon.c new file mode 100644 index 0000000000..334263ee2f --- /dev/null +++ b/src/gralloc/gralloc_gem_radeon.c @@ -0,0 +1,353 @@ +/* + * Based on xf86-video-ati, which is + * + * 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 (including the next + * paragraph) 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. + * + * Authors: + * Dave Airlie + */ + +#define LOG_TAG "GRALLOC-RADEON" + +#include +#include +#include +#include +#include +#include +#include + +#include "gralloc_mod.h" +#include "gralloc_gem.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 drm_module_t *drm; + 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; +}; + +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->drm->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 = MAX(info->num_banks, + (((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 void +drm_gem_radeon_init_features(struct drm_module_t *drm) +{ + drm->mode_dirty_fb = 0; + /* XXX there are synchronization issues */ + drm->mode_page_flip = 0; + drm->swap_interval = 1; + drm->vblank_secondary = 0; +} + +static int +drm_gem_radeon_init(struct drm_module_t *drm) +{ + struct radeon_info *info; + int ret; + + info = calloc(1, sizeof(*info)); + if (!info) + return -ENOMEM; + + info->drm = drm; + info->bufmgr = radeon_bo_manager_gem_ctor(info->drm->fd); + if (!info->bufmgr) { + LOGE("failed to create buffer manager"); + free(info); + return -ENOMEM; + } + + + drm->gem = (void *) info; + + ret = eg_init_tile_config(info); + if (ret) { + radeon_bo_manager_gem_dtor(info->bufmgr); + free(info); + return ret; + } + + drm_gem_radeon_init_features(drm); + + return 0; +} + +static uint32_t +drm_gem_get_tiling(struct drm_bo_t *bo) +{ + return 0; +} + +static struct drm_bo_t * +drm_gem_radeon_alloc(struct drm_module_t *drm, int width, int height, + int format, int usage, int *stride) +{ + struct radeon_info *info = (struct radeon_info *) drm->gem; + struct drm_bo_t *bo; + struct radeon_bo *rbo; + int aligned_width, aligned_height, cpp; + int pitch, size, base_align; + uint32_t tiling; + + bo = drm_gem_create_bo(width, height, format, usage); + if (!bo) + return NULL; + + cpp = drm_mod_get_bpp(format); + if (!cpp) { + LOGE("unrecognized format 0x%x", format); + free(bo); + return NULL; + } + + tiling = drm_gem_get_tiling(bo); + + if (usage & (GRALLOC_USAGE_HW_FB | GRALLOC_USAGE_HW_TEXTURE)) { + aligned_width = ALIGN(width, eg_get_pitch_align(info, cpp, tiling)); + aligned_height = ALIGN(height, eg_get_height_align(info, tiling)); + } + else { + aligned_width = width; + aligned_height = height; + } + + pitch = aligned_width * cpp; + size = ALIGN(aligned_height * pitch, RADEON_GPU_PAGE_SIZE); + base_align = eg_get_base_align(info, cpp, tiling); + + rbo = radeon_bo_open(info->bufmgr, 0, size, + base_align, RADEON_GEM_DOMAIN_VRAM, 0); + if (!rbo) { + LOGE("failed to allocate rbo %dx%dx%d", width, height, cpp); + free(bo); + return NULL; + } + + if (tiling) + radeon_bo_set_tiling(rbo, tiling, pitch); + + if (bo->usage & GRALLOC_USAGE_HW_FB) { + bo->stride = pitch; + bo->fb_handle = rbo->handle; + } + + if (radeon_gem_get_kernel_name(rbo, (uint32_t *) &bo->name)) { + LOGE("failed to flink rbo"); + radeon_bo_unref(rbo); + free(bo); + return NULL; + } + + bo->data = (int) rbo; + + *stride = pitch; + + return bo; +} + +static void +drm_gem_radeon_free(struct drm_module_t *drm, struct drm_bo_t *bo) +{ + radeon_bo_unref((struct radeon_bo *) bo->data); + free(bo); +} + +static int +drm_gem_radeon_map(struct drm_module_t *drm, struct drm_bo_t *bo, + int x, int y, int w, int h, int enable_write, void **addr) +{ + struct radeon_bo *rbo = (struct radeon_bo *) bo->data; + int err; + + if (!rbo) { + struct radeon_info *info = (struct radeon_info *) drm->gem; + + rbo = radeon_bo_open(info->bufmgr, bo->name, 0, 0, RADEON_GEM_DOMAIN_VRAM, 0); + if (!rbo) { + LOGE("failed to create rbo from name %u", bo->name); + return -EINVAL; + } + + bo->data = (int) rbo; + } + + err = radeon_bo_map(rbo, enable_write); + if (!err) + *addr = rbo->ptr; + + return err; +} + +static void +drm_gem_radeon_unmap(struct drm_module_t *drm, struct drm_bo_t *bo) +{ + struct radeon_bo *rbo = (struct radeon_bo *) bo->data; + + radeon_bo_unmap(rbo); +} + +const struct drm_gem_drv drm_gem_drv_radeon = { + .init = drm_gem_radeon_init, + .alloc = drm_gem_radeon_alloc, + .free = drm_gem_radeon_free, + .map = drm_gem_radeon_map, + .unmap = drm_gem_radeon_unmap, +}; diff --git a/src/gralloc/gralloc_kms.c b/src/gralloc/gralloc_kms.c index 569e862f9b..2ed06f7701 100644 --- a/src/gralloc/gralloc_kms.c +++ b/src/gralloc/gralloc_kms.c @@ -73,7 +73,7 @@ drm_kms_page_flip(struct drm_module_t *drm, struct drm_bo_t *bo) while (waits) { ret = drmModePageFlip(drm->fd, drm->crtc_id, bo->fb_id, 0x0, NULL); - if (ret && errno == -EBUSY) { + if (ret && errno == EBUSY) { if (drm->swap_interval) drm_kms_wait_vblank(drm, 1); else -- cgit v1.2.3