blob: 270a07a3a892e8d429d6ab47334a78d19a29bd2e [file] [log] [blame]
/*
* Copyright 2010 Jerome Glisse <glisse@freedesktop.org>
*
* 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
* on the rights to use, copy, modify, merge, publish, distribute, sub
* license, 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 NON-INFRINGEMENT. IN NO EVENT SHALL
* THE AUTHOR(S) AND/OR THEIR SUPPLIERS 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:
* Jerome Glisse
* Corbin Simpson <MostAwesomeDude@gmail.com>
* Joakim Sindholt <opensource@zhasha.com>
*/
#include "r600_priv.h"
#include "r600_drm_public.h"
#include "util/u_memory.h"
#include <radeon_drm.h>
#include <xf86drm.h>
#include <errno.h>
#ifndef RADEON_INFO_NUM_TILE_PIPES
#define RADEON_INFO_NUM_TILE_PIPES 0xb
#endif
#ifndef RADEON_INFO_BACKEND_MAP
#define RADEON_INFO_BACKEND_MAP 0xd
#endif
enum radeon_family r600_get_family(struct radeon *r600)
{
return r600->family;
}
enum chip_class r600_get_family_class(struct radeon *radeon)
{
return radeon->chip_class;
}
struct r600_tiling_info *r600_get_tiling_info(struct radeon *radeon)
{
return &radeon->tiling_info;
}
unsigned r600_get_clock_crystal_freq(struct radeon *radeon)
{
return radeon->info.r600_clock_crystal_freq;
}
unsigned r600_get_num_backends(struct radeon *radeon)
{
return radeon->info.r600_num_backends;
}
unsigned r600_get_num_tile_pipes(struct radeon *radeon)
{
return radeon->num_tile_pipes;
}
unsigned r600_get_backend_map(struct radeon *radeon)
{
return radeon->backend_map;
}
unsigned r600_get_minor_version(struct radeon *radeon)
{
return radeon->info.drm_minor;
}
static int r600_interpret_tiling(struct radeon *radeon, uint32_t tiling_config)
{
switch ((tiling_config & 0xe) >> 1) {
case 0:
radeon->tiling_info.num_channels = 1;
break;
case 1:
radeon->tiling_info.num_channels = 2;
break;
case 2:
radeon->tiling_info.num_channels = 4;
break;
case 3:
radeon->tiling_info.num_channels = 8;
break;
default:
return -EINVAL;
}
switch ((tiling_config & 0x30) >> 4) {
case 0:
radeon->tiling_info.num_banks = 4;
break;
case 1:
radeon->tiling_info.num_banks = 8;
break;
default:
return -EINVAL;
}
switch ((tiling_config & 0xc0) >> 6) {
case 0:
radeon->tiling_info.group_bytes = 256;
break;
case 1:
radeon->tiling_info.group_bytes = 512;
break;
default:
return -EINVAL;
}
return 0;
}
static int eg_interpret_tiling(struct radeon *radeon, uint32_t tiling_config)
{
switch (tiling_config & 0xf) {
case 0:
radeon->tiling_info.num_channels = 1;
break;
case 1:
radeon->tiling_info.num_channels = 2;
break;
case 2:
radeon->tiling_info.num_channels = 4;
break;
case 3:
radeon->tiling_info.num_channels = 8;
break;
default:
return -EINVAL;
}
switch ((tiling_config & 0xf0) >> 4) {
case 0:
radeon->tiling_info.num_banks = 4;
break;
case 1:
radeon->tiling_info.num_banks = 8;
break;
case 2:
radeon->tiling_info.num_banks = 16;
break;
default:
return -EINVAL;
}
switch ((tiling_config & 0xf00) >> 8) {
case 0:
radeon->tiling_info.group_bytes = 256;
break;
case 1:
radeon->tiling_info.group_bytes = 512;
break;
default:
return -EINVAL;
}
return 0;
}
static int radeon_drm_get_tiling(struct radeon *radeon)
{
uint32_t tiling_config = radeon->info.r600_tiling_config;
if (!tiling_config)
return 0;
if (radeon->chip_class == R600 || radeon->chip_class == R700) {
return r600_interpret_tiling(radeon, tiling_config);
} else {
return eg_interpret_tiling(radeon, tiling_config);
}
}
static int radeon_get_num_tile_pipes(struct radeon *radeon)
{
struct drm_radeon_info info = {};
uint32_t num_tile_pipes = 0;
int r;
info.request = RADEON_INFO_NUM_TILE_PIPES;
info.value = (uintptr_t)&num_tile_pipes;
r = drmCommandWriteRead(radeon->info.fd, DRM_RADEON_INFO, &info,
sizeof(struct drm_radeon_info));
if (r)
return r;
radeon->num_tile_pipes = num_tile_pipes;
return 0;
}
static int radeon_get_backend_map(struct radeon *radeon)
{
struct drm_radeon_info info = {};
uint32_t backend_map = 0;
int r;
info.request = RADEON_INFO_BACKEND_MAP;
info.value = (uintptr_t)&backend_map;
r = drmCommandWriteRead(radeon->info.fd, DRM_RADEON_INFO, &info,
sizeof(struct drm_radeon_info));
if (r)
return r;
radeon->backend_map = backend_map;
radeon->backend_map_valid = TRUE;
return 0;
}
struct radeon *radeon_create(struct radeon_winsys *ws)
{
struct radeon *radeon = CALLOC_STRUCT(radeon);
if (radeon == NULL) {
return NULL;
}
radeon->ws = ws;
ws->query_info(ws, &radeon->info);
radeon->family = radeon_family_from_device(radeon->info.pci_id);
if (radeon->family == CHIP_UNKNOWN) {
fprintf(stderr, "Unknown chipset 0x%04X\n", radeon->info.pci_id);
return radeon_destroy(radeon);
}
/* setup class */
switch (radeon->family) {
case CHIP_R600:
case CHIP_RV610:
case CHIP_RV630:
case CHIP_RV670:
case CHIP_RV620:
case CHIP_RV635:
case CHIP_RS780:
case CHIP_RS880:
radeon->chip_class = R600;
/* set default group bytes, overridden by tiling info ioctl */
radeon->tiling_info.group_bytes = 256;
break;
case CHIP_RV770:
case CHIP_RV730:
case CHIP_RV710:
case CHIP_RV740:
radeon->chip_class = R700;
/* set default group bytes, overridden by tiling info ioctl */
radeon->tiling_info.group_bytes = 256;
break;
case CHIP_CEDAR:
case CHIP_REDWOOD:
case CHIP_JUNIPER:
case CHIP_CYPRESS:
case CHIP_HEMLOCK:
case CHIP_PALM:
case CHIP_SUMO:
case CHIP_SUMO2:
case CHIP_BARTS:
case CHIP_TURKS:
case CHIP_CAICOS:
radeon->chip_class = EVERGREEN;
/* set default group bytes, overridden by tiling info ioctl */
radeon->tiling_info.group_bytes = 512;
break;
case CHIP_CAYMAN:
radeon->chip_class = CAYMAN;
/* set default group bytes, overridden by tiling info ioctl */
radeon->tiling_info.group_bytes = 512;
break;
default:
fprintf(stderr, "%s unknown or unsupported chipset 0x%04X\n",
__func__, radeon->info.pci_id);
break;
}
if (radeon_drm_get_tiling(radeon))
return NULL;
if (radeon->info.drm_minor >= 11) {
radeon_get_num_tile_pipes(radeon);
radeon_get_backend_map(radeon);
}
/* XXX disable ioctl thread offloading until the porting is done. */
setenv("RADEON_THREAD", "0", 0);
return radeon;
}
struct radeon *radeon_destroy(struct radeon *radeon)
{
if (radeon == NULL)
return NULL;
FREE(radeon);
return NULL;
}