summaryrefslogtreecommitdiffstats
path: root/gralloc_drm_radeon.c
diff options
context:
space:
mode:
authorChia-I Wu <olvaffe@gmail.com>2011-07-14 14:42:30 +0800
committerChia-I Wu <olvaffe@gmail.com>2011-07-15 09:57:25 +0800
commit896fbd12925a080d5c1a771f94cd087f6fa0fb8f (patch)
treef80d6c7baf2c0edc063fc20883ea7ca487d91aac /gralloc_drm_radeon.c
parent3dcc0159dcbc8f81fa2e1d0ea1c3a975a187b716 (diff)
downloadexternal_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.c362
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;
}