>From 88ca304ef749e66961e11ee1e258ea1e001e471f Mon Sep 17 00:00:00 2001
From: Christian Koenig <deathsimple@vodafone.de>
Date: Sat, 10 Apr 2010 03:13:16 +0200
Subject: [PATCH 2/2] drm/radeon/kms: HDMI irq support
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Implements irq support for HDMI audio output. Now the polling timer
is only enabled if irq support isn't available.
Signed-off-by: Christian König <deathsimple@vodafone.de>
---
drivers/gpu/drm/radeon/r600.c | 6 ++++
drivers/gpu/drm/radeon/r600_audio.c | 20 +++++++++----
drivers/gpu/drm/radeon/r600_hdmi.c | 56 ++++++++++++++++++++++++----------
drivers/gpu/drm/radeon/radeon.h | 2 +
4 files changed, 61 insertions(+), 23 deletions(-)
@@ -2713,6 +2713,8 @@ static inline u32 r600_get_ih_wptr(struct radeon_device *rdev)
* 19 1 FP Hot plug detection B
* 19 2 DAC A auto-detection
* 19 3 DAC B auto-detection
+ * 21 4 HDMI block A
+ * 21 5 HDMI block B
* 176 - CP_INT RB
* 177 - CP_INT IB1
* 178 - CP_INT IB2
@@ -2852,6 +2854,10 @@ restart_ih:
break;
}
break;
+ case 21: /* HDMI */
+ DRM_DEBUG("IH: HDMI: 0x%x\n", src_data);
+ r600_audio_schedule_polling(rdev);
+ break;
case 176: /* CP_INT in ring buffer */
case 177: /* CP_INT in IB1 */
case 178: /* CP_INT in IB2 */
@@ -104,6 +104,15 @@ uint8_t r600_audio_category_code(struct radeon_device *rdev)
}
/*
+ * schedule next audio update event
+ */
+void r600_audio_schedule_polling(struct radeon_device *rdev)
+{
+ mod_timer(&rdev->audio_timer,
+ jiffies + msecs_to_jiffies(AUDIO_TIMER_INTERVALL));
+}
+
+/*
* update all hdmi interfaces with current audio parameters
*/
static void r600_audio_update_hdmi(unsigned long param)
@@ -136,16 +145,15 @@ static void r600_audio_update_hdmi(unsigned long param)
list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
- if (radeon_encoder->audio_polling_active) {
- still_going = 1;
- if (changes || r600_hdmi_buffer_status_changed(encoder))
+ int irq_pending = r600_hdmi_irq_pending(encoder);
+ if (irq_pending || radeon_encoder->audio_polling_active) {
+ still_going |= radeon_encoder->audio_polling_active;
+ if (irq_pending || changes || r600_hdmi_buffer_status_changed(encoder))
r600_hdmi_update_audio_settings(encoder);
}
}
- if(still_going)
- mod_timer(&rdev->audio_timer,
- jiffies + msecs_to_jiffies(AUDIO_TIMER_INTERVALL));
+ if(still_going) r600_audio_schedule_polling(rdev);
}
/*
@@ -278,6 +278,21 @@ int r600_hdmi_buffer_status_changed(struct drm_encoder *encoder)
}
/*
+ * is there still an irq pending?
+ */
+int r600_hdmi_irq_pending(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);
+
+ if (!radeon_encoder->hdmi_offset)
+ return 0;
+
+ return (RREG32(radeon_encoder->hdmi_offset + R600_HDMI_STATUS) & 0x20000000) != 0;
+}
+
+/*
* write the audio workaround status to the hardware
*/
void r600_hdmi_audio_workaround(struct drm_encoder *encoder)
@@ -290,17 +305,15 @@ void r600_hdmi_audio_workaround(struct drm_encoder *encoder)
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);
+ if (!radeon_encoder->hdmi_audio_workaround ||
+ r600_hdmi_is_audio_buffer_filled(encoder)) {
- } else if (radeon_encoder->hdmi_audio_workaround) {
- /* enable audio workaround and start delivering of audio frames */
- WREG32_P(offset+R600_HDMI_CNTL, 0x00001001, ~0x00001001);
+ /* disable audio workaround */
+ WREG32_P(offset+R600_HDMI_CNTL, 0x00000001, ~0x00001001);
} else {
- /* disable audio workaround and stop delivering of audio frames */
- WREG32_P(offset+R600_HDMI_CNTL, 0x00000000, ~0x00001001);
+ /* enable audio workaround */
+ WREG32_P(offset+R600_HDMI_CNTL, 0x00001001, ~0x00001001);
}
}
@@ -342,9 +355,6 @@ void r600_hdmi_setmode(struct drm_encoder *encoder, struct drm_display_mode *mod
/* 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);
}
/*
@@ -367,6 +377,9 @@ void r600_hdmi_update_audio_settings(struct drm_encoder *encoder)
if (!offset)
return;
+ /* first reset any pending irq */
+ WREG32_P(offset + R600_HDMI_CNTL, 0x20000000, ~0x20000000);
+
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);
@@ -413,9 +426,6 @@ void r600_hdmi_update_audio_settings(struct drm_encoder *encoder)
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);
}
static int r600_hdmi_find_free_block(struct drm_device *dev)
@@ -513,7 +523,15 @@ void r600_hdmi_enable(struct drm_encoder *encoder)
}
}
- r600_audio_enable_polling(encoder);
+ if (rdev->ih.enabled) {
+ /* if irq is available use it */
+ WREG32_P(radeon_encoder->hdmi_offset + R600_HDMI_CNTL, 0x10000000, ~0x10000000);
+ r600_audio_disable_polling(encoder);
+ } else {
+ /* if not fallback to polling */
+ WREG32_P(radeon_encoder->hdmi_offset + R600_HDMI_CNTL, 0x0, ~0x10000000);
+ r600_audio_enable_polling(encoder);
+ }
DRM_DEBUG("Enabling HDMI interface @ 0x%04X for encoder 0x%x\n",
radeon_encoder->hdmi_offset, radeon_encoder->encoder_id);
@@ -533,11 +551,15 @@ void r600_hdmi_disable(struct drm_encoder *encoder)
return;
}
- r600_audio_disable_polling(encoder);
-
DRM_DEBUG("Disabling HDMI interface @ 0x%04X for encoder 0x%x\n",
radeon_encoder->hdmi_offset, radeon_encoder->encoder_id);
+ /* disable irq */
+ WREG32_P(radeon_encoder->hdmi_offset + R600_HDMI_CNTL, 0x0, ~0x10000000);
+
+ /* disable polling */
+ r600_audio_disable_polling(encoder);
+
if (ASIC_IS_DCE32(rdev) && !ASIC_IS_DCE4(rdev)) {
WREG32_P(radeon_encoder->hdmi_config_offset + 0x4, 0, ~0x1);
} else if (rdev->family >= CHIP_R600 && !ASIC_IS_DCE3(rdev)) {
@@ -1292,6 +1292,7 @@ extern int r600_audio_bits_per_sample(struct radeon_device *rdev);
extern int r600_audio_rate(struct radeon_device *rdev);
extern uint8_t r600_audio_status_bits(struct radeon_device *rdev);
extern uint8_t r600_audio_category_code(struct radeon_device *rdev);
+extern void r600_audio_schedule_polling(struct radeon_device *rdev);
extern void r600_audio_enable_polling(struct drm_encoder *encoder);
extern void r600_audio_disable_polling(struct drm_encoder *encoder);
extern void r600_audio_fini(struct radeon_device *rdev);
@@ -1300,6 +1301,7 @@ extern void r600_hdmi_enable(struct drm_encoder *encoder);
extern void r600_hdmi_disable(struct drm_encoder *encoder);
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 int r600_hdmi_irq_pending(struct drm_encoder *encoder);
extern void r600_hdmi_update_audio_settings(struct drm_encoder *encoder);
/* evergreen */
--
1.7.0