diff options
author | Chia-I Wu <olvaffe@gmail.com> | 2011-07-14 14:42:30 +0800 |
---|---|---|
committer | Chia-I Wu <olvaffe@gmail.com> | 2011-07-15 09:57:25 +0800 |
commit | 896fbd12925a080d5c1a771f94cd087f6fa0fb8f (patch) | |
tree | f80d6c7baf2c0edc063fc20883ea7ca487d91aac /gralloc_drm_radeon.c | |
parent | 3dcc0159dcbc8f81fa2e1d0ea1c3a975a187b716 (diff) | |
download | external_drm_gralloc-896fbd12925a080d5c1a771f94cd087f6fa0fb8f.zip external_drm_gralloc-896fbd12925a080d5c1a771f94cd087f6fa0fb8f.tar.gz external_drm_gralloc-896fbd12925a080d5c1a771f94cd087f6fa0fb8f.tar.bz2 |
radeon: detect chip family
This should not change the behavior in any way.
Diffstat (limited to 'gralloc_drm_radeon.c')
-rw-r--r-- | gralloc_drm_radeon.c | 362 |
1 files changed, 247 insertions, 115 deletions
diff --git a/gralloc_drm_radeon.c b/gralloc_drm_radeon.c index b17de99..27dc443 100644 --- a/gralloc_drm_radeon.c +++ b/gralloc_drm_radeon.c @@ -45,19 +45,33 @@ #define MAX(a, b) (((a) > (b)) ? (a) : (b)) #define ALIGN(val, align) (((val) + (align) - 1) & ~((align) - 1)) +enum { + CHIP_FAMILY_R600, + CHIP_FAMILY_CEDAR, + CHIP_FAMILY_PALM, + CHIP_FAMILY_LAST +}; + struct radeon_info { struct gralloc_drm_drv_t base; int fd; struct radeon_bo_manager *bufmgr; + int chipset; + int chip_family; + uint32_t tile_config; int num_channels; int num_banks; int group_bytes; /* r6xx+ tile config */ int have_tiling_info; + int allow_color_tiling; + + int vram_size; + int gart_size; }; struct radeon_buffer { @@ -66,137 +80,100 @@ struct radeon_buffer { 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) +static int radeon_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; + if (info->chip_family >= CHIP_FAMILY_R600) { + 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; + } + } + else { + /* general surface requirements */ + if (tiling) + pitch_align = 256 / bpe; + else + pitch_align = 64; } return pitch_align; } /* returns height alignment in pixels */ -static int eg_get_height_align(struct radeon_info *info, uint32_t tiling) +static int radeon_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; + if (info->chip_family >= CHIP_FAMILY_R600) { + if (tiling & RADEON_TILING_MACRO) + height_align = info->num_channels * 8; + else if (tiling & RADEON_TILING_MICRO) + height_align = 8; + else + height_align = 8; + } + else { + if (tiling) + height_align = 16; + else + height_align = 1; + } return height_align; } /* returns base alignment in bytes */ -static int eg_get_base_align(struct radeon_info *info, +static int radeon_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; + int pixel_align = radeon_get_pitch_align(info, bpe, tiling); + int height_align = radeon_get_height_align(info, tiling); + int base_align = RADEON_GPU_PAGE_SIZE; + + if (info->chip_family >= CHIP_FAMILY_R600) { + 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) { + /* tiling must be disabled for CPU access */ return 0; } @@ -238,9 +215,9 @@ drm_gem_radeon_alloc(struct gralloc_drm_drv_t *drv, struct gralloc_drm_handle_t if (handle->usage & (GRALLOC_USAGE_HW_FB | GRALLOC_USAGE_HW_TEXTURE)) { aligned_width = ALIGN(handle->width, - eg_get_pitch_align(info, cpp, tiling)); + radeon_get_pitch_align(info, cpp, tiling)); aligned_height = ALIGN(handle->height, - eg_get_height_align(info, tiling)); + radeon_get_height_align(info, tiling)); } else { aligned_width = handle->width; @@ -254,7 +231,7 @@ drm_gem_radeon_alloc(struct gralloc_drm_drv_t *drv, struct gralloc_drm_handle_t pitch = aligned_width * cpp; size = ALIGN(aligned_height * pitch, RADEON_GPU_PAGE_SIZE); - base_align = eg_get_base_align(info, cpp, tiling); + base_align = radeon_get_base_align(info, cpp, tiling); rbuf->rbo = radeon_bo_open(info->bufmgr, 0, size, base_align, domain, 0); @@ -334,6 +311,162 @@ static void drm_gem_radeon_destroy(struct gralloc_drm_drv_t *drv) free(info); } +static int radeon_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; + + if (info->chip_family >= CHIP_FAMILY_CEDAR) { + 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; + } + + switch ((info->tile_config & 0xf0) >> 4) { + case 0: + info->num_banks = 4; + break; + case 1: + info->num_banks = 8; + break; + case 2: + info->num_banks = 16; + break; + default: + return -EINVAL; + break; + } + + switch ((info->tile_config & 0xf00) >> 8) { + case 0: + info->group_bytes = 256; + break; + case 1: + info->group_bytes = 512; + break; + default: + return -EINVAL; + break; + } + } + else { + switch ((info->tile_config & 0xe) >> 1) { + 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; + } + + switch ((info->tile_config & 0x30) >> 4) { + case 0: + info->num_banks = 4; + break; + case 1: + info->num_banks = 8; + break; + default: + return -EINVAL; + break; + } + + switch ((info->tile_config & 0xc0) >> 6) { + case 0: + info->group_bytes = 256; + break; + case 1: + info->group_bytes = 512; + break; + default: + return -EINVAL; + break; + } + } + + info->have_tiling_info = 1; + + return 0; +} + +static int radeon_probe(struct radeon_info *info) +{ + struct drm_radeon_info kinfo; + struct drm_radeon_gem_info mminfo; + int err; + + memset(&kinfo, 0, sizeof(kinfo)); + kinfo.request = RADEON_INFO_DEVICE_ID; + kinfo.value = (long) &info->chipset; + err = drmCommandWriteRead(info->fd, DRM_RADEON_INFO, &kinfo, sizeof(kinfo)); + if (err) + return err; + + /* XXX this is wrong and a table should be used */ + if (info->chipset >= 0x68e4 && info->chipset <= 0x68fe) + info->chip_family = CHIP_FAMILY_CEDAR; + else if (info->chipset >= 0x9802 && info->chipset <= 0x9807) + info->chip_family = CHIP_FAMILY_PALM; + else + return -EINVAL; + + err = radeon_init_tile_config(info); + if (err) + return err; + + info->allow_color_tiling = + (info->chip_family != CHIP_FAMILY_CEDAR); + + memset(&mminfo, 0, sizeof(mminfo)); + err = drmCommandWriteRead(info->fd, DRM_RADEON_GEM_INFO, &mminfo, sizeof(mminfo)); + if (err) + return err; + + info->vram_size = mminfo.vram_visible; + info->gart_size = mminfo.gart_size; + + LOGI("detected chip family %s (vram size %dMiB, gart size %dMiB)", + (info->chip_family == CHIP_FAMILY_CEDAR) ? + "CEDAR" : "PALM", + info->vram_size / 1024 / 1024, + info->gart_size / 1024 / 1024); + + return 0; +} + struct gralloc_drm_drv_t *gralloc_drm_drv_create_for_radeon(int fd) { struct radeon_info *info; @@ -343,15 +476,14 @@ struct gralloc_drm_drv_t *gralloc_drm_drv_create_for_radeon(int fd) return NULL; info->fd = fd; - info->bufmgr = radeon_bo_manager_gem_ctor(info->fd); - if (!info->bufmgr) { - LOGE("failed to create buffer manager"); + if (radeon_probe(info)) { free(info); return NULL; } - if (eg_init_tile_config(info)) { - radeon_bo_manager_gem_dtor(info->bufmgr); + info->bufmgr = radeon_bo_manager_gem_ctor(info->fd); + if (!info->bufmgr) { + LOGE("failed to create buffer manager"); free(info); return NULL; } |