mirror of
https://gitlab.freedesktop.org/mesa/drm.git
synced 2026-05-09 07:28:42 +02:00
Add TV out hotplug detection
Doesn't yet work on my i915 test machine, but most of the necessary bits should be there.
This commit is contained in:
parent
b3737f3fd9
commit
386ea38b8e
2 changed files with 59 additions and 4 deletions
|
|
@ -554,7 +554,9 @@ extern int i915_wait_ring(struct drm_device * dev, int n, const char *caller);
|
|||
|
||||
#define I915_VBLANK_INTERRUPT_ENABLE (1UL<<17)
|
||||
#define I915_HOTPLUG_INTERRUPT_ENABLE (1UL<<26)
|
||||
#define I915_HOTPLUG_TV_INTERRUPT_ENABLE (1UL<<18)
|
||||
#define I915_HOTPLUG_CLEAR (1UL<<10)
|
||||
#define I915_HOTPLUG_TV_CLEAR (1UL<<2)
|
||||
#define I915_VBLANK_CLEAR (1UL<<1)
|
||||
|
||||
/*
|
||||
|
|
@ -669,6 +671,7 @@ extern int i915_wait_ring(struct drm_device * dev, int n, const char *caller);
|
|||
#define I915_LEGACY_BLC_EVENT_STATUS (1UL<<6)
|
||||
#define I915_ODD_FIELD_INTERRUPT_STATUS (1UL<<5)
|
||||
#define I915_EVEN_FIELD_INTERRUPT_STATUS (1UL<<4)
|
||||
#define I915_HOTPLUG_TV_INTERRUPT_STATUS (1UL<<2)
|
||||
#define I915_START_VBLANK_INTERRUPT_STATUS (1UL<<2) /* 965 or later */
|
||||
#define I915_VBLANK_INTERRUPT_STATUS (1UL<<1)
|
||||
#define I915_OVERLAY_UPDATED_STATUS (1UL<<0)
|
||||
|
|
|
|||
|
|
@ -424,11 +424,41 @@ u32 i915_get_vblank_counter(struct drm_device *dev, int plane)
|
|||
#define HOTPLUG_CMD_CRT_DIS 2
|
||||
#define HOTPLUG_CMD_SDVOB 4
|
||||
#define HOTPLUG_CMD_SDVOC 8
|
||||
#define HOTPLUG_CMD_TV 16
|
||||
|
||||
static struct drm_device *hotplug_dev;
|
||||
static int hotplug_cmd = 0;
|
||||
static spinlock_t hotplug_lock = SPIN_LOCK_UNLOCKED;
|
||||
|
||||
static void i915_hotplug_tv(struct drm_device *dev)
|
||||
{
|
||||
struct drm_output *output;
|
||||
struct intel_output *iout;
|
||||
enum drm_output_status status;
|
||||
|
||||
mutex_lock(&dev->mode_config.mutex);
|
||||
|
||||
/* find the crt output */
|
||||
list_for_each_entry(output, &dev->mode_config.output_list, head) {
|
||||
iout = output->driver_private;
|
||||
if (iout->type == INTEL_OUTPUT_TVOUT)
|
||||
break;
|
||||
else
|
||||
iout = 0;
|
||||
}
|
||||
|
||||
if (iout == 0)
|
||||
goto unlock;
|
||||
|
||||
/* may need to I915_WRITE(TVDAC, 1<<31) to ack the interrupt */
|
||||
status = output->funcs->detect(output);
|
||||
drm_hotplug_stage_two(dev, output,
|
||||
status == output_status_connected ? 1 : 0);
|
||||
|
||||
unlock:
|
||||
mutex_unlock(&dev->mode_config.mutex);
|
||||
}
|
||||
|
||||
static void i915_hotplug_crt(struct drm_device *dev, bool isconnected)
|
||||
{
|
||||
struct drm_output *output;
|
||||
|
|
@ -493,8 +523,10 @@ static void i915_hotplug_work_func(struct work_struct *work)
|
|||
int crtDis;
|
||||
int sdvoB;
|
||||
int sdvoC;
|
||||
int tv;
|
||||
|
||||
spin_lock(&hotplug_lock);
|
||||
tv = hotplug_cmd & HOTPLUG_CMD_TV;
|
||||
crt = hotplug_cmd & HOTPLUG_CMD_CRT;
|
||||
crtDis = hotplug_cmd & HOTPLUG_CMD_CRT_DIS;
|
||||
sdvoB = hotplug_cmd & HOTPLUG_CMD_SDVOB;
|
||||
|
|
@ -502,6 +534,8 @@ static void i915_hotplug_work_func(struct work_struct *work)
|
|||
hotplug_cmd = 0;
|
||||
spin_unlock(&hotplug_lock);
|
||||
|
||||
if (tv)
|
||||
i915_hotplug_tv(dev);
|
||||
if (crt)
|
||||
i915_hotplug_crt(dev, true);
|
||||
if (crtDis)
|
||||
|
|
@ -527,6 +561,14 @@ static int i915_run_hotplug_tasklet(struct drm_device *dev, uint32_t stat)
|
|||
|
||||
hotplug_dev = dev;
|
||||
|
||||
if (stat & TV_HOTPLUG_INT_STATUS) {
|
||||
DRM_DEBUG("TV event\n");
|
||||
|
||||
spin_lock(&hotplug_lock);
|
||||
hotplug_cmd |= HOTPLUG_CMD_TV;
|
||||
spin_unlock(&hotplug_lock);
|
||||
}
|
||||
|
||||
if (stat & CRT_HOTPLUG_INT_STATUS) {
|
||||
DRM_DEBUG("CRT event\n");
|
||||
|
||||
|
|
@ -584,12 +626,14 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS)
|
|||
DRM_DEBUG("flag=%08x\n", iir);
|
||||
#endif
|
||||
if (iir == 0) {
|
||||
#if 0
|
||||
DRM_DEBUG ("iir 0x%08x im 0x%08x ie 0x%08x pipea 0x%08x pipeb 0x%08x\n",
|
||||
iir,
|
||||
I915_READ(I915REG_INT_MASK_R),
|
||||
I915_READ(I915REG_INT_ENABLE_R),
|
||||
I915_READ(I915REG_PIPEASTAT),
|
||||
I915_READ(I915REG_PIPEBSTAT));
|
||||
#endif
|
||||
return IRQ_NONE;
|
||||
}
|
||||
|
||||
|
|
@ -607,7 +651,8 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS)
|
|||
}
|
||||
|
||||
/* This is a global event, and not a pipe A event */
|
||||
if (pipea_stats & I915_HOTPLUG_INTERRUPT_STATUS)
|
||||
if ((pipea_stats & I915_HOTPLUG_INTERRUPT_STATUS) ||
|
||||
(pipea_stats & I915_HOTPLUG_TV_INTERRUPT_STATUS))
|
||||
hotplug = 1;
|
||||
|
||||
I915_WRITE(I915REG_PIPEASTAT, pipea_stats);
|
||||
|
|
@ -656,8 +701,11 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS)
|
|||
DRM_INFO("Hotplug event received\n");
|
||||
|
||||
if (!IS_I9XX(dev) || IS_I915G(dev) || IS_I915GM(dev)) {
|
||||
temp2 |= SDVOB_HOTPLUG_INT_STATUS |
|
||||
SDVOC_HOTPLUG_INT_STATUS;
|
||||
if (pipea_stats & I915_HOTPLUG_INTERRUPT_STATUS)
|
||||
temp2 |= SDVOB_HOTPLUG_INT_STATUS |
|
||||
SDVOC_HOTPLUG_INT_STATUS;
|
||||
if (pipea_stats & I915_HOTPLUG_TV_INTERRUPT_STATUS)
|
||||
temp2 |= TV_HOTPLUG_INT_STATUS;
|
||||
} else {
|
||||
temp2 = I915_READ(PORT_HOTPLUG_STAT);
|
||||
|
||||
|
|
@ -898,7 +946,11 @@ void i915_enable_interrupt (struct drm_device *dev)
|
|||
dev_priv->irq_enable_reg |= I915_DISPLAY_PIPE_A_EVENT_INTERRUPT;
|
||||
|
||||
/* Enable global interrupts for hotplug - not a pipeA event */
|
||||
I915_WRITE(I915REG_PIPEASTAT, I915_READ(I915REG_PIPEASTAT) | I915_HOTPLUG_INTERRUPT_ENABLE | I915_HOTPLUG_CLEAR);
|
||||
I915_WRITE(I915REG_PIPEASTAT, I915_READ(I915REG_PIPEASTAT) |
|
||||
I915_HOTPLUG_INTERRUPT_ENABLE |
|
||||
I915_HOTPLUG_TV_INTERRUPT_ENABLE |
|
||||
I915_HOTPLUG_TV_CLEAR |
|
||||
I915_HOTPLUG_CLEAR);
|
||||
}
|
||||
|
||||
if (dev_priv->irq_enable_reg & (I915_DISPLAY_PORT_INTERRUPT | I915_DISPLAY_PIPE_A_EVENT_INTERRUPT)) {
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue