Merge branch 'drm-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/airlied/drm-2.6

* 'drm-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/airlied/drm-2.6:
  drm/radeon/kms: fix r100->r500 CS checker for compressed textures. (v2)
  drm/radeon/kms: allow for texture tiling
  drm/radeon/kms: init pm on all chipsets
  drm/radeon/kms: HDMI support for R600 KMS
  drm/radeon/kms: make sure mc is initialized before mapping blit bo
  drm/radeon/kms: Return to userspace on ERESTARTSYS
  drm/radeon/gem: don't leak a gem object if reserve fails on get tiling (v2)
  drm/radeon/kms: don't report allocate failure on ERESTARTSYS
  drm/radeon/kms: Check if bo we got from ttm are radeon object or not
  drm/radeon/kms: If no placement is supplied fallback to system
  drm/ttm: Fix memory type manager debug information printing
  drm/ttm: Fix printk format & compute bo->mem.size at bo initialization
  drm/ttm: Fix potential ttm_mem_evict_first races.
  drm/ttm: Delayed delete fixes.
  drm/ttm: fix two bugs in new placement routines.
  drm/ttm: fix incorrect logic in ttm_bo_io path
  drm/nouveau: remove use of -ERESTART
  nouveau: Fix endianness with new context program loader
  drm/nouveau: fix build with CONFIG_AGP=n
  drm/nouveau: fix ch7006 build
This commit is contained in:
Linus Torvalds 2009-12-16 10:30:17 -08:00
commit c5113e3d66
28 changed files with 1118 additions and 92 deletions

View file

@ -30,11 +30,12 @@ config DRM_NOUVEAU_DEBUG
via debugfs. via debugfs.
menu "I2C encoder or helper chips" menu "I2C encoder or helper chips"
depends on DRM depends on DRM && I2C
config DRM_I2C_CH7006 config DRM_I2C_CH7006
tristate "Chrontel ch7006 TV encoder" tristate "Chrontel ch7006 TV encoder"
default m if DRM_NOUVEAU depends on DRM_NOUVEAU
default m
help help
Support for Chrontel ch7006 and similar TV encoders, found Support for Chrontel ch7006 and similar TV encoders, found
on some nVidia video cards. on some nVidia video cards.

View file

@ -311,8 +311,10 @@ nouveau_bo_create_ttm_backend_entry(struct ttm_bo_device *bdev)
struct drm_device *dev = dev_priv->dev; struct drm_device *dev = dev_priv->dev;
switch (dev_priv->gart_info.type) { switch (dev_priv->gart_info.type) {
#if __OS_HAS_AGP
case NOUVEAU_GART_AGP: case NOUVEAU_GART_AGP:
return ttm_agp_backend_init(bdev, dev->agp->bridge); return ttm_agp_backend_init(bdev, dev->agp->bridge);
#endif
case NOUVEAU_GART_SGDMA: case NOUVEAU_GART_SGDMA:
return nouveau_sgdma_init_ttm(dev); return nouveau_sgdma_init_ttm(dev);
default: default:

View file

@ -205,7 +205,7 @@ nouveau_fence_wait(void *sync_obj, void *sync_arg, bool lazy, bool intr)
schedule_timeout(1); schedule_timeout(1);
if (intr && signal_pending(current)) { if (intr && signal_pending(current)) {
ret = -ERESTART; ret = -ERESTARTSYS;
break; break;
} }
} }

View file

@ -342,8 +342,6 @@ retry:
} }
ret = ttm_bo_wait_cpu(&nvbo->bo, false); ret = ttm_bo_wait_cpu(&nvbo->bo, false);
if (ret == -ERESTART)
ret = -EAGAIN;
if (ret) if (ret)
return ret; return ret;
goto retry; goto retry;
@ -915,8 +913,6 @@ nouveau_gem_ioctl_cpu_prep(struct drm_device *dev, void *data,
goto out; goto out;
ret = ttm_bo_wait_cpu(&nvbo->bo, no_wait); ret = ttm_bo_wait_cpu(&nvbo->bo, no_wait);
if (ret == -ERESTART)
ret = -EAGAIN;
if (ret) if (ret)
goto out; goto out;
} }
@ -925,9 +921,6 @@ nouveau_gem_ioctl_cpu_prep(struct drm_device *dev, void *data,
ret = ttm_bo_wait(&nvbo->bo, false, false, no_wait); ret = ttm_bo_wait(&nvbo->bo, false, false, no_wait);
} else { } else {
ret = ttm_bo_synccpu_write_grab(&nvbo->bo, no_wait); ret = ttm_bo_synccpu_write_grab(&nvbo->bo, no_wait);
if (ret == -ERESTART)
ret = -EAGAIN;
else
if (ret == 0) if (ret == 0)
nvbo->cpu_filp = file_priv; nvbo->cpu_filp = file_priv;
} }

View file

@ -407,6 +407,7 @@ uint64_t nouveau_mem_fb_amount(struct drm_device *dev)
return 0; return 0;
} }
#if __OS_HAS_AGP
static void nouveau_mem_reset_agp(struct drm_device *dev) static void nouveau_mem_reset_agp(struct drm_device *dev)
{ {
uint32_t saved_pci_nv_1, saved_pci_nv_19, pmc_enable; uint32_t saved_pci_nv_1, saved_pci_nv_19, pmc_enable;
@ -432,10 +433,12 @@ static void nouveau_mem_reset_agp(struct drm_device *dev)
nv_wr32(dev, NV04_PBUS_PCI_NV_19, saved_pci_nv_19); nv_wr32(dev, NV04_PBUS_PCI_NV_19, saved_pci_nv_19);
nv_wr32(dev, NV04_PBUS_PCI_NV_1, saved_pci_nv_1); nv_wr32(dev, NV04_PBUS_PCI_NV_1, saved_pci_nv_1);
} }
#endif
int int
nouveau_mem_init_agp(struct drm_device *dev) nouveau_mem_init_agp(struct drm_device *dev)
{ {
#if __OS_HAS_AGP
struct drm_nouveau_private *dev_priv = dev->dev_private; struct drm_nouveau_private *dev_priv = dev->dev_private;
struct drm_agp_info info; struct drm_agp_info info;
struct drm_agp_mode mode; struct drm_agp_mode mode;
@ -471,6 +474,7 @@ nouveau_mem_init_agp(struct drm_device *dev)
dev_priv->gart_info.type = NOUVEAU_GART_AGP; dev_priv->gart_info.type = NOUVEAU_GART_AGP;
dev_priv->gart_info.aper_base = info.aperture_base; dev_priv->gart_info.aper_base = info.aperture_base;
dev_priv->gart_info.aper_size = info.aperture_size; dev_priv->gart_info.aper_size = info.aperture_size;
#endif
return 0; return 0;
} }

View file

@ -252,8 +252,9 @@ nv40_grctx_init(struct drm_device *dev)
memcpy(pgraph->ctxprog, fw->data, fw->size); memcpy(pgraph->ctxprog, fw->data, fw->size);
cp = pgraph->ctxprog; cp = pgraph->ctxprog;
if (cp->signature != 0x5043564e || cp->version != 0 || if (le32_to_cpu(cp->signature) != 0x5043564e ||
cp->length != ((fw->size - 7) / 4)) { cp->version != 0 ||
le16_to_cpu(cp->length) != ((fw->size - 7) / 4)) {
NV_ERROR(dev, "ctxprog invalid\n"); NV_ERROR(dev, "ctxprog invalid\n");
release_firmware(fw); release_firmware(fw);
nv40_grctx_fini(dev); nv40_grctx_fini(dev);
@ -281,8 +282,9 @@ nv40_grctx_init(struct drm_device *dev)
memcpy(pgraph->ctxvals, fw->data, fw->size); memcpy(pgraph->ctxvals, fw->data, fw->size);
cv = (void *)pgraph->ctxvals; cv = (void *)pgraph->ctxvals;
if (cv->signature != 0x5643564e || cv->version != 0 || if (le32_to_cpu(cv->signature) != 0x5643564e ||
cv->length != ((fw->size - 9) / 8)) { cv->version != 0 ||
le32_to_cpu(cv->length) != ((fw->size - 9) / 8)) {
NV_ERROR(dev, "ctxvals invalid\n"); NV_ERROR(dev, "ctxvals invalid\n");
release_firmware(fw); release_firmware(fw);
nv40_grctx_fini(dev); nv40_grctx_fini(dev);
@ -294,8 +296,9 @@ nv40_grctx_init(struct drm_device *dev)
cp = pgraph->ctxprog; cp = pgraph->ctxprog;
nv_wr32(dev, NV40_PGRAPH_CTXCTL_UCODE_INDEX, 0); nv_wr32(dev, NV40_PGRAPH_CTXCTL_UCODE_INDEX, 0);
for (i = 0; i < cp->length; i++) for (i = 0; i < le16_to_cpu(cp->length); i++)
nv_wr32(dev, NV40_PGRAPH_CTXCTL_UCODE_DATA, cp->data[i]); nv_wr32(dev, NV40_PGRAPH_CTXCTL_UCODE_DATA,
le32_to_cpu(cp->data[i]));
pgraph->accel_blocked = false; pgraph->accel_blocked = false;
return 0; return 0;
@ -329,8 +332,9 @@ nv40_grctx_vals_load(struct drm_device *dev, struct nouveau_gpuobj *ctx)
if (!cv) if (!cv)
return; return;
for (i = 0; i < cv->length; i++) for (i = 0; i < le32_to_cpu(cv->length); i++)
nv_wo32(dev, ctx, cv->data[i].offset, cv->data[i].value); nv_wo32(dev, ctx, le32_to_cpu(cv->data[i].offset),
le32_to_cpu(cv->data[i].value));
} }
/* /*

View file

@ -49,7 +49,7 @@ radeon-y += radeon_device.o radeon_kms.o \
radeon_cs.o radeon_bios.o radeon_benchmark.o r100.o r300.o r420.o \ radeon_cs.o radeon_bios.o radeon_benchmark.o r100.o r300.o r420.o \
rs400.o rs600.o rs690.o rv515.o r520.o r600.o rv770.o radeon_test.o \ rs400.o rs600.o rs690.o rv515.o r520.o r600.o rv770.o radeon_test.o \
r200.o radeon_legacy_tv.o r600_cs.o r600_blit.o r600_blit_shaders.o \ r200.o radeon_legacy_tv.o r600_cs.o r600_blit.o r600_blit_shaders.o \
r600_blit_kms.o radeon_pm.o atombios_dp.o r600_blit_kms.o radeon_pm.o atombios_dp.o r600_audio.o r600_hdmi.o
radeon-$(CONFIG_COMPAT) += radeon_ioc32.o radeon-$(CONFIG_COMPAT) += radeon_ioc32.o

View file

@ -1374,7 +1374,6 @@ static int r100_packet0_check(struct radeon_cs_parser *p,
case RADEON_TXFORMAT_ARGB4444: case RADEON_TXFORMAT_ARGB4444:
case RADEON_TXFORMAT_VYUY422: case RADEON_TXFORMAT_VYUY422:
case RADEON_TXFORMAT_YVYU422: case RADEON_TXFORMAT_YVYU422:
case RADEON_TXFORMAT_DXT1:
case RADEON_TXFORMAT_SHADOW16: case RADEON_TXFORMAT_SHADOW16:
case RADEON_TXFORMAT_LDUDV655: case RADEON_TXFORMAT_LDUDV655:
case RADEON_TXFORMAT_DUDV88: case RADEON_TXFORMAT_DUDV88:
@ -1382,12 +1381,19 @@ static int r100_packet0_check(struct radeon_cs_parser *p,
break; break;
case RADEON_TXFORMAT_ARGB8888: case RADEON_TXFORMAT_ARGB8888:
case RADEON_TXFORMAT_RGBA8888: case RADEON_TXFORMAT_RGBA8888:
case RADEON_TXFORMAT_DXT23:
case RADEON_TXFORMAT_DXT45:
case RADEON_TXFORMAT_SHADOW32: case RADEON_TXFORMAT_SHADOW32:
case RADEON_TXFORMAT_LDUDUV8888: case RADEON_TXFORMAT_LDUDUV8888:
track->textures[i].cpp = 4; track->textures[i].cpp = 4;
break; break;
case RADEON_TXFORMAT_DXT1:
track->textures[i].cpp = 1;
track->textures[i].compress_format = R100_TRACK_COMP_DXT1;
break;
case RADEON_TXFORMAT_DXT23:
case RADEON_TXFORMAT_DXT45:
track->textures[i].cpp = 1;
track->textures[i].compress_format = R100_TRACK_COMP_DXT35;
break;
} }
track->textures[i].cube_info[4].width = 1 << ((idx_value >> 16) & 0xf); track->textures[i].cube_info[4].width = 1 << ((idx_value >> 16) & 0xf);
track->textures[i].cube_info[4].height = 1 << ((idx_value >> 20) & 0xf); track->textures[i].cube_info[4].height = 1 << ((idx_value >> 20) & 0xf);
@ -2731,6 +2737,7 @@ static inline void r100_cs_track_texture_print(struct r100_cs_track_texture *t)
DRM_ERROR("coordinate type %d\n", t->tex_coord_type); DRM_ERROR("coordinate type %d\n", t->tex_coord_type);
DRM_ERROR("width round to power of 2 %d\n", t->roundup_w); DRM_ERROR("width round to power of 2 %d\n", t->roundup_w);
DRM_ERROR("height round to power of 2 %d\n", t->roundup_h); DRM_ERROR("height round to power of 2 %d\n", t->roundup_h);
DRM_ERROR("compress format %d\n", t->compress_format);
} }
static int r100_cs_track_cube(struct radeon_device *rdev, static int r100_cs_track_cube(struct radeon_device *rdev,
@ -2760,6 +2767,36 @@ static int r100_cs_track_cube(struct radeon_device *rdev,
return 0; return 0;
} }
static int r100_track_compress_size(int compress_format, int w, int h)
{
int block_width, block_height, block_bytes;
int wblocks, hblocks;
int min_wblocks;
int sz;
block_width = 4;
block_height = 4;
switch (compress_format) {
case R100_TRACK_COMP_DXT1:
block_bytes = 8;
min_wblocks = 4;
break;
default:
case R100_TRACK_COMP_DXT35:
block_bytes = 16;
min_wblocks = 2;
break;
}
hblocks = (h + block_height - 1) / block_height;
wblocks = (w + block_width - 1) / block_width;
if (wblocks < min_wblocks)
wblocks = min_wblocks;
sz = wblocks * hblocks * block_bytes;
return sz;
}
static int r100_cs_track_texture_check(struct radeon_device *rdev, static int r100_cs_track_texture_check(struct radeon_device *rdev,
struct r100_cs_track *track) struct r100_cs_track *track)
{ {
@ -2797,9 +2834,15 @@ static int r100_cs_track_texture_check(struct radeon_device *rdev,
h = h / (1 << i); h = h / (1 << i);
if (track->textures[u].roundup_h) if (track->textures[u].roundup_h)
h = roundup_pow_of_two(h); h = roundup_pow_of_two(h);
size += w * h; if (track->textures[u].compress_format) {
size += r100_track_compress_size(track->textures[u].compress_format, w, h);
/* compressed textures are block based */
} else
size += w * h;
} }
size *= track->textures[u].cpp; size *= track->textures[u].cpp;
switch (track->textures[u].tex_coord_type) { switch (track->textures[u].tex_coord_type) {
case 0: case 0:
break; break;
@ -2967,6 +3010,7 @@ void r100_cs_track_clear(struct radeon_device *rdev, struct r100_cs_track *track
track->arrays[i].esize = 0x7F; track->arrays[i].esize = 0x7F;
} }
for (i = 0; i < track->num_texture; i++) { for (i = 0; i < track->num_texture; i++) {
track->textures[i].compress_format = R100_TRACK_COMP_NONE;
track->textures[i].pitch = 16536; track->textures[i].pitch = 16536;
track->textures[i].width = 16536; track->textures[i].width = 16536;
track->textures[i].height = 16536; track->textures[i].height = 16536;
@ -3399,6 +3443,8 @@ int r100_init(struct radeon_device *rdev)
r100_errata(rdev); r100_errata(rdev);
/* Initialize clocks */ /* Initialize clocks */
radeon_get_clock_info(rdev->ddev); radeon_get_clock_info(rdev->ddev);
/* Initialize power management */
radeon_pm_init(rdev);
/* Get vram informations */ /* Get vram informations */
r100_vram_info(rdev); r100_vram_info(rdev);
/* Initialize memory controller (also test AGP) */ /* Initialize memory controller (also test AGP) */

View file

@ -28,6 +28,10 @@ struct r100_cs_cube_info {
unsigned height; unsigned height;
}; };
#define R100_TRACK_COMP_NONE 0
#define R100_TRACK_COMP_DXT1 1
#define R100_TRACK_COMP_DXT35 2
struct r100_cs_track_texture { struct r100_cs_track_texture {
struct radeon_bo *robj; struct radeon_bo *robj;
struct r100_cs_cube_info cube_info[5]; /* info for 5 non-primary faces */ struct r100_cs_cube_info cube_info[5]; /* info for 5 non-primary faces */
@ -44,6 +48,7 @@ struct r100_cs_track_texture {
bool enabled; bool enabled;
bool roundup_w; bool roundup_w;
bool roundup_h; bool roundup_h;
unsigned compress_format;
}; };
struct r100_cs_track_limits { struct r100_cs_track_limits {

View file

@ -401,7 +401,6 @@ int r200_packet0_check(struct radeon_cs_parser *p,
case R200_TXFORMAT_Y8: case R200_TXFORMAT_Y8:
track->textures[i].cpp = 1; track->textures[i].cpp = 1;
break; break;
case R200_TXFORMAT_DXT1:
case R200_TXFORMAT_AI88: case R200_TXFORMAT_AI88:
case R200_TXFORMAT_ARGB1555: case R200_TXFORMAT_ARGB1555:
case R200_TXFORMAT_RGB565: case R200_TXFORMAT_RGB565:
@ -418,9 +417,16 @@ int r200_packet0_check(struct radeon_cs_parser *p,
case R200_TXFORMAT_ABGR8888: case R200_TXFORMAT_ABGR8888:
case R200_TXFORMAT_BGR111110: case R200_TXFORMAT_BGR111110:
case R200_TXFORMAT_LDVDU8888: case R200_TXFORMAT_LDVDU8888:
track->textures[i].cpp = 4;
break;
case R200_TXFORMAT_DXT1:
track->textures[i].cpp = 1;
track->textures[i].compress_format = R100_TRACK_COMP_DXT1;
break;
case R200_TXFORMAT_DXT23: case R200_TXFORMAT_DXT23:
case R200_TXFORMAT_DXT45: case R200_TXFORMAT_DXT45:
track->textures[i].cpp = 4; track->textures[i].cpp = 1;
track->textures[i].compress_format = R100_TRACK_COMP_DXT1;
break; break;
} }
track->textures[i].cube_info[4].width = 1 << ((idx_value >> 16) & 0xf); track->textures[i].cube_info[4].width = 1 << ((idx_value >> 16) & 0xf);

View file

@ -686,7 +686,15 @@ static int r300_packet0_check(struct radeon_cs_parser *p,
r100_cs_dump_packet(p, pkt); r100_cs_dump_packet(p, pkt);
return r; return r;
} }
ib[idx] = idx_value + ((u32)reloc->lobj.gpu_offset);
if (reloc->lobj.tiling_flags & RADEON_TILING_MACRO)
tile_flags |= R300_TXO_MACRO_TILE;
if (reloc->lobj.tiling_flags & RADEON_TILING_MICRO)
tile_flags |= R300_TXO_MICRO_TILE;
tmp = idx_value + ((u32)reloc->lobj.gpu_offset);
tmp |= tile_flags;
ib[idx] = tmp;
track->textures[i].robj = reloc->robj; track->textures[i].robj = reloc->robj;
break; break;
/* Tracked registers */ /* Tracked registers */
@ -852,7 +860,6 @@ static int r300_packet0_check(struct radeon_cs_parser *p,
case R300_TX_FORMAT_Z6Y5X5: case R300_TX_FORMAT_Z6Y5X5:
case R300_TX_FORMAT_W4Z4Y4X4: case R300_TX_FORMAT_W4Z4Y4X4:
case R300_TX_FORMAT_W1Z5Y5X5: case R300_TX_FORMAT_W1Z5Y5X5:
case R300_TX_FORMAT_DXT1:
case R300_TX_FORMAT_D3DMFT_CxV8U8: case R300_TX_FORMAT_D3DMFT_CxV8U8:
case R300_TX_FORMAT_B8G8_B8G8: case R300_TX_FORMAT_B8G8_B8G8:
case R300_TX_FORMAT_G8R8_G8B8: case R300_TX_FORMAT_G8R8_G8B8:
@ -866,8 +873,6 @@ static int r300_packet0_check(struct radeon_cs_parser *p,
case 0x17: case 0x17:
case R300_TX_FORMAT_FL_I32: case R300_TX_FORMAT_FL_I32:
case 0x1e: case 0x1e:
case R300_TX_FORMAT_DXT3:
case R300_TX_FORMAT_DXT5:
track->textures[i].cpp = 4; track->textures[i].cpp = 4;
break; break;
case R300_TX_FORMAT_W16Z16Y16X16: case R300_TX_FORMAT_W16Z16Y16X16:
@ -878,6 +883,15 @@ static int r300_packet0_check(struct radeon_cs_parser *p,
case R300_TX_FORMAT_FL_R32G32B32A32: case R300_TX_FORMAT_FL_R32G32B32A32:
track->textures[i].cpp = 16; track->textures[i].cpp = 16;
break; break;
case R300_TX_FORMAT_DXT1:
track->textures[i].cpp = 1;
track->textures[i].compress_format = R100_TRACK_COMP_DXT1;
break;
case R300_TX_FORMAT_DXT3:
case R300_TX_FORMAT_DXT5:
track->textures[i].cpp = 1;
track->textures[i].compress_format = R100_TRACK_COMP_DXT35;
break;
default: default:
DRM_ERROR("Invalid texture format %u\n", DRM_ERROR("Invalid texture format %u\n",
(idx_value & 0x1F)); (idx_value & 0x1F));
@ -1324,6 +1338,8 @@ int r300_init(struct radeon_device *rdev)
r300_errata(rdev); r300_errata(rdev);
/* Initialize clocks */ /* Initialize clocks */
radeon_get_clock_info(rdev->ddev); radeon_get_clock_info(rdev->ddev);
/* Initialize power management */
radeon_pm_init(rdev);
/* Get vram informations */ /* Get vram informations */
r300_vram_info(rdev); r300_vram_info(rdev);
/* Initialize memory controller (also test AGP) */ /* Initialize memory controller (also test AGP) */

View file

@ -1863,6 +1863,14 @@ int r600_startup(struct radeon_device *rdev)
} }
r600_gpu_init(rdev); r600_gpu_init(rdev);
if (!rdev->r600_blit.shader_obj) {
r = r600_blit_init(rdev);
if (r) {
DRM_ERROR("radeon: failed blitter (%d).\n", r);
return r;
}
}
r = radeon_bo_reserve(rdev->r600_blit.shader_obj, false); r = radeon_bo_reserve(rdev->r600_blit.shader_obj, false);
if (unlikely(r != 0)) if (unlikely(r != 0))
return r; return r;
@ -2038,12 +2046,6 @@ int r600_init(struct radeon_device *rdev)
if (r) if (r)
return r; return r;
r = r600_blit_init(rdev);
if (r) {
DRM_ERROR("radeon: failed blitter (%d).\n", r);
return r;
}
rdev->accel_working = true; rdev->accel_working = true;
r = r600_startup(rdev); r = r600_startup(rdev);
if (r) { if (r) {
@ -2065,6 +2067,10 @@ int r600_init(struct radeon_device *rdev)
rdev->accel_working = false; rdev->accel_working = false;
} }
} }
r = r600_audio_init(rdev);
if (r)
return r; /* TODO error handling */
return 0; return 0;
} }
@ -2073,6 +2079,7 @@ void r600_fini(struct radeon_device *rdev)
/* Suspend operations */ /* Suspend operations */
r600_suspend(rdev); r600_suspend(rdev);
r600_audio_fini(rdev);
r600_blit_fini(rdev); r600_blit_fini(rdev);
r600_irq_fini(rdev); r600_irq_fini(rdev);
radeon_irq_kms_fini(rdev); radeon_irq_kms_fini(rdev);

View file

@ -0,0 +1,267 @@
/*
* Copyright 2008 Advanced Micro Devices, Inc.
* Copyright 2008 Red Hat Inc.
* Copyright 2009 Christian König.
*
* 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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: Christian König
*/
#include "drmP.h"
#include "radeon.h"
#include "radeon_reg.h"
#include "atom.h"
#define AUDIO_TIMER_INTERVALL 100 /* 1/10 sekund should be enough */
/*
* check if the chipset is supported
*/
static int r600_audio_chipset_supported(struct radeon_device *rdev)
{
return rdev->family >= CHIP_R600
|| rdev->family == CHIP_RS600
|| rdev->family == CHIP_RS690
|| rdev->family == CHIP_RS740;
}
/*
* current number of channels
*/
static int r600_audio_channels(struct radeon_device *rdev)
{
return (RREG32(R600_AUDIO_RATE_BPS_CHANNEL) & 0x7) + 1;
}
/*
* current bits per sample
*/
static int r600_audio_bits_per_sample(struct radeon_device *rdev)
{
uint32_t value = (RREG32(R600_AUDIO_RATE_BPS_CHANNEL) & 0xF0) >> 4;
switch (value) {
case 0x0: return 8;
case 0x1: return 16;
case 0x2: return 20;
case 0x3: return 24;
case 0x4: return 32;
}
DRM_ERROR("Unknown bits per sample 0x%x using 16 instead.\n", (int)value);
return 16;
}
/*
* current sampling rate in HZ
*/
static int r600_audio_rate(struct radeon_device *rdev)
{
uint32_t value = RREG32(R600_AUDIO_RATE_BPS_CHANNEL);
uint32_t result;
if (value & 0x4000)
result = 44100;
else
result = 48000;
result *= ((value >> 11) & 0x7) + 1;
result /= ((value >> 8) & 0x7) + 1;
return result;
}
/*
* iec 60958 status bits
*/
static uint8_t r600_audio_status_bits(struct radeon_device *rdev)
{
return RREG32(R600_AUDIO_STATUS_BITS) & 0xff;
}
/*
* iec 60958 category code
*/
static uint8_t r600_audio_category_code(struct radeon_device *rdev)
{
return (RREG32(R600_AUDIO_STATUS_BITS) >> 8) & 0xff;
}
/*
* update all hdmi interfaces with current audio parameters
*/
static void r600_audio_update_hdmi(unsigned long param)
{
struct radeon_device *rdev = (struct radeon_device *)param;
struct drm_device *dev = rdev->ddev;
int channels = r600_audio_channels(rdev);
int rate = r600_audio_rate(rdev);
int bps = r600_audio_bits_per_sample(rdev);
uint8_t status_bits = r600_audio_status_bits(rdev);
uint8_t category_code = r600_audio_category_code(rdev);
struct drm_encoder *encoder;
int changes = 0;
changes |= channels != rdev->audio_channels;
changes |= rate != rdev->audio_rate;
changes |= bps != rdev->audio_bits_per_sample;
changes |= status_bits != rdev->audio_status_bits;
changes |= category_code != rdev->audio_category_code;
if (changes) {
rdev->audio_channels = channels;
rdev->audio_rate = rate;
rdev->audio_bits_per_sample = bps;
rdev->audio_status_bits = status_bits;
rdev->audio_category_code = category_code;
}
list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
if (changes || r600_hdmi_buffer_status_changed(encoder))
r600_hdmi_update_audio_settings(
encoder, channels,
rate, bps, status_bits,
category_code);
}
mod_timer(&rdev->audio_timer,
jiffies + msecs_to_jiffies(AUDIO_TIMER_INTERVALL));
}
/*
* initialize the audio vars and register the update timer
*/
int r600_audio_init(struct radeon_device *rdev)
{
if (!r600_audio_chipset_supported(rdev))
return 0;
DRM_INFO("%s audio support", radeon_audio ? "Enabling" : "Disabling");
WREG32_P(R600_AUDIO_ENABLE, radeon_audio ? 0x81000000 : 0x0, ~0x81000000);
rdev->audio_channels = -1;
rdev->audio_rate = -1;
rdev->audio_bits_per_sample = -1;
rdev->audio_status_bits = 0;
rdev->audio_category_code = 0;
setup_timer(
&rdev->audio_timer,
r600_audio_update_hdmi,
(unsigned long)rdev);
mod_timer(&rdev->audio_timer, jiffies + 1);
return 0;
}
/*
* determin how the encoders and audio interface is wired together
*/
int r600_audio_tmds_index(struct drm_encoder *encoder)
{
struct drm_device *dev = encoder->dev;
struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
struct drm_encoder *other;
switch (radeon_encoder->encoder_id) {
case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_TMDS1:
case ENCODER_OBJECT_ID_INTERNAL_UNIPHY:
case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1:
return 0;
case ENCODER_OBJECT_ID_INTERNAL_LVTM1:
/* special case check if an TMDS1 is present */
list_for_each_entry(other, &dev->mode_config.encoder_list, head) {
if (to_radeon_encoder(other)->encoder_id ==
ENCODER_OBJECT_ID_INTERNAL_TMDS1)
return 1;
}
return 0;
case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2:
case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA:
return 1;
default:
DRM_ERROR("Unsupported encoder type 0x%02X\n",
radeon_encoder->encoder_id);
return -1;
}
}
/*
* atach the audio codec to the clock source of the encoder
*/
void r600_audio_set_clock(struct drm_encoder *encoder, int clock)
{
struct drm_device *dev = encoder->dev;
struct radeon_device *rdev = dev->dev_private;
struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
int base_rate = 48000;
switch (radeon_encoder->encoder_id) {
case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_TMDS1:
case ENCODER_OBJECT_ID_INTERNAL_LVTM1:
WREG32_P(R600_AUDIO_TIMING, 0, ~0x301);
break;
case ENCODER_OBJECT_ID_INTERNAL_UNIPHY:
case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1:
case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2:
case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA:
WREG32_P(R600_AUDIO_TIMING, 0x100, ~0x301);
break;
default:
DRM_ERROR("Unsupported encoder type 0x%02X\n",
radeon_encoder->encoder_id);
return;
}
switch (r600_audio_tmds_index(encoder)) {
case 0:
WREG32(R600_AUDIO_PLL1_MUL, base_rate*50);
WREG32(R600_AUDIO_PLL1_DIV, clock*100);
WREG32(R600_AUDIO_CLK_SRCSEL, 0);
break;
case 1:
WREG32(R600_AUDIO_PLL2_MUL, base_rate*50);
WREG32(R600_AUDIO_PLL2_DIV, clock*100);
WREG32(R600_AUDIO_CLK_SRCSEL, 1);
break;
}
}
/*
* release the audio timer
* TODO: How to do this correctly on SMP systems?
*/
void r600_audio_fini(struct radeon_device *rdev)
{
if (!r600_audio_chipset_supported(rdev))
return;
WREG32_P(R600_AUDIO_ENABLE, 0x0, ~0x81000000);
del_timer(&rdev->audio_timer);
}

View file

@ -0,0 +1,506 @@
/*
* Copyright 2008 Advanced Micro Devices, Inc.
* Copyright 2008 Red Hat Inc.
* Copyright 2009 Christian König.
*
* 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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: Christian König
*/
#include "drmP.h"
#include "radeon_drm.h"
#include "radeon.h"
#include "atom.h"
/*
* HDMI color format
*/
enum r600_hdmi_color_format {
RGB = 0,
YCC_422 = 1,
YCC_444 = 2
};
/*
* IEC60958 status bits
*/
enum r600_hdmi_iec_status_bits {
AUDIO_STATUS_DIG_ENABLE = 0x01,
AUDIO_STATUS_V = 0x02,
AUDIO_STATUS_VCFG = 0x04,
AUDIO_STATUS_EMPHASIS = 0x08,
AUDIO_STATUS_COPYRIGHT = 0x10,
AUDIO_STATUS_NONAUDIO = 0x20,
AUDIO_STATUS_PROFESSIONAL = 0x40,
AUDIO_STATUS_LEVEL = 0x80
};
struct {
uint32_t Clock;
int N_32kHz;
int CTS_32kHz;
int N_44_1kHz;
int CTS_44_1kHz;
int N_48kHz;
int CTS_48kHz;
} r600_hdmi_ACR[] = {
/* 32kHz 44.1kHz 48kHz */
/* Clock N CTS N CTS N CTS */
{ 25174, 4576, 28125, 7007, 31250, 6864, 28125 }, /* 25,20/1.001 MHz */
{ 25200, 4096, 25200, 6272, 28000, 6144, 25200 }, /* 25.20 MHz */
{ 27000, 4096, 27000, 6272, 30000, 6144, 27000 }, /* 27.00 MHz */
{ 27027, 4096, 27027, 6272, 30030, 6144, 27027 }, /* 27.00*1.001 MHz */
{ 54000, 4096, 54000, 6272, 60000, 6144, 54000 }, /* 54.00 MHz */
{ 54054, 4096, 54054, 6272, 60060, 6144, 54054 }, /* 54.00*1.001 MHz */
{ 74175, 11648, 210937, 17836, 234375, 11648, 140625 }, /* 74.25/1.001 MHz */
{ 74250, 4096, 74250, 6272, 82500, 6144, 74250 }, /* 74.25 MHz */
{ 148351, 11648, 421875, 8918, 234375, 5824, 140625 }, /* 148.50/1.001 MHz */
{ 148500, 4096, 148500, 6272, 165000, 6144, 148500 }, /* 148.50 MHz */
{ 0, 4096, 0, 6272, 0, 6144, 0 } /* Other */
};
/*
* calculate CTS value if it's not found in the table
*/
static void r600_hdmi_calc_CTS(uint32_t clock, int *CTS, int N, int freq)
{
if (*CTS == 0)
*CTS = clock*N/(128*freq)*1000;
DRM_DEBUG("Using ACR timing N=%d CTS=%d for frequency %d\n",
N, *CTS, freq);
}
/*
* update the N and CTS parameters for a given pixel clock rate
*/
static void r600_hdmi_update_ACR(struct drm_encoder *encoder, uint32_t clock)
{
struct drm_device *dev = encoder->dev;
struct radeon_device *rdev = dev->dev_private;
uint32_t offset = to_radeon_encoder(encoder)->hdmi_offset;
int CTS;
int N;
int i;
for (i = 0; r600_hdmi_ACR[i].Clock != clock && r600_hdmi_ACR[i].Clock != 0; i++);
CTS = r600_hdmi_ACR[i].CTS_32kHz;
N = r600_hdmi_ACR[i].N_32kHz;
r600_hdmi_calc_CTS(clock, &CTS, N, 32000);
WREG32(offset+R600_HDMI_32kHz_CTS, CTS << 12);
WREG32(offset+R600_HDMI_32kHz_N, N);
CTS = r600_hdmi_ACR[i].CTS_44_1kHz;
N = r600_hdmi_ACR[i].N_44_1kHz;
r600_hdmi_calc_CTS(clock, &CTS, N, 44100);
WREG32(offset+R600_HDMI_44_1kHz_CTS, CTS << 12);
WREG32(offset+R600_HDMI_44_1kHz_N, N);
CTS = r600_hdmi_ACR[i].CTS_48kHz;
N = r600_hdmi_ACR[i].N_48kHz;
r600_hdmi_calc_CTS(clock, &CTS, N, 48000);
WREG32(offset+R600_HDMI_48kHz_CTS, CTS << 12);
WREG32(offset+R600_HDMI_48kHz_N, N);
}
/*
* calculate the crc for a given info frame
*/
static void r600_hdmi_infoframe_checksum(uint8_t packetType,
uint8_t versionNumber,
uint8_t length,
uint8_t *frame)
{
int i;
frame[0] = packetType + versionNumber + length;
for (i = 1; i <= length; i++)
frame[0] += frame[i];
frame[0] = 0x100 - frame[0];
}
/*
* build a HDMI Video Info Frame
*/
static void r600_hdmi_videoinfoframe(
struct drm_encoder *encoder,
enum r600_hdmi_color_format color_format,
int active_information_present,
uint8_t active_format_aspect_ratio,
uint8_t scan_information,
uint8_t colorimetry,
uint8_t ex_colorimetry,
uint8_t quantization,
int ITC,
uint8_t picture_aspect_ratio,
uint8_t video_format_identification,
uint8_t pixel_repetition,
uint8_t non_uniform_picture_scaling,
uint8_t bar_info_data_valid,
uint16_t top_bar,
uint16_t bottom_bar,
uint16_t left_bar,
uint16_t right_bar
)
{
struct drm_device *dev = encoder->dev;
struct radeon_device *rdev = dev->dev_private;
uint32_t offset = to_radeon_encoder(encoder)->hdmi_offset;
uint8_t frame[14];
frame[0x0] = 0;
frame[0x1] =
(scan_information & 0x3) |
((bar_info_data_valid & 0x3) << 2) |
((active_information_present & 0x1) << 4) |
((color_format & 0x3) << 5);
frame[0x2] =
(active_format_aspect_ratio & 0xF) |
((picture_aspect_ratio & 0x3) << 4) |
((colorimetry & 0x3) << 6);
frame[0x3] =
(non_uniform_picture_scaling & 0x3) |
((quantization & 0x3) << 2) |
((ex_colorimetry & 0x7) << 4) |
((ITC & 0x1) << 7);
frame[0x4] = (video_format_identification & 0x7F);
frame[0x5] = (pixel_repetition & 0xF);
frame[0x6] = (top_bar & 0xFF);
frame[0x7] = (top_bar >> 8);
frame[0x8] = (bottom_bar & 0xFF);
frame[0x9] = (bottom_bar >> 8);
frame[0xA] = (left_bar & 0xFF);
frame[0xB] = (left_bar >> 8);
frame[0xC] = (right_bar & 0xFF);
frame[0xD] = (right_bar >> 8);
r600_hdmi_infoframe_checksum(0x82, 0x02, 0x0D, frame);
WREG32(offset+R600_HDMI_VIDEOINFOFRAME_0,
frame[0x0] | (frame[0x1] << 8) | (frame[0x2] << 16) | (frame[0x3] << 24));
WREG32(offset+R600_HDMI_VIDEOINFOFRAME_1,
frame[0x4] | (frame[0x5] << 8) | (frame[0x6] << 16) | (frame[0x7] << 24));
WREG32(offset+R600_HDMI_VIDEOINFOFRAME_2,
frame[0x8] | (frame[0x9] << 8) | (frame[0xA] << 16) | (frame[0xB] << 24));
WREG32(offset+R600_HDMI_VIDEOINFOFRAME_3,
frame[0xC] | (frame[0xD] << 8));
}
/*
* build a Audio Info Frame
*/
static void r600_hdmi_audioinfoframe(
struct drm_encoder *encoder,
uint8_t channel_count,
uint8_t coding_type,
uint8_t sample_size,
uint8_t sample_frequency,
uint8_t format,
uint8_t channel_allocation,
uint8_t level_shift,
int downmix_inhibit
)
{
struct drm_device *dev = encoder->dev;
struct radeon_device *rdev = dev->dev_private;
uint32_t offset = to_radeon_encoder(encoder)->hdmi_offset;
uint8_t frame[11];
frame[0x0] = 0;
frame[0x1] = (channel_count & 0x7) | ((coding_type & 0xF) << 4);
frame[0x2] = (sample_size & 0x3) | ((sample_frequency & 0x7) << 2);
frame[0x3] = format;
frame[0x4] = channel_allocation;
frame[0x5] = ((level_shift & 0xF) << 3) | ((downmix_inhibit & 0x1) << 7);
frame[0x6] = 0;
frame[0x7] = 0;
frame[0x8] = 0;
frame[0x9] = 0;
frame[0xA] = 0;
r600_hdmi_infoframe_checksum(0x84, 0x01, 0x0A, frame);
WREG32(offset+R600_HDMI_AUDIOINFOFRAME_0,
frame[0x0] | (frame[0x1] << 8) | (frame[0x2] << 16) | (frame[0x3] << 24));
WREG32(offset+R600_HDMI_AUDIOINFOFRAME_1,
frame[0x4] | (frame[0x5] << 8) | (frame[0x6] << 16) | (frame[0x8] << 24));
}
/*
* test if audio buffer is filled enough to start playing
*/
static int r600_hdmi_is_audio_buffer_filled(struct drm_encoder *encoder)
{
struct drm_device *dev = encoder->dev;
struct radeon_device *rdev = dev->dev_private;
uint32_t offset = to_radeon_encoder(encoder)->hdmi_offset;
return (RREG32(offset+R600_HDMI_STATUS) & 0x10) != 0;
}
/*
* have buffer status changed since last call?
*/
int r600_hdmi_buffer_status_changed(struct drm_encoder *encoder)
{
struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
int status, result;
if (!radeon_encoder->hdmi_offset)
return 0;
status = r600_hdmi_is_audio_buffer_filled(encoder);
result = radeon_encoder->hdmi_buffer_status != status;
radeon_encoder->hdmi_buffer_status = status;
return result;
}
/*
* write the audio workaround status to the hardware
*/
void r600_hdmi_audio_workaround(struct drm_encoder *encoder)
{
struct drm_device *dev = encoder->dev;
struct radeon_device *rdev = dev->dev_private;
struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
uint32_t offset = radeon_encoder->hdmi_offset;
if (!offset)
return;
if (r600_hdmi_is_audio_buffer_filled(encoder)) {
/* disable audio workaround and start delivering of audio frames */
WREG32_P(offset+R600_HDMI_CNTL, 0x00000001, ~0x00001001);
} else if (radeon_encoder->hdmi_audio_workaround) {
/* enable audio workaround and start delivering of audio frames */
WREG32_P(offset+R600_HDMI_CNTL, 0x00001001, ~0x00001001);
} else {
/* disable audio workaround and stop delivering of audio frames */
WREG32_P(offset+R600_HDMI_CNTL, 0x00000000, ~0x00001001);
}
}
/*
* update the info frames with the data from the current display mode
*/
void r600_hdmi_setmode(struct drm_encoder *encoder, struct drm_display_mode *mode)
{
struct drm_device *dev = encoder->dev;
struct radeon_device *rdev = dev->dev_private;
uint32_t offset = to_radeon_encoder(encoder)->hdmi_offset;
if (!offset)
return;
r600_audio_set_clock(encoder, mode->clock);
WREG32(offset+R600_HDMI_UNKNOWN_0, 0x1000);
WREG32(offset+R600_HDMI_UNKNOWN_1, 0x0);
WREG32(offset+R600_HDMI_UNKNOWN_2, 0x1000);
r600_hdmi_update_ACR(encoder, mode->clock);
WREG32(offset+R600_HDMI_VIDEOCNTL, 0x13);
WREG32(offset+R600_HDMI_VERSION, 0x202);
r600_hdmi_videoinfoframe(encoder, RGB, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
/* it's unknown what these bits do excatly, but it's indeed quite usefull for debugging */
WREG32(offset+R600_HDMI_AUDIO_DEBUG_0, 0x00FFFFFF);
WREG32(offset+R600_HDMI_AUDIO_DEBUG_1, 0x007FFFFF);
WREG32(offset+R600_HDMI_AUDIO_DEBUG_2, 0x00000001);
WREG32(offset+R600_HDMI_AUDIO_DEBUG_3, 0x00000001);
r600_hdmi_audio_workaround(encoder);
/* audio packets per line, does anyone know how to calc this ? */
WREG32_P(offset+R600_HDMI_CNTL, 0x00040000, ~0x001F0000);
/* update? reset? don't realy know */
WREG32_P(offset+R600_HDMI_CNTL, 0x14000000, ~0x14000000);
}
/*
* update settings with current parameters from audio engine
*/
void r600_hdmi_update_audio_settings(struct drm_encoder *encoder,
int channels,
int rate,
int bps,
uint8_t status_bits,
uint8_t category_code)
{
struct drm_device *dev = encoder->dev;
struct radeon_device *rdev = dev->dev_private;
uint32_t offset = to_radeon_encoder(encoder)->hdmi_offset;
uint32_t iec;
if (!offset)
return;
DRM_DEBUG("%s with %d channels, %d Hz sampling rate, %d bits per sample,\n",
r600_hdmi_is_audio_buffer_filled(encoder) ? "playing" : "stopped",
channels, rate, bps);
DRM_DEBUG("0x%02X IEC60958 status bits and 0x%02X category code\n",
(int)status_bits, (int)category_code);
iec = 0;
if (status_bits & AUDIO_STATUS_PROFESSIONAL)
iec |= 1 << 0;
if (status_bits & AUDIO_STATUS_NONAUDIO)
iec |= 1 << 1;
if (status_bits & AUDIO_STATUS_COPYRIGHT)
iec |= 1 << 2;
if (status_bits & AUDIO_STATUS_EMPHASIS)
iec |= 1 << 3;
iec |= category_code << 8;
switch (rate) {
case 32000: iec |= 0x3 << 24; break;
case 44100: iec |= 0x0 << 24; break;
case 88200: iec |= 0x8 << 24; break;
case 176400: iec |= 0xc << 24; break;
case 48000: iec |= 0x2 << 24; break;
case 96000: iec |= 0xa << 24; break;
case 192000: iec |= 0xe << 24; break;
}
WREG32(offset+R600_HDMI_IEC60958_1, iec);
iec = 0;
switch (bps) {
case 16: iec |= 0x2; break;
case 20: iec |= 0x3; break;
case 24: iec |= 0xb; break;
}
if (status_bits & AUDIO_STATUS_V)
iec |= 0x5 << 16;
WREG32_P(offset+R600_HDMI_IEC60958_2, iec, ~0x5000f);
/* 0x021 or 0x031 sets the audio frame length */
WREG32(offset+R600_HDMI_AUDIOCNTL, 0x31);
r600_hdmi_audioinfoframe(encoder, channels-1, 0, 0, 0, 0, 0, 0, 0);
r600_hdmi_audio_workaround(encoder);
/* update? reset? don't realy know */
WREG32_P(offset+R600_HDMI_CNTL, 0x04000000, ~0x04000000);
}
/*
* enable/disable the HDMI engine
*/
void r600_hdmi_enable(struct drm_encoder *encoder, int enable)
{
struct drm_device *dev = encoder->dev;
struct radeon_device *rdev = dev->dev_private;
struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
uint32_t offset = to_radeon_encoder(encoder)->hdmi_offset;
if (!offset)
return;
DRM_DEBUG("%s HDMI interface @ 0x%04X\n", enable ? "Enabling" : "Disabling", offset);
/* some version of atombios ignore the enable HDMI flag
* so enabling/disabling HDMI was moved here for TMDS1+2 */
switch (radeon_encoder->encoder_id) {
case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_TMDS1:
WREG32_P(AVIVO_TMDSA_CNTL, enable ? 0x4 : 0x0, ~0x4);
WREG32(offset+R600_HDMI_ENABLE, enable ? 0x101 : 0x0);
break;
case ENCODER_OBJECT_ID_INTERNAL_LVTM1:
WREG32_P(AVIVO_LVTMA_CNTL, enable ? 0x4 : 0x0, ~0x4);
WREG32(offset+R600_HDMI_ENABLE, enable ? 0x105 : 0x0);
break;
case ENCODER_OBJECT_ID_INTERNAL_UNIPHY:
case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1:
case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2:
case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA:
/* This part is doubtfull in my opinion */
WREG32(offset+R600_HDMI_ENABLE, enable ? 0x110 : 0x0);
break;
default:
DRM_ERROR("unknown HDMI output type\n");
break;
}
}
/*
* determin at which register offset the HDMI encoder is
*/
void r600_hdmi_init(struct drm_encoder *encoder)
{
struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
switch (radeon_encoder->encoder_id) {
case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_TMDS1:
case ENCODER_OBJECT_ID_INTERNAL_UNIPHY:
case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1:
radeon_encoder->hdmi_offset = R600_HDMI_TMDS1;
break;
case ENCODER_OBJECT_ID_INTERNAL_LVTM1:
switch (r600_audio_tmds_index(encoder)) {
case 0:
radeon_encoder->hdmi_offset = R600_HDMI_TMDS1;
break;
case 1:
radeon_encoder->hdmi_offset = R600_HDMI_TMDS2;
break;
default:
radeon_encoder->hdmi_offset = 0;
break;
}
case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2:
radeon_encoder->hdmi_offset = R600_HDMI_TMDS2;
break;
case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA:
radeon_encoder->hdmi_offset = R600_HDMI_DIG;
break;
default:
radeon_encoder->hdmi_offset = 0;
break;
}
DRM_DEBUG("using HDMI engine at offset 0x%04X for encoder 0x%x\n",
radeon_encoder->hdmi_offset, radeon_encoder->encoder_id);
/* TODO: make this configureable */
radeon_encoder->hdmi_audio_workaround = 0;
}

View file

@ -110,5 +110,79 @@
#define R600_BIOS_6_SCRATCH 0x173c #define R600_BIOS_6_SCRATCH 0x173c
#define R600_BIOS_7_SCRATCH 0x1740 #define R600_BIOS_7_SCRATCH 0x1740
/* Audio, these regs were reverse enginered,
* so the chance is high that the naming is wrong
* R6xx+ ??? */
/* Audio clocks */
#define R600_AUDIO_PLL1_MUL 0x0514
#define R600_AUDIO_PLL1_DIV 0x0518
#define R600_AUDIO_PLL2_MUL 0x0524
#define R600_AUDIO_PLL2_DIV 0x0528
#define R600_AUDIO_CLK_SRCSEL 0x0534
/* Audio general */
#define R600_AUDIO_ENABLE 0x7300
#define R600_AUDIO_TIMING 0x7344
/* Audio params */
#define R600_AUDIO_VENDOR_ID 0x7380
#define R600_AUDIO_REVISION_ID 0x7384
#define R600_AUDIO_ROOT_NODE_COUNT 0x7388
#define R600_AUDIO_NID1_NODE_COUNT 0x738c
#define R600_AUDIO_NID1_TYPE 0x7390
#define R600_AUDIO_SUPPORTED_SIZE_RATE 0x7394
#define R600_AUDIO_SUPPORTED_CODEC 0x7398
#define R600_AUDIO_SUPPORTED_POWER_STATES 0x739c
#define R600_AUDIO_NID2_CAPS 0x73a0
#define R600_AUDIO_NID3_CAPS 0x73a4
#define R600_AUDIO_NID3_PIN_CAPS 0x73a8
/* Audio conn list */
#define R600_AUDIO_CONN_LIST_LEN 0x73ac
#define R600_AUDIO_CONN_LIST 0x73b0
/* Audio verbs */
#define R600_AUDIO_RATE_BPS_CHANNEL 0x73c0
#define R600_AUDIO_PLAYING 0x73c4
#define R600_AUDIO_IMPLEMENTATION_ID 0x73c8
#define R600_AUDIO_CONFIG_DEFAULT 0x73cc
#define R600_AUDIO_PIN_SENSE 0x73d0
#define R600_AUDIO_PIN_WIDGET_CNTL 0x73d4
#define R600_AUDIO_STATUS_BITS 0x73d8
/* HDMI base register addresses */
#define R600_HDMI_TMDS1 0x7400
#define R600_HDMI_TMDS2 0x7700
#define R600_HDMI_DIG 0x7800
/* HDMI registers */
#define R600_HDMI_ENABLE 0x00
#define R600_HDMI_STATUS 0x04
#define R600_HDMI_CNTL 0x08
#define R600_HDMI_UNKNOWN_0 0x0C
#define R600_HDMI_AUDIOCNTL 0x10
#define R600_HDMI_VIDEOCNTL 0x14
#define R600_HDMI_VERSION 0x18
#define R600_HDMI_UNKNOWN_1 0x28
#define R600_HDMI_VIDEOINFOFRAME_0 0x54
#define R600_HDMI_VIDEOINFOFRAME_1 0x58
#define R600_HDMI_VIDEOINFOFRAME_2 0x5c
#define R600_HDMI_VIDEOINFOFRAME_3 0x60
#define R600_HDMI_32kHz_CTS 0xac
#define R600_HDMI_32kHz_N 0xb0
#define R600_HDMI_44_1kHz_CTS 0xb4
#define R600_HDMI_44_1kHz_N 0xb8
#define R600_HDMI_48kHz_CTS 0xbc
#define R600_HDMI_48kHz_N 0xc0
#define R600_HDMI_AUDIOINFOFRAME_0 0xcc
#define R600_HDMI_AUDIOINFOFRAME_1 0xd0
#define R600_HDMI_IEC60958_1 0xd4
#define R600_HDMI_IEC60958_2 0xd8
#define R600_HDMI_UNKNOWN_2 0xdc
#define R600_HDMI_AUDIO_DEBUG_0 0xe0
#define R600_HDMI_AUDIO_DEBUG_1 0xe4
#define R600_HDMI_AUDIO_DEBUG_2 0xe8
#define R600_HDMI_AUDIO_DEBUG_3 0xec
#endif #endif

View file

@ -89,6 +89,7 @@ extern int radeon_testing;
extern int radeon_connector_table; extern int radeon_connector_table;
extern int radeon_tv; extern int radeon_tv;
extern int radeon_new_pll; extern int radeon_new_pll;
extern int radeon_audio;
/* /*
* Copy from radeon_drv.h so we don't have to include both and have conflicting * Copy from radeon_drv.h so we don't have to include both and have conflicting
@ -814,6 +815,14 @@ struct radeon_device {
struct r600_ih ih; /* r6/700 interrupt ring */ struct r600_ih ih; /* r6/700 interrupt ring */
struct workqueue_struct *wq; struct workqueue_struct *wq;
struct work_struct hotplug_work; struct work_struct hotplug_work;
/* audio stuff */
struct timer_list audio_timer;
int audio_channels;
int audio_rate;
int audio_bits_per_sample;
uint8_t audio_status_bits;
uint8_t audio_category_code;
}; };
int radeon_device_init(struct radeon_device *rdev, int radeon_device_init(struct radeon_device *rdev,
@ -1016,6 +1025,7 @@ extern int radeon_cs_parser_init(struct radeon_cs_parser *p, void *data);
extern void radeon_legacy_set_clock_gating(struct radeon_device *rdev, int enable); extern void radeon_legacy_set_clock_gating(struct radeon_device *rdev, int enable);
extern void radeon_atom_set_clock_gating(struct radeon_device *rdev, int enable); extern void radeon_atom_set_clock_gating(struct radeon_device *rdev, int enable);
extern void radeon_ttm_placement_from_domain(struct radeon_bo *rbo, u32 domain); extern void radeon_ttm_placement_from_domain(struct radeon_bo *rbo, u32 domain);
extern bool radeon_ttm_bo_is_radeon_bo(struct ttm_buffer_object *bo);
/* r100,rv100,rs100,rv200,rs200,r200,rv250,rs300,rv280 */ /* r100,rv100,rs100,rv200,rs200,r200,rv250,rs300,rv280 */
struct r100_mc_save { struct r100_mc_save {
@ -1146,6 +1156,21 @@ extern void r600_irq_fini(struct radeon_device *rdev);
extern void r600_ih_ring_init(struct radeon_device *rdev, unsigned ring_size); extern void r600_ih_ring_init(struct radeon_device *rdev, unsigned ring_size);
extern int r600_irq_set(struct radeon_device *rdev); extern int r600_irq_set(struct radeon_device *rdev);
extern int r600_audio_init(struct radeon_device *rdev);
extern int r600_audio_tmds_index(struct drm_encoder *encoder);
extern void r600_audio_set_clock(struct drm_encoder *encoder, int clock);
extern void r600_audio_fini(struct radeon_device *rdev);
extern void r600_hdmi_init(struct drm_encoder *encoder);
extern void r600_hdmi_enable(struct drm_encoder *encoder, int enable);
extern void r600_hdmi_setmode(struct drm_encoder *encoder, struct drm_display_mode *mode);
extern int r600_hdmi_buffer_status_changed(struct drm_encoder *encoder);
extern void r600_hdmi_update_audio_settings(struct drm_encoder *encoder,
int channels,
int rate,
int bps,
uint8_t status_bits,
uint8_t category_code);
#include "radeon_object.h" #include "radeon_object.h"
#endif #endif

View file

@ -87,6 +87,7 @@ int radeon_testing = 0;
int radeon_connector_table = 0; int radeon_connector_table = 0;
int radeon_tv = 1; int radeon_tv = 1;
int radeon_new_pll = 1; int radeon_new_pll = 1;
int radeon_audio = 1;
MODULE_PARM_DESC(no_wb, "Disable AGP writeback for scratch registers"); MODULE_PARM_DESC(no_wb, "Disable AGP writeback for scratch registers");
module_param_named(no_wb, radeon_no_wb, int, 0444); module_param_named(no_wb, radeon_no_wb, int, 0444);
@ -124,6 +125,9 @@ module_param_named(tv, radeon_tv, int, 0444);
MODULE_PARM_DESC(new_pll, "Select new PLL code for AVIVO chips"); MODULE_PARM_DESC(new_pll, "Select new PLL code for AVIVO chips");
module_param_named(new_pll, radeon_new_pll, int, 0444); module_param_named(new_pll, radeon_new_pll, int, 0444);
MODULE_PARM_DESC(audio, "Audio enable (0 = disable)");
module_param_named(audio, radeon_audio, int, 0444);
static int radeon_suspend(struct drm_device *dev, pm_message_t state) static int radeon_suspend(struct drm_device *dev, pm_message_t state)
{ {
drm_radeon_private_t *dev_priv = dev->dev_private; drm_radeon_private_t *dev_priv = dev->dev_private;

View file

@ -438,6 +438,7 @@ atombios_digital_setup(struct drm_encoder *encoder, int action)
struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
union lvds_encoder_control args; union lvds_encoder_control args;
int index = 0; int index = 0;
int hdmi_detected = 0;
uint8_t frev, crev; uint8_t frev, crev;
struct radeon_encoder_atom_dig *dig; struct radeon_encoder_atom_dig *dig;
struct drm_connector *connector; struct drm_connector *connector;
@ -458,6 +459,9 @@ atombios_digital_setup(struct drm_encoder *encoder, int action)
if (!radeon_connector->con_priv) if (!radeon_connector->con_priv)
return; return;
if (drm_detect_hdmi_monitor(radeon_connector->edid))
hdmi_detected = 1;
dig_connector = radeon_connector->con_priv; dig_connector = radeon_connector->con_priv;
memset(&args, 0, sizeof(args)); memset(&args, 0, sizeof(args));
@ -487,7 +491,7 @@ atombios_digital_setup(struct drm_encoder *encoder, int action)
case 1: case 1:
args.v1.ucMisc = 0; args.v1.ucMisc = 0;
args.v1.ucAction = action; args.v1.ucAction = action;
if (drm_detect_hdmi_monitor(radeon_connector->edid)) if (hdmi_detected)
args.v1.ucMisc |= PANEL_ENCODER_MISC_HDMI_TYPE; args.v1.ucMisc |= PANEL_ENCODER_MISC_HDMI_TYPE;
args.v1.usPixelClock = cpu_to_le16(radeon_encoder->pixel_clock / 10); args.v1.usPixelClock = cpu_to_le16(radeon_encoder->pixel_clock / 10);
if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) { if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) {
@ -512,7 +516,7 @@ atombios_digital_setup(struct drm_encoder *encoder, int action)
if (dig->coherent_mode) if (dig->coherent_mode)
args.v2.ucMisc |= PANEL_ENCODER_MISC_COHERENT; args.v2.ucMisc |= PANEL_ENCODER_MISC_COHERENT;
} }
if (drm_detect_hdmi_monitor(radeon_connector->edid)) if (hdmi_detected)
args.v2.ucMisc |= PANEL_ENCODER_MISC_HDMI_TYPE; args.v2.ucMisc |= PANEL_ENCODER_MISC_HDMI_TYPE;
args.v2.usPixelClock = cpu_to_le16(radeon_encoder->pixel_clock / 10); args.v2.usPixelClock = cpu_to_le16(radeon_encoder->pixel_clock / 10);
args.v2.ucTruncate = 0; args.v2.ucTruncate = 0;
@ -552,7 +556,7 @@ atombios_digital_setup(struct drm_encoder *encoder, int action)
} }
atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
r600_hdmi_enable(encoder, hdmi_detected);
} }
int int
@ -893,7 +897,6 @@ atombios_dig_transmitter_setup(struct drm_encoder *encoder, int action, uint8_t
} }
atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
} }
static void static void
@ -1162,7 +1165,6 @@ atombios_set_encoder_crtc_source(struct drm_encoder *encoder)
} }
atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
} }
static void static void
@ -1265,6 +1267,8 @@ radeon_atom_encoder_mode_set(struct drm_encoder *encoder,
break; break;
} }
atombios_apply_encoder_quirks(encoder, adjusted_mode); atombios_apply_encoder_quirks(encoder, adjusted_mode);
r600_hdmi_setmode(encoder, adjusted_mode);
} }
static bool static bool
@ -1510,4 +1514,6 @@ radeon_add_atom_encoder(struct drm_device *dev, uint32_t encoder_id, uint32_t su
drm_encoder_helper_add(encoder, &radeon_atom_dig_helper_funcs); drm_encoder_helper_add(encoder, &radeon_atom_dig_helper_funcs);
break; break;
} }
r600_hdmi_init(encoder);
} }

View file

@ -66,8 +66,9 @@ int radeon_gem_object_create(struct radeon_device *rdev, int size,
} }
r = radeon_bo_create(rdev, gobj, size, kernel, initial_domain, &robj); r = radeon_bo_create(rdev, gobj, size, kernel, initial_domain, &robj);
if (r) { if (r) {
DRM_ERROR("Failed to allocate GEM object (%d, %d, %u)\n", if (r != -ERESTARTSYS)
size, initial_domain, alignment); DRM_ERROR("Failed to allocate GEM object (%d, %d, %u, %d)\n",
size, initial_domain, alignment, r);
mutex_lock(&rdev->ddev->struct_mutex); mutex_lock(&rdev->ddev->struct_mutex);
drm_gem_object_unreference(gobj); drm_gem_object_unreference(gobj);
mutex_unlock(&rdev->ddev->struct_mutex); mutex_unlock(&rdev->ddev->struct_mutex);
@ -350,9 +351,10 @@ int radeon_gem_get_tiling_ioctl(struct drm_device *dev, void *data,
rbo = gobj->driver_private; rbo = gobj->driver_private;
r = radeon_bo_reserve(rbo, false); r = radeon_bo_reserve(rbo, false);
if (unlikely(r != 0)) if (unlikely(r != 0))
return r; goto out;
radeon_bo_get_tiling_flags(rbo, &args->tiling_flags, &args->pitch); radeon_bo_get_tiling_flags(rbo, &args->tiling_flags, &args->pitch);
radeon_bo_unreserve(rbo); radeon_bo_unreserve(rbo);
out:
mutex_lock(&dev->struct_mutex); mutex_lock(&dev->struct_mutex);
drm_gem_object_unreference(gobj); drm_gem_object_unreference(gobj);
mutex_unlock(&dev->struct_mutex); mutex_unlock(&dev->struct_mutex);

View file

@ -334,6 +334,9 @@ struct radeon_encoder {
enum radeon_rmx_type rmx_type; enum radeon_rmx_type rmx_type;
struct drm_display_mode native_mode; struct drm_display_mode native_mode;
void *enc_priv; void *enc_priv;
int hdmi_offset;
int hdmi_audio_workaround;
int hdmi_buffer_status;
}; };
struct radeon_connector_atom_dig { struct radeon_connector_atom_dig {

View file

@ -56,6 +56,13 @@ static void radeon_ttm_bo_destroy(struct ttm_buffer_object *tbo)
kfree(bo); kfree(bo);
} }
bool radeon_ttm_bo_is_radeon_bo(struct ttm_buffer_object *bo)
{
if (bo->destroy == &radeon_ttm_bo_destroy)
return true;
return false;
}
void radeon_ttm_placement_from_domain(struct radeon_bo *rbo, u32 domain) void radeon_ttm_placement_from_domain(struct radeon_bo *rbo, u32 domain)
{ {
u32 c = 0; u32 c = 0;
@ -71,6 +78,8 @@ void radeon_ttm_placement_from_domain(struct radeon_bo *rbo, u32 domain)
rbo->placements[c++] = TTM_PL_MASK_CACHING | TTM_PL_FLAG_TT; rbo->placements[c++] = TTM_PL_MASK_CACHING | TTM_PL_FLAG_TT;
if (domain & RADEON_GEM_DOMAIN_CPU) if (domain & RADEON_GEM_DOMAIN_CPU)
rbo->placements[c++] = TTM_PL_MASK_CACHING | TTM_PL_FLAG_SYSTEM; rbo->placements[c++] = TTM_PL_MASK_CACHING | TTM_PL_FLAG_SYSTEM;
if (!c)
rbo->placements[c++] = TTM_PL_MASK_CACHING | TTM_PL_FLAG_SYSTEM;
rbo->placement.num_placement = c; rbo->placement.num_placement = c;
rbo->placement.num_busy_placement = c; rbo->placement.num_busy_placement = c;
} }
@ -481,14 +490,20 @@ int radeon_bo_check_tiling(struct radeon_bo *bo, bool has_moved,
} }
void radeon_bo_move_notify(struct ttm_buffer_object *bo, void radeon_bo_move_notify(struct ttm_buffer_object *bo,
struct ttm_mem_reg *mem) struct ttm_mem_reg *mem)
{ {
struct radeon_bo *rbo = container_of(bo, struct radeon_bo, tbo); struct radeon_bo *rbo;
if (!radeon_ttm_bo_is_radeon_bo(bo))
return;
rbo = container_of(bo, struct radeon_bo, tbo);
radeon_bo_check_tiling(rbo, 0, 1); radeon_bo_check_tiling(rbo, 0, 1);
} }
void radeon_bo_fault_reserve_notify(struct ttm_buffer_object *bo) void radeon_bo_fault_reserve_notify(struct ttm_buffer_object *bo)
{ {
struct radeon_bo *rbo = container_of(bo, struct radeon_bo, tbo); struct radeon_bo *rbo;
if (!radeon_ttm_bo_is_radeon_bo(bo))
return;
rbo = container_of(bo, struct radeon_bo, tbo);
radeon_bo_check_tiling(rbo, 0, 0); radeon_bo_check_tiling(rbo, 0, 0);
} }

View file

@ -59,19 +59,17 @@ static inline unsigned radeon_mem_type_to_domain(u32 mem_type)
* *
* Returns: * Returns:
* -EBUSY: buffer is busy and @no_wait is true * -EBUSY: buffer is busy and @no_wait is true
* -ERESTART: A wait for the buffer to become unreserved was interrupted by * -ERESTARTSYS: A wait for the buffer to become unreserved was interrupted by
* a signal. Release all buffer reservations and return to user-space. * a signal. Release all buffer reservations and return to user-space.
*/ */
static inline int radeon_bo_reserve(struct radeon_bo *bo, bool no_wait) static inline int radeon_bo_reserve(struct radeon_bo *bo, bool no_wait)
{ {
int r; int r;
retry:
r = ttm_bo_reserve(&bo->tbo, true, no_wait, false, 0); r = ttm_bo_reserve(&bo->tbo, true, no_wait, false, 0);
if (unlikely(r != 0)) { if (unlikely(r != 0)) {
if (r == -ERESTART) if (r != -ERESTARTSYS)
goto retry; dev_err(bo->rdev->dev, "%p reserve failed\n", bo);
dev_err(bo->rdev->dev, "%p reserve failed\n", bo);
return r; return r;
} }
return 0; return 0;
@ -125,12 +123,10 @@ static inline int radeon_bo_wait(struct radeon_bo *bo, u32 *mem_type,
{ {
int r; int r;
retry:
r = ttm_bo_reserve(&bo->tbo, true, no_wait, false, 0); r = ttm_bo_reserve(&bo->tbo, true, no_wait, false, 0);
if (unlikely(r != 0)) { if (unlikely(r != 0)) {
if (r == -ERESTART) if (r != -ERESTARTSYS)
goto retry; dev_err(bo->rdev->dev, "%p reserve failed for wait\n", bo);
dev_err(bo->rdev->dev, "%p reserve failed for wait\n", bo);
return r; return r;
} }
spin_lock(&bo->tbo.lock); spin_lock(&bo->tbo.lock);
@ -140,8 +136,6 @@ retry:
r = ttm_bo_wait(&bo->tbo, true, true, no_wait); r = ttm_bo_wait(&bo->tbo, true, true, no_wait);
spin_unlock(&bo->tbo.lock); spin_unlock(&bo->tbo.lock);
ttm_bo_unreserve(&bo->tbo); ttm_bo_unreserve(&bo->tbo);
if (unlikely(r == -ERESTART))
goto retry;
return r; return r;
} }

View file

@ -44,8 +44,11 @@ static int radeon_debugfs_pm_info(struct seq_file *m, void *data)
struct drm_device *dev = node->minor->dev; struct drm_device *dev = node->minor->dev;
struct radeon_device *rdev = dev->dev_private; struct radeon_device *rdev = dev->dev_private;
seq_printf(m, "engine clock: %u0 kHz\n", radeon_get_engine_clock(rdev)); seq_printf(m, "default engine clock: %u0 kHz\n", rdev->clock.default_sclk);
seq_printf(m, "memory clock: %u0 kHz\n", radeon_get_memory_clock(rdev)); seq_printf(m, "current engine clock: %u0 kHz\n", radeon_get_engine_clock(rdev));
seq_printf(m, "default memory clock: %u0 kHz\n", rdev->clock.default_mclk);
if (rdev->asic->get_memory_clock)
seq_printf(m, "current memory clock: %u0 kHz\n", radeon_get_memory_clock(rdev));
return 0; return 0;
} }

View file

@ -200,7 +200,19 @@ static int radeon_init_mem_type(struct ttm_bo_device *bdev, uint32_t type,
static void radeon_evict_flags(struct ttm_buffer_object *bo, static void radeon_evict_flags(struct ttm_buffer_object *bo,
struct ttm_placement *placement) struct ttm_placement *placement)
{ {
struct radeon_bo *rbo = container_of(bo, struct radeon_bo, tbo); struct radeon_bo *rbo;
static u32 placements = TTM_PL_MASK_CACHING | TTM_PL_FLAG_SYSTEM;
if (!radeon_ttm_bo_is_radeon_bo(bo)) {
placement->fpfn = 0;
placement->lpfn = 0;
placement->placement = &placements;
placement->busy_placement = &placements;
placement->num_placement = 1;
placement->num_busy_placement = 1;
return;
}
rbo = container_of(bo, struct radeon_bo, tbo);
switch (bo->mem.mem_type) { switch (bo->mem.mem_type) {
case TTM_PL_VRAM: case TTM_PL_VRAM:
radeon_ttm_placement_from_domain(rbo, RADEON_GEM_DOMAIN_GTT); radeon_ttm_placement_from_domain(rbo, RADEON_GEM_DOMAIN_GTT);

View file

@ -497,6 +497,8 @@ int rs400_init(struct radeon_device *rdev)
/* Initialize clocks */ /* Initialize clocks */
radeon_get_clock_info(rdev->ddev); radeon_get_clock_info(rdev->ddev);
/* Initialize power management */
radeon_pm_init(rdev);
/* Get vram informations */ /* Get vram informations */
rs400_vram_info(rdev); rs400_vram_info(rdev);
/* Initialize memory controller (also test AGP) */ /* Initialize memory controller (also test AGP) */

View file

@ -892,6 +892,14 @@ static int rv770_startup(struct radeon_device *rdev)
} }
rv770_gpu_init(rdev); rv770_gpu_init(rdev);
if (!rdev->r600_blit.shader_obj) {
r = r600_blit_init(rdev);
if (r) {
DRM_ERROR("radeon: failed blitter (%d).\n", r);
return r;
}
}
r = radeon_bo_reserve(rdev->r600_blit.shader_obj, false); r = radeon_bo_reserve(rdev->r600_blit.shader_obj, false);
if (unlikely(r != 0)) if (unlikely(r != 0))
return r; return r;
@ -1051,12 +1059,6 @@ int rv770_init(struct radeon_device *rdev)
if (r) if (r)
return r; return r;
r = r600_blit_init(rdev);
if (r) {
DRM_ERROR("radeon: failed blitter (%d).\n", r);
return r;
}
rdev->accel_working = true; rdev->accel_working = true;
r = rv770_startup(rdev); r = rv770_startup(rdev);
if (r) { if (r) {

View file

@ -71,34 +71,34 @@ static inline int ttm_mem_type_from_flags(uint32_t flags, uint32_t *mem_type)
return -EINVAL; return -EINVAL;
} }
static void ttm_mem_type_manager_debug(struct ttm_bo_global *glob, static void ttm_mem_type_debug(struct ttm_bo_device *bdev, int mem_type)
struct ttm_mem_type_manager *man)
{ {
struct ttm_mem_type_manager *man = &bdev->man[mem_type];
printk(KERN_ERR TTM_PFX " has_type: %d\n", man->has_type); printk(KERN_ERR TTM_PFX " has_type: %d\n", man->has_type);
printk(KERN_ERR TTM_PFX " use_type: %d\n", man->use_type); printk(KERN_ERR TTM_PFX " use_type: %d\n", man->use_type);
printk(KERN_ERR TTM_PFX " flags: 0x%08X\n", man->flags); printk(KERN_ERR TTM_PFX " flags: 0x%08X\n", man->flags);
printk(KERN_ERR TTM_PFX " gpu_offset: 0x%08lX\n", man->gpu_offset); printk(KERN_ERR TTM_PFX " gpu_offset: 0x%08lX\n", man->gpu_offset);
printk(KERN_ERR TTM_PFX " io_offset: 0x%08lX\n", man->io_offset); printk(KERN_ERR TTM_PFX " io_offset: 0x%08lX\n", man->io_offset);
printk(KERN_ERR TTM_PFX " io_size: %ld\n", man->io_size); printk(KERN_ERR TTM_PFX " io_size: %ld\n", man->io_size);
printk(KERN_ERR TTM_PFX " size: %ld\n", (unsigned long)man->size); printk(KERN_ERR TTM_PFX " size: %llu\n", man->size);
printk(KERN_ERR TTM_PFX " available_caching: 0x%08X\n", printk(KERN_ERR TTM_PFX " available_caching: 0x%08X\n",
man->available_caching); man->available_caching);
printk(KERN_ERR TTM_PFX " default_caching: 0x%08X\n", printk(KERN_ERR TTM_PFX " default_caching: 0x%08X\n",
man->default_caching); man->default_caching);
spin_lock(&glob->lru_lock); if (mem_type != TTM_PL_SYSTEM) {
drm_mm_debug_table(&man->manager, TTM_PFX); spin_lock(&bdev->glob->lru_lock);
spin_unlock(&glob->lru_lock); drm_mm_debug_table(&man->manager, TTM_PFX);
spin_unlock(&bdev->glob->lru_lock);
}
} }
static void ttm_bo_mem_space_debug(struct ttm_buffer_object *bo, static void ttm_bo_mem_space_debug(struct ttm_buffer_object *bo,
struct ttm_placement *placement) struct ttm_placement *placement)
{ {
struct ttm_bo_device *bdev = bo->bdev;
struct ttm_bo_global *glob = bo->glob;
struct ttm_mem_type_manager *man;
int i, ret, mem_type; int i, ret, mem_type;
printk(KERN_ERR TTM_PFX "No space for %p (%ld pages, %ldK, %ldM)\n", printk(KERN_ERR TTM_PFX "No space for %p (%lu pages, %luK, %luM)\n",
bo, bo->mem.num_pages, bo->mem.size >> 10, bo, bo->mem.num_pages, bo->mem.size >> 10,
bo->mem.size >> 20); bo->mem.size >> 20);
for (i = 0; i < placement->num_placement; i++) { for (i = 0; i < placement->num_placement; i++) {
@ -106,10 +106,9 @@ static void ttm_bo_mem_space_debug(struct ttm_buffer_object *bo,
&mem_type); &mem_type);
if (ret) if (ret)
return; return;
man = &bdev->man[mem_type];
printk(KERN_ERR TTM_PFX " placement[%d]=0x%08X (%d)\n", printk(KERN_ERR TTM_PFX " placement[%d]=0x%08X (%d)\n",
i, placement->placement[i], mem_type); i, placement->placement[i], mem_type);
ttm_mem_type_manager_debug(glob, man); ttm_mem_type_debug(bo->bdev, mem_type);
} }
} }
@ -465,6 +464,8 @@ static int ttm_bo_cleanup_refs(struct ttm_buffer_object *bo, bool remove_all)
spin_unlock(&bo->lock); spin_unlock(&bo->lock);
spin_lock(&glob->lru_lock); spin_lock(&glob->lru_lock);
put_count = ttm_bo_del_from_lru(bo);
ret = ttm_bo_reserve_locked(bo, false, false, false, 0); ret = ttm_bo_reserve_locked(bo, false, false, false, 0);
BUG_ON(ret); BUG_ON(ret);
if (bo->ttm) if (bo->ttm)
@ -472,20 +473,19 @@ static int ttm_bo_cleanup_refs(struct ttm_buffer_object *bo, bool remove_all)
if (!list_empty(&bo->ddestroy)) { if (!list_empty(&bo->ddestroy)) {
list_del_init(&bo->ddestroy); list_del_init(&bo->ddestroy);
kref_put(&bo->list_kref, ttm_bo_ref_bug); ++put_count;
} }
if (bo->mem.mm_node) { if (bo->mem.mm_node) {
bo->mem.mm_node->private = NULL; bo->mem.mm_node->private = NULL;
drm_mm_put_block(bo->mem.mm_node); drm_mm_put_block(bo->mem.mm_node);
bo->mem.mm_node = NULL; bo->mem.mm_node = NULL;
} }
put_count = ttm_bo_del_from_lru(bo);
spin_unlock(&glob->lru_lock); spin_unlock(&glob->lru_lock);
atomic_set(&bo->reserved, 0); atomic_set(&bo->reserved, 0);
while (put_count--) while (put_count--)
kref_put(&bo->list_kref, ttm_bo_release_list); kref_put(&bo->list_kref, ttm_bo_ref_bug);
return 0; return 0;
} }
@ -684,19 +684,45 @@ static int ttm_mem_evict_first(struct ttm_bo_device *bdev,
struct ttm_buffer_object *bo; struct ttm_buffer_object *bo;
int ret, put_count = 0; int ret, put_count = 0;
retry:
spin_lock(&glob->lru_lock); spin_lock(&glob->lru_lock);
if (list_empty(&man->lru)) {
spin_unlock(&glob->lru_lock);
return -EBUSY;
}
bo = list_first_entry(&man->lru, struct ttm_buffer_object, lru); bo = list_first_entry(&man->lru, struct ttm_buffer_object, lru);
kref_get(&bo->list_kref); kref_get(&bo->list_kref);
ret = ttm_bo_reserve_locked(bo, interruptible, no_wait, false, 0);
if (likely(ret == 0)) ret = ttm_bo_reserve_locked(bo, false, true, false, 0);
put_count = ttm_bo_del_from_lru(bo);
if (unlikely(ret == -EBUSY)) {
spin_unlock(&glob->lru_lock);
if (likely(!no_wait))
ret = ttm_bo_wait_unreserved(bo, interruptible);
kref_put(&bo->list_kref, ttm_bo_release_list);
/**
* We *need* to retry after releasing the lru lock.
*/
if (unlikely(ret != 0))
return ret;
goto retry;
}
put_count = ttm_bo_del_from_lru(bo);
spin_unlock(&glob->lru_lock); spin_unlock(&glob->lru_lock);
if (unlikely(ret != 0))
return ret; BUG_ON(ret != 0);
while (put_count--) while (put_count--)
kref_put(&bo->list_kref, ttm_bo_ref_bug); kref_put(&bo->list_kref, ttm_bo_ref_bug);
ret = ttm_bo_evict(bo, interruptible, no_wait); ret = ttm_bo_evict(bo, interruptible, no_wait);
ttm_bo_unreserve(bo); ttm_bo_unreserve(bo);
kref_put(&bo->list_kref, ttm_bo_release_list); kref_put(&bo->list_kref, ttm_bo_release_list);
return ret; return ret;
} }
@ -849,7 +875,7 @@ int ttm_bo_mem_space(struct ttm_buffer_object *bo,
int i, ret; int i, ret;
mem->mm_node = NULL; mem->mm_node = NULL;
for (i = 0; i <= placement->num_placement; ++i) { for (i = 0; i < placement->num_placement; ++i) {
ret = ttm_mem_type_from_flags(placement->placement[i], ret = ttm_mem_type_from_flags(placement->placement[i],
&mem_type); &mem_type);
if (ret) if (ret)
@ -900,8 +926,8 @@ int ttm_bo_mem_space(struct ttm_buffer_object *bo,
if (!type_found) if (!type_found)
return -EINVAL; return -EINVAL;
for (i = 0; i <= placement->num_busy_placement; ++i) { for (i = 0; i < placement->num_busy_placement; ++i) {
ret = ttm_mem_type_from_flags(placement->placement[i], ret = ttm_mem_type_from_flags(placement->busy_placement[i],
&mem_type); &mem_type);
if (ret) if (ret)
return ret; return ret;
@ -911,7 +937,7 @@ int ttm_bo_mem_space(struct ttm_buffer_object *bo,
if (!ttm_bo_mt_compatible(man, if (!ttm_bo_mt_compatible(man,
bo->type == ttm_bo_type_user, bo->type == ttm_bo_type_user,
mem_type, mem_type,
placement->placement[i], placement->busy_placement[i],
&cur_flags)) &cur_flags))
continue; continue;
@ -921,7 +947,7 @@ int ttm_bo_mem_space(struct ttm_buffer_object *bo,
* Use the access and other non-mapping-related flag bits from * Use the access and other non-mapping-related flag bits from
* the memory placement flags to the current flags * the memory placement flags to the current flags
*/ */
ttm_flag_masked(&cur_flags, placement->placement[i], ttm_flag_masked(&cur_flags, placement->busy_placement[i],
~TTM_PL_MASK_MEMTYPE); ~TTM_PL_MASK_MEMTYPE);
ret = ttm_bo_mem_force_space(bo, mem_type, placement, mem, ret = ttm_bo_mem_force_space(bo, mem_type, placement, mem,
@ -1115,6 +1141,7 @@ int ttm_bo_init(struct ttm_bo_device *bdev,
bo->glob = bdev->glob; bo->glob = bdev->glob;
bo->type = type; bo->type = type;
bo->num_pages = num_pages; bo->num_pages = num_pages;
bo->mem.size = num_pages << PAGE_SHIFT;
bo->mem.mem_type = TTM_PL_SYSTEM; bo->mem.mem_type = TTM_PL_SYSTEM;
bo->mem.num_pages = bo->num_pages; bo->mem.num_pages = bo->num_pages;
bo->mem.mm_node = NULL; bo->mem.mm_node = NULL;

View file

@ -320,7 +320,7 @@ ssize_t ttm_bo_io(struct ttm_bo_device *bdev, struct file *filp,
return -EFAULT; return -EFAULT;
driver = bo->bdev->driver; driver = bo->bdev->driver;
if (unlikely(driver->verify_access)) { if (unlikely(!driver->verify_access)) {
ret = -EPERM; ret = -EPERM;
goto out_unref; goto out_unref;
} }