Merge branch 'for-airlied' of git://people.freedesktop.org/~danvet/drm-intel into drm-next

Daniel writes:
"The big ticket item here is the new i915 modeset infrastructure.
Shockingly it didn't not blow up all over the place (i.e. I've managed to
fix the ugly issues before merging). 1-2 smaller corner cases broke, but
we have patches. Also, there's tons of patches on top of this that clean
out cruft and fix a few bugs that couldn't be fixed with the crtc helper
based stuff. So more stuff to come ;-)

Also a few other things:
- Tiny fix in the fb helper to go through the official dpms interface
  instead of calling the crtc helper code.
- forcewake code frobbery from Ben, code should be more in-line with
  what Windows does now.
- fixes for the render ring flush on hsw (Paulo)
- gpu frequency tracepoint
- vlv forcewake changes to better align it with our understanding of the
  forcewake magic.
- a few smaller cleanups"

+ 2 fixes.

* 'for-airlied' of git://people.freedesktop.org/~danvet/drm-intel: (78 commits)
  drm/i915: fix OOPS in lid_notify
  drm/i915: correctly update crtc->x/y in set_base
  drm/fb helper: don't call drm_helper_connector_dpms directly
  drm/i915: improve modeset state checking after dpms calls
  drm/i915: add tons of modeset state checks
  drm/i915: no longer call drm_helper_resume_force_mode
  drm/i915: disable all crtcs at suspend time
  drm/i915: push commit_output_state past the crtc/encoder preparing
  drm/i915: switch the load detect code to the staged modeset config
  drm/i915: WARN if the pipe won't turn off
  drm/i915: s/intel_encoder_disable/intel_encoder_noop
  drm/i915: push commit_output_state past crtc disabling
  drm/i915: implement new set_mode code flow
  drm/i915: compute masks of crtcs affected in set_mode
  drm/i915: use staged outuput config in lvds->mode_fixup
  drm/i915: use staged outuput config in tv->mode_fixup
  drm/i915: extract adjusted mode computation
  drm/i915: move output commit and crtc disabling into set_mode
  drm/i915: remove crtc disabling special case
  drm/i915: push crtc->fb update into pipe_set_base
  ...
This commit is contained in:
Dave Airlie 2012-09-19 20:00:10 +10:00
commit 7facf16690
27 changed files with 2290 additions and 675 deletions

View File

@ -330,7 +330,7 @@ static void drm_fb_helper_dpms(struct fb_info *info, int dpms_mode)
/* Walk the connectors & encoders on this fb turning them on/off */ /* Walk the connectors & encoders on this fb turning them on/off */
for (j = 0; j < fb_helper->connector_count; j++) { for (j = 0; j < fb_helper->connector_count; j++) {
connector = fb_helper->connector_info[j]->connector; connector = fb_helper->connector_info[j]->connector;
drm_helper_connector_dpms(connector, dpms_mode); connector->funcs->dpms(connector, dpms_mode);
drm_connector_property_set_value(connector, drm_connector_property_set_value(connector,
dev->mode_config.dpms_property, dpms_mode); dev->mode_config.dpms_property, dpms_mode);
} }

View File

@ -114,6 +114,12 @@ struct intel_dvo_dev_ops {
*/ */
enum drm_connector_status (*detect)(struct intel_dvo_device *dvo); enum drm_connector_status (*detect)(struct intel_dvo_device *dvo);
/*
* Probe the current hw status, returning true if the connected output
* is active.
*/
bool (*get_hw_state)(struct intel_dvo_device *dev);
/** /**
* Query the device for the modes it provides. * Query the device for the modes it provides.
* *

View File

@ -359,6 +359,18 @@ static void ch7017_dpms(struct intel_dvo_device *dvo, bool enable)
msleep(20); msleep(20);
} }
static bool ch7017_get_hw_state(struct intel_dvo_device *dvo)
{
uint8_t val;
ch7017_read(dvo, CH7017_LVDS_POWER_DOWN, &val);
if (val & CH7017_LVDS_POWER_DOWN_EN)
return false;
else
return true;
}
static void ch7017_dump_regs(struct intel_dvo_device *dvo) static void ch7017_dump_regs(struct intel_dvo_device *dvo)
{ {
uint8_t val; uint8_t val;
@ -396,6 +408,7 @@ struct intel_dvo_dev_ops ch7017_ops = {
.mode_valid = ch7017_mode_valid, .mode_valid = ch7017_mode_valid,
.mode_set = ch7017_mode_set, .mode_set = ch7017_mode_set,
.dpms = ch7017_dpms, .dpms = ch7017_dpms,
.get_hw_state = ch7017_get_hw_state,
.dump_regs = ch7017_dump_regs, .dump_regs = ch7017_dump_regs,
.destroy = ch7017_destroy, .destroy = ch7017_destroy,
}; };

View File

@ -297,6 +297,18 @@ static void ch7xxx_dpms(struct intel_dvo_device *dvo, bool enable)
ch7xxx_writeb(dvo, CH7xxx_PM, CH7xxx_PM_FPD); ch7xxx_writeb(dvo, CH7xxx_PM, CH7xxx_PM_FPD);
} }
static bool ch7xxx_get_hw_state(struct intel_dvo_device *dvo)
{
u8 val;
ch7xxx_readb(dvo, CH7xxx_PM, &val);
if (val & CH7xxx_PM_FPD)
return false;
else
return true;
}
static void ch7xxx_dump_regs(struct intel_dvo_device *dvo) static void ch7xxx_dump_regs(struct intel_dvo_device *dvo)
{ {
int i; int i;
@ -326,6 +338,7 @@ struct intel_dvo_dev_ops ch7xxx_ops = {
.mode_valid = ch7xxx_mode_valid, .mode_valid = ch7xxx_mode_valid,
.mode_set = ch7xxx_mode_set, .mode_set = ch7xxx_mode_set,
.dpms = ch7xxx_dpms, .dpms = ch7xxx_dpms,
.get_hw_state = ch7xxx_get_hw_state,
.dump_regs = ch7xxx_dump_regs, .dump_regs = ch7xxx_dump_regs,
.destroy = ch7xxx_destroy, .destroy = ch7xxx_destroy,
}; };

View File

@ -323,6 +323,20 @@ static void ivch_dpms(struct intel_dvo_device *dvo, bool enable)
udelay(16 * 1000); udelay(16 * 1000);
} }
static bool ivch_get_hw_state(struct intel_dvo_device *dvo)
{
uint16_t vr01;
/* Set the new power state of the panel. */
if (!ivch_read(dvo, VR01, &vr01))
return false;
if (vr01 & VR01_LCD_ENABLE)
return true;
else
return false;
}
static void ivch_mode_set(struct intel_dvo_device *dvo, static void ivch_mode_set(struct intel_dvo_device *dvo,
struct drm_display_mode *mode, struct drm_display_mode *mode,
struct drm_display_mode *adjusted_mode) struct drm_display_mode *adjusted_mode)
@ -413,6 +427,7 @@ static void ivch_destroy(struct intel_dvo_device *dvo)
struct intel_dvo_dev_ops ivch_ops = { struct intel_dvo_dev_ops ivch_ops = {
.init = ivch_init, .init = ivch_init,
.dpms = ivch_dpms, .dpms = ivch_dpms,
.get_hw_state = ivch_get_hw_state,
.mode_valid = ivch_mode_valid, .mode_valid = ivch_mode_valid,
.mode_set = ivch_mode_set, .mode_set = ivch_mode_set,
.detect = ivch_detect, .detect = ivch_detect,

View File

@ -492,6 +492,20 @@ static void ns2501_mode_set(struct intel_dvo_device *dvo,
restore_dvo(dvo); restore_dvo(dvo);
} }
/* set the NS2501 power state */
static bool ns2501_get_hw_state(struct intel_dvo_device *dvo)
{
unsigned char ch;
if (!ns2501_readb(dvo, NS2501_REG8, &ch))
return false;
if (ch & NS2501_8_PD)
return true;
else
return false;
}
/* set the NS2501 power state */ /* set the NS2501 power state */
static void ns2501_dpms(struct intel_dvo_device *dvo, bool enable) static void ns2501_dpms(struct intel_dvo_device *dvo, bool enable)
{ {
@ -568,6 +582,7 @@ struct intel_dvo_dev_ops ns2501_ops = {
.mode_valid = ns2501_mode_valid, .mode_valid = ns2501_mode_valid,
.mode_set = ns2501_mode_set, .mode_set = ns2501_mode_set,
.dpms = ns2501_dpms, .dpms = ns2501_dpms,
.get_hw_state = ns2501_get_hw_state,
.dump_regs = ns2501_dump_regs, .dump_regs = ns2501_dump_regs,
.destroy = ns2501_destroy, .destroy = ns2501_destroy,
}; };

View File

@ -226,6 +226,21 @@ static void sil164_dpms(struct intel_dvo_device *dvo, bool enable)
return; return;
} }
static bool sil164_get_hw_state(struct intel_dvo_device *dvo)
{
int ret;
unsigned char ch;
ret = sil164_readb(dvo, SIL164_REG8, &ch);
if (ret == false)
return false;
if (ch & SIL164_8_PD)
return true;
else
return false;
}
static void sil164_dump_regs(struct intel_dvo_device *dvo) static void sil164_dump_regs(struct intel_dvo_device *dvo)
{ {
uint8_t val; uint8_t val;
@ -258,6 +273,7 @@ struct intel_dvo_dev_ops sil164_ops = {
.mode_valid = sil164_mode_valid, .mode_valid = sil164_mode_valid,
.mode_set = sil164_mode_set, .mode_set = sil164_mode_set,
.dpms = sil164_dpms, .dpms = sil164_dpms,
.get_hw_state = sil164_get_hw_state,
.dump_regs = sil164_dump_regs, .dump_regs = sil164_dump_regs,
.destroy = sil164_destroy, .destroy = sil164_destroy,
}; };

View File

@ -249,6 +249,19 @@ static void tfp410_dpms(struct intel_dvo_device *dvo, bool enable)
tfp410_writeb(dvo, TFP410_CTL_1, ctl1); tfp410_writeb(dvo, TFP410_CTL_1, ctl1);
} }
static bool tfp410_get_hw_state(struct intel_dvo_device *dvo)
{
uint8_t ctl1;
if (!tfp410_readb(dvo, TFP410_CTL_1, &ctl1))
return false;
if (ctl1 & TFP410_CTL_1_PD)
return true;
else
return false;
}
static void tfp410_dump_regs(struct intel_dvo_device *dvo) static void tfp410_dump_regs(struct intel_dvo_device *dvo)
{ {
uint8_t val, val2; uint8_t val, val2;
@ -299,6 +312,7 @@ struct intel_dvo_dev_ops tfp410_ops = {
.mode_valid = tfp410_mode_valid, .mode_valid = tfp410_mode_valid,
.mode_set = tfp410_mode_set, .mode_set = tfp410_mode_set,
.dpms = tfp410_dpms, .dpms = tfp410_dpms,
.get_hw_state = tfp410_get_hw_state,
.dump_regs = tfp410_dump_regs, .dump_regs = tfp410_dump_regs,
.destroy = tfp410_destroy, .destroy = tfp410_destroy,
}; };

View File

@ -353,40 +353,22 @@ static int i915_gem_request_info(struct seq_file *m, void *data)
struct drm_info_node *node = (struct drm_info_node *) m->private; struct drm_info_node *node = (struct drm_info_node *) m->private;
struct drm_device *dev = node->minor->dev; struct drm_device *dev = node->minor->dev;
drm_i915_private_t *dev_priv = dev->dev_private; drm_i915_private_t *dev_priv = dev->dev_private;
struct intel_ring_buffer *ring;
struct drm_i915_gem_request *gem_request; struct drm_i915_gem_request *gem_request;
int ret, count; int ret, count, i;
ret = mutex_lock_interruptible(&dev->struct_mutex); ret = mutex_lock_interruptible(&dev->struct_mutex);
if (ret) if (ret)
return ret; return ret;
count = 0; count = 0;
if (!list_empty(&dev_priv->ring[RCS].request_list)) { for_each_ring(ring, dev_priv, i) {
seq_printf(m, "Render requests:\n"); if (list_empty(&ring->request_list))
continue;
seq_printf(m, "%s requests:\n", ring->name);
list_for_each_entry(gem_request, list_for_each_entry(gem_request,
&dev_priv->ring[RCS].request_list, &ring->request_list,
list) {
seq_printf(m, " %d @ %d\n",
gem_request->seqno,
(int) (jiffies - gem_request->emitted_jiffies));
}
count++;
}
if (!list_empty(&dev_priv->ring[VCS].request_list)) {
seq_printf(m, "BSD requests:\n");
list_for_each_entry(gem_request,
&dev_priv->ring[VCS].request_list,
list) {
seq_printf(m, " %d @ %d\n",
gem_request->seqno,
(int) (jiffies - gem_request->emitted_jiffies));
}
count++;
}
if (!list_empty(&dev_priv->ring[BCS].request_list)) {
seq_printf(m, "BLT requests:\n");
list_for_each_entry(gem_request,
&dev_priv->ring[BCS].request_list,
list) { list) {
seq_printf(m, " %d @ %d\n", seq_printf(m, " %d @ %d\n",
gem_request->seqno, gem_request->seqno,
@ -416,14 +398,15 @@ static int i915_gem_seqno_info(struct seq_file *m, void *data)
struct drm_info_node *node = (struct drm_info_node *) m->private; struct drm_info_node *node = (struct drm_info_node *) m->private;
struct drm_device *dev = node->minor->dev; struct drm_device *dev = node->minor->dev;
drm_i915_private_t *dev_priv = dev->dev_private; drm_i915_private_t *dev_priv = dev->dev_private;
struct intel_ring_buffer *ring;
int ret, i; int ret, i;
ret = mutex_lock_interruptible(&dev->struct_mutex); ret = mutex_lock_interruptible(&dev->struct_mutex);
if (ret) if (ret)
return ret; return ret;
for (i = 0; i < I915_NUM_RINGS; i++) for_each_ring(ring, dev_priv, i)
i915_ring_seqno_info(m, &dev_priv->ring[i]); i915_ring_seqno_info(m, ring);
mutex_unlock(&dev->struct_mutex); mutex_unlock(&dev->struct_mutex);
@ -436,6 +419,7 @@ static int i915_interrupt_info(struct seq_file *m, void *data)
struct drm_info_node *node = (struct drm_info_node *) m->private; struct drm_info_node *node = (struct drm_info_node *) m->private;
struct drm_device *dev = node->minor->dev; struct drm_device *dev = node->minor->dev;
drm_i915_private_t *dev_priv = dev->dev_private; drm_i915_private_t *dev_priv = dev->dev_private;
struct intel_ring_buffer *ring;
int ret, i, pipe; int ret, i, pipe;
ret = mutex_lock_interruptible(&dev->struct_mutex); ret = mutex_lock_interruptible(&dev->struct_mutex);
@ -513,13 +497,13 @@ static int i915_interrupt_info(struct seq_file *m, void *data)
} }
seq_printf(m, "Interrupts received: %d\n", seq_printf(m, "Interrupts received: %d\n",
atomic_read(&dev_priv->irq_received)); atomic_read(&dev_priv->irq_received));
for (i = 0; i < I915_NUM_RINGS; i++) { for_each_ring(ring, dev_priv, i) {
if (IS_GEN6(dev) || IS_GEN7(dev)) { if (IS_GEN6(dev) || IS_GEN7(dev)) {
seq_printf(m, "Graphics Interrupt mask (%s): %08x\n", seq_printf(m,
dev_priv->ring[i].name, "Graphics Interrupt mask (%s): %08x\n",
I915_READ_IMR(&dev_priv->ring[i])); ring->name, I915_READ_IMR(ring));
} }
i915_ring_seqno_info(m, &dev_priv->ring[i]); i915_ring_seqno_info(m, ring);
} }
mutex_unlock(&dev->struct_mutex); mutex_unlock(&dev->struct_mutex);
@ -1529,9 +1513,7 @@ static int i915_ppgtt_info(struct seq_file *m, void *data)
if (INTEL_INFO(dev)->gen == 6) if (INTEL_INFO(dev)->gen == 6)
seq_printf(m, "GFX_MODE: 0x%08x\n", I915_READ(GFX_MODE)); seq_printf(m, "GFX_MODE: 0x%08x\n", I915_READ(GFX_MODE));
for (i = 0; i < I915_NUM_RINGS; i++) { for_each_ring(ring, dev_priv, i) {
ring = &dev_priv->ring[i];
seq_printf(m, "%s\n", ring->name); seq_printf(m, "%s\n", ring->name);
if (INTEL_INFO(dev)->gen == 7) if (INTEL_INFO(dev)->gen == 7)
seq_printf(m, "GFX_MODE: 0x%08x\n", I915_READ(RING_MODE_GEN7(ring))); seq_printf(m, "GFX_MODE: 0x%08x\n", I915_READ(RING_MODE_GEN7(ring)));

View File

@ -470,6 +470,9 @@ static int i915_drm_freeze(struct drm_device *dev)
"GEM idle failed, resume might fail\n"); "GEM idle failed, resume might fail\n");
return error; return error;
} }
intel_modeset_disable(dev);
drm_irq_uninstall(dev); drm_irq_uninstall(dev);
} }
@ -543,13 +546,9 @@ static int i915_drm_thaw(struct drm_device *dev)
mutex_unlock(&dev->struct_mutex); mutex_unlock(&dev->struct_mutex);
intel_modeset_init_hw(dev); intel_modeset_init_hw(dev);
intel_modeset_setup_hw_state(dev);
drm_mode_config_reset(dev); drm_mode_config_reset(dev);
drm_irq_install(dev); drm_irq_install(dev);
/* Resume the modeset for every activated CRTC */
mutex_lock(&dev->mode_config.mutex);
drm_helper_resume_force_mode(dev);
mutex_unlock(&dev->mode_config.mutex);
} }
intel_opregion_init(dev); intel_opregion_init(dev);

View File

@ -241,7 +241,6 @@ struct drm_i915_error_state {
}; };
struct drm_i915_display_funcs { struct drm_i915_display_funcs {
void (*dpms)(struct drm_crtc *crtc, int mode);
bool (*fbc_enabled)(struct drm_device *dev); bool (*fbc_enabled)(struct drm_device *dev);
void (*enable_fbc)(struct drm_crtc *crtc, unsigned long interval); void (*enable_fbc)(struct drm_crtc *crtc, unsigned long interval);
void (*disable_fbc)(struct drm_device *dev); void (*disable_fbc)(struct drm_device *dev);
@ -257,6 +256,8 @@ struct drm_i915_display_funcs {
struct drm_display_mode *adjusted_mode, struct drm_display_mode *adjusted_mode,
int x, int y, int x, int y,
struct drm_framebuffer *old_fb); struct drm_framebuffer *old_fb);
void (*crtc_enable)(struct drm_crtc *crtc);
void (*crtc_disable)(struct drm_crtc *crtc);
void (*off)(struct drm_crtc *crtc); void (*off)(struct drm_crtc *crtc);
void (*write_eld)(struct drm_connector *connector, void (*write_eld)(struct drm_connector *connector,
struct drm_crtc *crtc); struct drm_crtc *crtc);
@ -839,22 +840,26 @@ typedef struct drm_i915_private {
u8 max_delay; u8 max_delay;
} rps; } rps;
/* ilk-only ips/rps state. Everything in here is protected by the global
* mchdev_lock in intel_pm.c */
struct {
u8 cur_delay;
u8 min_delay;
u8 max_delay;
u8 fmax;
u8 fstart;
u8 cur_delay; u64 last_count1;
u8 min_delay; unsigned long last_time1;
u8 max_delay; unsigned long chipset_power;
u8 fmax; u64 last_count2;
u8 fstart; struct timespec last_time2;
unsigned long gfx_power;
u8 corr;
u64 last_count1; int c_m;
unsigned long last_time1; int r_t;
unsigned long chipset_power; } ips;
u64 last_count2;
struct timespec last_time2;
unsigned long gfx_power;
int c_m;
int r_t;
u8 corr;
enum no_fbc_reason no_fbc_reason; enum no_fbc_reason no_fbc_reason;
@ -1546,6 +1551,7 @@ extern void intel_modeset_init(struct drm_device *dev);
extern void intel_modeset_gem_init(struct drm_device *dev); extern void intel_modeset_gem_init(struct drm_device *dev);
extern void intel_modeset_cleanup(struct drm_device *dev); extern void intel_modeset_cleanup(struct drm_device *dev);
extern int intel_modeset_vga_set_state(struct drm_device *dev, bool state); extern int intel_modeset_vga_set_state(struct drm_device *dev, bool state);
extern void intel_modeset_setup_hw_state(struct drm_device *dev);
extern bool intel_fbc_enabled(struct drm_device *dev); extern bool intel_fbc_enabled(struct drm_device *dev);
extern void intel_disable_fbc(struct drm_device *dev); extern void intel_disable_fbc(struct drm_device *dev);
extern bool ironlake_set_drps(struct drm_device *dev, u8 val); extern bool ironlake_set_drps(struct drm_device *dev, u8 val);

View File

@ -310,7 +310,7 @@ static void ironlake_handle_rps_change(struct drm_device *dev)
I915_WRITE16(MEMINTRSTS, I915_READ(MEMINTRSTS)); I915_WRITE16(MEMINTRSTS, I915_READ(MEMINTRSTS));
new_delay = dev_priv->cur_delay; new_delay = dev_priv->ips.cur_delay;
I915_WRITE16(MEMINTRSTS, MEMINT_EVAL_CHG); I915_WRITE16(MEMINTRSTS, MEMINT_EVAL_CHG);
busy_up = I915_READ(RCPREVBSYTUPAVG); busy_up = I915_READ(RCPREVBSYTUPAVG);
@ -320,19 +320,19 @@ static void ironlake_handle_rps_change(struct drm_device *dev)
/* Handle RCS change request from hw */ /* Handle RCS change request from hw */
if (busy_up > max_avg) { if (busy_up > max_avg) {
if (dev_priv->cur_delay != dev_priv->max_delay) if (dev_priv->ips.cur_delay != dev_priv->ips.max_delay)
new_delay = dev_priv->cur_delay - 1; new_delay = dev_priv->ips.cur_delay - 1;
if (new_delay < dev_priv->max_delay) if (new_delay < dev_priv->ips.max_delay)
new_delay = dev_priv->max_delay; new_delay = dev_priv->ips.max_delay;
} else if (busy_down < min_avg) { } else if (busy_down < min_avg) {
if (dev_priv->cur_delay != dev_priv->min_delay) if (dev_priv->ips.cur_delay != dev_priv->ips.min_delay)
new_delay = dev_priv->cur_delay + 1; new_delay = dev_priv->ips.cur_delay + 1;
if (new_delay > dev_priv->min_delay) if (new_delay > dev_priv->ips.min_delay)
new_delay = dev_priv->min_delay; new_delay = dev_priv->ips.min_delay;
} }
if (ironlake_set_drps(dev, new_delay)) if (ironlake_set_drps(dev, new_delay))
dev_priv->cur_delay = new_delay; dev_priv->ips.cur_delay = new_delay;
spin_unlock_irqrestore(&mchdev_lock, flags); spin_unlock_irqrestore(&mchdev_lock, flags);

View File

@ -4037,6 +4037,8 @@
#define PORT_TRANS_C_SEL_CPT (2<<29) #define PORT_TRANS_C_SEL_CPT (2<<29)
#define PORT_TRANS_SEL_MASK (3<<29) #define PORT_TRANS_SEL_MASK (3<<29)
#define PORT_TRANS_SEL_CPT(pipe) ((pipe) << 29) #define PORT_TRANS_SEL_CPT(pipe) ((pipe) << 29)
#define PORT_TO_PIPE(val) (((val) & (1<<30)) >> 30)
#define PORT_TO_PIPE_CPT(val) (((val) & PORT_TRANS_SEL_MASK) >> 29)
#define TRANS_DP_CTL_A 0xe0300 #define TRANS_DP_CTL_A 0xe0300
#define TRANS_DP_CTL_B 0xe1300 #define TRANS_DP_CTL_B 0xe1300

View File

@ -93,6 +93,7 @@ static struct attribute_group rc6_attr_group = {
.name = power_group_name, .name = power_group_name,
.attrs = rc6_attrs .attrs = rc6_attrs
}; };
#endif
static int l3_access_valid(struct drm_device *dev, loff_t offset) static int l3_access_valid(struct drm_device *dev, loff_t offset)
{ {
@ -206,13 +207,14 @@ void i915_setup_sysfs(struct drm_device *dev)
{ {
int ret; int ret;
#ifdef CONFIG_PM
if (INTEL_INFO(dev)->gen >= 6) { if (INTEL_INFO(dev)->gen >= 6) {
ret = sysfs_merge_group(&dev->primary->kdev.kobj, ret = sysfs_merge_group(&dev->primary->kdev.kobj,
&rc6_attr_group); &rc6_attr_group);
if (ret) if (ret)
DRM_ERROR("RC6 residency sysfs setup failed\n"); DRM_ERROR("RC6 residency sysfs setup failed\n");
} }
#endif
if (HAS_L3_GPU_CACHE(dev)) { if (HAS_L3_GPU_CACHE(dev)) {
ret = device_create_bin_file(&dev->primary->kdev, &dpf_attrs); ret = device_create_bin_file(&dev->primary->kdev, &dpf_attrs);
if (ret) if (ret)
@ -225,14 +227,3 @@ void i915_teardown_sysfs(struct drm_device *dev)
device_remove_bin_file(&dev->primary->kdev, &dpf_attrs); device_remove_bin_file(&dev->primary->kdev, &dpf_attrs);
sysfs_unmerge_group(&dev->primary->kdev.kobj, &rc6_attr_group); sysfs_unmerge_group(&dev->primary->kdev.kobj, &rc6_attr_group);
} }
#else
void i915_setup_sysfs(struct drm_device *dev)
{
return;
}
void i915_teardown_sysfs(struct drm_device *dev)
{
return;
}
#endif /* CONFIG_PM */

View File

@ -430,6 +430,21 @@ TRACE_EVENT(i915_reg_rw,
(u32)(__entry->val >> 32)) (u32)(__entry->val >> 32))
); );
TRACE_EVENT(intel_gpu_freq_change,
TP_PROTO(u32 freq),
TP_ARGS(freq),
TP_STRUCT__entry(
__field(u32, freq)
),
TP_fast_assign(
__entry->freq = freq;
),
TP_printk("new_freq=%u", __entry->freq)
);
#endif /* _I915_TRACE_H_ */ #endif /* _I915_TRACE_H_ */
/* This part must be outside protection */ /* This part must be outside protection */

View File

@ -61,41 +61,62 @@ static struct intel_crt *intel_encoder_to_crt(struct intel_encoder *encoder)
return container_of(encoder, struct intel_crt, base); return container_of(encoder, struct intel_crt, base);
} }
static void pch_crt_dpms(struct drm_encoder *encoder, int mode) static bool intel_crt_get_hw_state(struct intel_encoder *encoder,
enum pipe *pipe)
{ {
struct drm_device *dev = encoder->dev; struct drm_device *dev = encoder->base.dev;
struct drm_i915_private *dev_priv = dev->dev_private; struct drm_i915_private *dev_priv = dev->dev_private;
u32 temp; struct intel_crt *crt = intel_encoder_to_crt(encoder);
u32 tmp;
temp = I915_READ(PCH_ADPA); tmp = I915_READ(crt->adpa_reg);
temp &= ~ADPA_DAC_ENABLE;
switch (mode) { if (!(tmp & ADPA_DAC_ENABLE))
case DRM_MODE_DPMS_ON: return false;
temp |= ADPA_DAC_ENABLE;
break;
case DRM_MODE_DPMS_STANDBY:
case DRM_MODE_DPMS_SUSPEND:
case DRM_MODE_DPMS_OFF:
/* Just leave port enable cleared */
break;
}
I915_WRITE(PCH_ADPA, temp); if (HAS_PCH_CPT(dev))
*pipe = PORT_TO_PIPE_CPT(tmp);
else
*pipe = PORT_TO_PIPE(tmp);
return true;
} }
static void gmch_crt_dpms(struct drm_encoder *encoder, int mode) static void intel_disable_crt(struct intel_encoder *encoder)
{ {
struct drm_device *dev = encoder->dev; struct drm_i915_private *dev_priv = encoder->base.dev->dev_private;
struct drm_i915_private *dev_priv = dev->dev_private; struct intel_crt *crt = intel_encoder_to_crt(encoder);
u32 temp; u32 temp;
temp = I915_READ(ADPA); temp = I915_READ(crt->adpa_reg);
temp &= ~(ADPA_HSYNC_CNTL_DISABLE | ADPA_VSYNC_CNTL_DISABLE); temp &= ~(ADPA_HSYNC_CNTL_DISABLE | ADPA_VSYNC_CNTL_DISABLE);
temp &= ~ADPA_DAC_ENABLE; temp &= ~ADPA_DAC_ENABLE;
I915_WRITE(crt->adpa_reg, temp);
}
if (IS_VALLEYVIEW(dev) && mode != DRM_MODE_DPMS_ON) static void intel_enable_crt(struct intel_encoder *encoder)
mode = DRM_MODE_DPMS_OFF; {
struct drm_i915_private *dev_priv = encoder->base.dev->dev_private;
struct intel_crt *crt = intel_encoder_to_crt(encoder);
u32 temp;
temp = I915_READ(crt->adpa_reg);
temp |= ADPA_DAC_ENABLE;
I915_WRITE(crt->adpa_reg, temp);
}
/* Note: The caller is required to filter out dpms modes not supported by the
* platform. */
static void intel_crt_set_dpms(struct intel_encoder *encoder, int mode)
{
struct drm_device *dev = encoder->base.dev;
struct drm_i915_private *dev_priv = dev->dev_private;
struct intel_crt *crt = intel_encoder_to_crt(encoder);
u32 temp;
temp = I915_READ(crt->adpa_reg);
temp &= ~(ADPA_HSYNC_CNTL_DISABLE | ADPA_VSYNC_CNTL_DISABLE);
temp &= ~ADPA_DAC_ENABLE;
switch (mode) { switch (mode) {
case DRM_MODE_DPMS_ON: case DRM_MODE_DPMS_ON:
@ -112,7 +133,51 @@ static void gmch_crt_dpms(struct drm_encoder *encoder, int mode)
break; break;
} }
I915_WRITE(ADPA, temp); I915_WRITE(crt->adpa_reg, temp);
}
static void intel_crt_dpms(struct drm_connector *connector, int mode)
{
struct drm_device *dev = connector->dev;
struct intel_encoder *encoder = intel_attached_encoder(connector);
struct drm_crtc *crtc;
int old_dpms;
/* PCH platforms and VLV only support on/off. */
if (INTEL_INFO(dev)->gen < 5 && mode != DRM_MODE_DPMS_ON)
mode = DRM_MODE_DPMS_OFF;
if (mode == connector->dpms)
return;
old_dpms = connector->dpms;
connector->dpms = mode;
/* Only need to change hw state when actually enabled */
crtc = encoder->base.crtc;
if (!crtc) {
encoder->connectors_active = false;
return;
}
/* We need the pipe to run for anything but OFF. */
if (mode == DRM_MODE_DPMS_OFF)
encoder->connectors_active = false;
else
encoder->connectors_active = true;
if (mode < old_dpms) {
/* From off to on, enable the pipe first. */
intel_crtc_update_dpms(crtc);
intel_crt_set_dpms(encoder, mode);
} else {
intel_crt_set_dpms(encoder, mode);
intel_crtc_update_dpms(crtc);
}
intel_modeset_check_state(connector->dev);
} }
static int intel_crt_mode_valid(struct drm_connector *connector, static int intel_crt_mode_valid(struct drm_connector *connector,
@ -603,25 +668,15 @@ static void intel_crt_reset(struct drm_connector *connector)
* Routines for controlling stuff on the analog port * Routines for controlling stuff on the analog port
*/ */
static const struct drm_encoder_helper_funcs pch_encoder_funcs = { static const struct drm_encoder_helper_funcs crt_encoder_funcs = {
.mode_fixup = intel_crt_mode_fixup, .mode_fixup = intel_crt_mode_fixup,
.prepare = intel_encoder_prepare,
.commit = intel_encoder_commit,
.mode_set = intel_crt_mode_set, .mode_set = intel_crt_mode_set,
.dpms = pch_crt_dpms, .disable = intel_encoder_noop,
};
static const struct drm_encoder_helper_funcs gmch_encoder_funcs = {
.mode_fixup = intel_crt_mode_fixup,
.prepare = intel_encoder_prepare,
.commit = intel_encoder_commit,
.mode_set = intel_crt_mode_set,
.dpms = gmch_crt_dpms,
}; };
static const struct drm_connector_funcs intel_crt_connector_funcs = { static const struct drm_connector_funcs intel_crt_connector_funcs = {
.reset = intel_crt_reset, .reset = intel_crt_reset,
.dpms = drm_helper_connector_dpms, .dpms = intel_crt_dpms,
.detect = intel_crt_detect, .detect = intel_crt_detect,
.fill_modes = drm_helper_probe_single_connector_modes, .fill_modes = drm_helper_probe_single_connector_modes,
.destroy = intel_crt_destroy, .destroy = intel_crt_destroy,
@ -662,7 +717,6 @@ void intel_crt_init(struct drm_device *dev)
struct intel_crt *crt; struct intel_crt *crt;
struct intel_connector *intel_connector; struct intel_connector *intel_connector;
struct drm_i915_private *dev_priv = dev->dev_private; struct drm_i915_private *dev_priv = dev->dev_private;
const struct drm_encoder_helper_funcs *encoder_helper_funcs;
/* Skip machines without VGA that falsely report hotplug events */ /* Skip machines without VGA that falsely report hotplug events */
if (dmi_check_system(intel_no_crt)) if (dmi_check_system(intel_no_crt))
@ -700,11 +754,6 @@ void intel_crt_init(struct drm_device *dev)
connector->interlace_allowed = 1; connector->interlace_allowed = 1;
connector->doublescan_allowed = 0; connector->doublescan_allowed = 0;
if (HAS_PCH_SPLIT(dev))
encoder_helper_funcs = &pch_encoder_funcs;
else
encoder_helper_funcs = &gmch_encoder_funcs;
if (HAS_PCH_SPLIT(dev)) if (HAS_PCH_SPLIT(dev))
crt->adpa_reg = PCH_ADPA; crt->adpa_reg = PCH_ADPA;
else if (IS_VALLEYVIEW(dev)) else if (IS_VALLEYVIEW(dev))
@ -712,7 +761,12 @@ void intel_crt_init(struct drm_device *dev)
else else
crt->adpa_reg = ADPA; crt->adpa_reg = ADPA;
drm_encoder_helper_add(&crt->base.base, encoder_helper_funcs); crt->base.disable = intel_disable_crt;
crt->base.enable = intel_enable_crt;
crt->base.get_hw_state = intel_crt_get_hw_state;
intel_connector->get_hw_state = intel_connector_get_hw_state;
drm_encoder_helper_add(&crt->base.base, &crt_encoder_funcs);
drm_connector_helper_add(connector, &intel_crt_connector_helper_funcs); drm_connector_helper_add(connector, &intel_crt_connector_helper_funcs);
drm_sysfs_connector_add(connector); drm_sysfs_connector_add(connector);

View File

@ -757,26 +757,63 @@ void intel_ddi_mode_set(struct drm_encoder *encoder,
intel_hdmi->set_infoframes(encoder, adjusted_mode); intel_hdmi->set_infoframes(encoder, adjusted_mode);
} }
void intel_ddi_dpms(struct drm_encoder *encoder, int mode) bool intel_ddi_get_hw_state(struct intel_encoder *encoder,
enum pipe *pipe)
{ {
struct drm_device *dev = encoder->dev; struct drm_device *dev = encoder->base.dev;
struct drm_i915_private *dev_priv = dev->dev_private; struct drm_i915_private *dev_priv = dev->dev_private;
struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder); struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(&encoder->base);
u32 tmp;
int i;
tmp = I915_READ(DDI_BUF_CTL(intel_hdmi->ddi_port));
if (!(tmp & DDI_BUF_CTL_ENABLE))
return false;
for_each_pipe(i) {
tmp = I915_READ(DDI_FUNC_CTL(i));
if ((tmp & PIPE_DDI_PORT_MASK)
== PIPE_DDI_SELECT_PORT(intel_hdmi->ddi_port)) {
*pipe = i;
return true;
}
}
DRM_DEBUG_KMS("No pipe for ddi port %i found\n", intel_hdmi->ddi_port);
return true;
}
void intel_enable_ddi(struct intel_encoder *encoder)
{
struct drm_device *dev = encoder->base.dev;
struct drm_i915_private *dev_priv = dev->dev_private;
struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(&encoder->base);
int port = intel_hdmi->ddi_port; int port = intel_hdmi->ddi_port;
u32 temp; u32 temp;
temp = I915_READ(DDI_BUF_CTL(port)); temp = I915_READ(DDI_BUF_CTL(port));
temp |= DDI_BUF_CTL_ENABLE;
if (mode != DRM_MODE_DPMS_ON) {
temp &= ~DDI_BUF_CTL_ENABLE;
} else {
temp |= DDI_BUF_CTL_ENABLE;
}
/* Enable DDI_BUF_CTL. In HDMI/DVI mode, the port width, /* Enable DDI_BUF_CTL. In HDMI/DVI mode, the port width,
* and swing/emphasis values are ignored so nothing special needs * and swing/emphasis values are ignored so nothing special needs
* to be done besides enabling the port. * to be done besides enabling the port.
*/ */
I915_WRITE(DDI_BUF_CTL(port), I915_WRITE(DDI_BUF_CTL(port), temp);
temp); }
void intel_disable_ddi(struct intel_encoder *encoder)
{
struct drm_device *dev = encoder->base.dev;
struct drm_i915_private *dev_priv = dev->dev_private;
struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(&encoder->base);
int port = intel_hdmi->ddi_port;
u32 temp;
temp = I915_READ(DDI_BUF_CTL(port));
temp &= ~DDI_BUF_CTL_ENABLE;
I915_WRITE(DDI_BUF_CTL(port), temp);
} }

File diff suppressed because it is too large Load Diff

View File

@ -1248,10 +1248,57 @@ static void intel_dp_sink_dpms(struct intel_dp *intel_dp, int mode)
} }
} }
static void intel_dp_prepare(struct drm_encoder *encoder) static bool intel_dp_get_hw_state(struct intel_encoder *encoder,
enum pipe *pipe)
{ {
struct intel_dp *intel_dp = enc_to_intel_dp(encoder); struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
struct drm_device *dev = encoder->base.dev;
struct drm_i915_private *dev_priv = dev->dev_private;
u32 tmp = I915_READ(intel_dp->output_reg);
if (!(tmp & DP_PORT_EN))
return false;
if (is_cpu_edp(intel_dp) && IS_GEN7(dev)) {
*pipe = PORT_TO_PIPE_CPT(tmp);
} else if (!HAS_PCH_CPT(dev) || is_cpu_edp(intel_dp)) {
*pipe = PORT_TO_PIPE(tmp);
} else {
u32 trans_sel;
u32 trans_dp;
int i;
switch (intel_dp->output_reg) {
case PCH_DP_B:
trans_sel = TRANS_DP_PORT_SEL_B;
break;
case PCH_DP_C:
trans_sel = TRANS_DP_PORT_SEL_C;
break;
case PCH_DP_D:
trans_sel = TRANS_DP_PORT_SEL_D;
break;
default:
return true;
}
for_each_pipe(i) {
trans_dp = I915_READ(TRANS_DP_CTL(i));
if ((trans_dp & TRANS_DP_PORT_SEL_MASK) == trans_sel) {
*pipe = i;
return true;
}
}
}
DRM_DEBUG_KMS("No pipe for dp port 0x%x found\n", intel_dp->output_reg);
return true;
}
static void intel_disable_dp(struct intel_encoder *encoder)
{
struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
/* Make sure the panel is off before trying to change the mode. But also /* Make sure the panel is off before trying to change the mode. But also
* ensure that we have vdd while we switch off the panel. */ * ensure that we have vdd while we switch off the panel. */
@ -1262,60 +1309,58 @@ static void intel_dp_prepare(struct drm_encoder *encoder)
intel_dp_link_down(intel_dp); intel_dp_link_down(intel_dp);
} }
static void intel_dp_commit(struct drm_encoder *encoder) static void intel_enable_dp(struct intel_encoder *encoder)
{ {
struct intel_dp *intel_dp = enc_to_intel_dp(encoder); struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
struct drm_device *dev = encoder->dev; struct drm_device *dev = encoder->base.dev;
struct intel_crtc *intel_crtc = to_intel_crtc(intel_dp->base.base.crtc);
ironlake_edp_panel_vdd_on(intel_dp);
intel_dp_sink_dpms(intel_dp, DRM_MODE_DPMS_ON);
intel_dp_start_link_train(intel_dp);
ironlake_edp_panel_on(intel_dp);
ironlake_edp_panel_vdd_off(intel_dp, true);
intel_dp_complete_link_train(intel_dp);
ironlake_edp_backlight_on(intel_dp);
intel_dp->dpms_mode = DRM_MODE_DPMS_ON;
if (HAS_PCH_CPT(dev))
intel_cpt_verify_modeset(dev, intel_crtc->pipe);
}
static void
intel_dp_dpms(struct drm_encoder *encoder, int mode)
{
struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
struct drm_device *dev = encoder->dev;
struct drm_i915_private *dev_priv = dev->dev_private; struct drm_i915_private *dev_priv = dev->dev_private;
uint32_t dp_reg = I915_READ(intel_dp->output_reg); uint32_t dp_reg = I915_READ(intel_dp->output_reg);
ironlake_edp_panel_vdd_on(intel_dp);
intel_dp_sink_dpms(intel_dp, DRM_MODE_DPMS_ON);
if (!(dp_reg & DP_PORT_EN)) {
intel_dp_start_link_train(intel_dp);
ironlake_edp_panel_on(intel_dp);
ironlake_edp_panel_vdd_off(intel_dp, true);
intel_dp_complete_link_train(intel_dp);
} else
ironlake_edp_panel_vdd_off(intel_dp, false);
ironlake_edp_backlight_on(intel_dp);
}
static void
intel_dp_dpms(struct drm_connector *connector, int mode)
{
struct intel_dp *intel_dp = intel_attached_dp(connector);
/* DP supports only 2 dpms states. */
if (mode != DRM_MODE_DPMS_ON)
mode = DRM_MODE_DPMS_OFF;
if (mode == connector->dpms)
return;
connector->dpms = mode;
/* Only need to change hw state when actually enabled */
if (!intel_dp->base.base.crtc) {
intel_dp->base.connectors_active = false;
return;
}
if (mode != DRM_MODE_DPMS_ON) { if (mode != DRM_MODE_DPMS_ON) {
/* Switching the panel off requires vdd. */ intel_encoder_dpms(&intel_dp->base, mode);
ironlake_edp_panel_vdd_on(intel_dp);
ironlake_edp_backlight_off(intel_dp);
intel_dp_sink_dpms(intel_dp, mode);
ironlake_edp_panel_off(intel_dp);
intel_dp_link_down(intel_dp);
if (is_cpu_edp(intel_dp)) if (is_cpu_edp(intel_dp))
ironlake_edp_pll_off(encoder); ironlake_edp_pll_off(&intel_dp->base.base);
} else { } else {
if (is_cpu_edp(intel_dp)) if (is_cpu_edp(intel_dp))
ironlake_edp_pll_on(encoder); ironlake_edp_pll_on(&intel_dp->base.base);
ironlake_edp_panel_vdd_on(intel_dp); intel_encoder_dpms(&intel_dp->base, mode);
intel_dp_sink_dpms(intel_dp, mode);
if (!(dp_reg & DP_PORT_EN)) {
intel_dp_start_link_train(intel_dp);
ironlake_edp_panel_on(intel_dp);
ironlake_edp_panel_vdd_off(intel_dp, true);
intel_dp_complete_link_train(intel_dp);
} else
ironlake_edp_panel_vdd_off(intel_dp, false);
ironlake_edp_backlight_on(intel_dp);
} }
intel_dp->dpms_mode = mode;
intel_modeset_check_state(connector->dev);
} }
/* /*
@ -2016,10 +2061,10 @@ intel_dp_check_link_status(struct intel_dp *intel_dp)
u8 sink_irq_vector; u8 sink_irq_vector;
u8 link_status[DP_LINK_STATUS_SIZE]; u8 link_status[DP_LINK_STATUS_SIZE];
if (intel_dp->dpms_mode != DRM_MODE_DPMS_ON) if (!intel_dp->base.connectors_active)
return; return;
if (!intel_dp->base.base.crtc) if (WARN_ON(!intel_dp->base.base.crtc))
return; return;
/* Try to read receiver status if the link appears to be up */ /* Try to read receiver status if the link appears to be up */
@ -2305,9 +2350,8 @@ intel_dp_set_property(struct drm_connector *connector,
done: done:
if (intel_dp->base.base.crtc) { if (intel_dp->base.base.crtc) {
struct drm_crtc *crtc = intel_dp->base.base.crtc; struct drm_crtc *crtc = intel_dp->base.base.crtc;
drm_crtc_helper_set_mode(crtc, &crtc->mode, intel_set_mode(crtc, &crtc->mode,
crtc->x, crtc->y, crtc->x, crtc->y, crtc->fb);
crtc->fb);
} }
return 0; return 0;
@ -2341,15 +2385,13 @@ static void intel_dp_encoder_destroy(struct drm_encoder *encoder)
} }
static const struct drm_encoder_helper_funcs intel_dp_helper_funcs = { static const struct drm_encoder_helper_funcs intel_dp_helper_funcs = {
.dpms = intel_dp_dpms,
.mode_fixup = intel_dp_mode_fixup, .mode_fixup = intel_dp_mode_fixup,
.prepare = intel_dp_prepare,
.mode_set = intel_dp_mode_set, .mode_set = intel_dp_mode_set,
.commit = intel_dp_commit, .disable = intel_encoder_noop,
}; };
static const struct drm_connector_funcs intel_dp_connector_funcs = { static const struct drm_connector_funcs intel_dp_connector_funcs = {
.dpms = drm_helper_connector_dpms, .dpms = intel_dp_dpms,
.detect = intel_dp_detect, .detect = intel_dp_detect,
.fill_modes = drm_helper_probe_single_connector_modes, .fill_modes = drm_helper_probe_single_connector_modes,
.set_property = intel_dp_set_property, .set_property = intel_dp_set_property,
@ -2436,7 +2478,6 @@ intel_dp_init(struct drm_device *dev, int output_reg, enum port port)
intel_dp->output_reg = output_reg; intel_dp->output_reg = output_reg;
intel_dp->port = port; intel_dp->port = port;
intel_dp->dpms_mode = -1;
intel_connector = kzalloc(sizeof(struct intel_connector), GFP_KERNEL); intel_connector = kzalloc(sizeof(struct intel_connector), GFP_KERNEL);
if (!intel_connector) { if (!intel_connector) {
@ -2480,6 +2521,11 @@ intel_dp_init(struct drm_device *dev, int output_reg, enum port port)
intel_connector_attach_encoder(intel_connector, intel_encoder); intel_connector_attach_encoder(intel_connector, intel_encoder);
drm_sysfs_connector_add(connector); drm_sysfs_connector_add(connector);
intel_encoder->enable = intel_enable_dp;
intel_encoder->disable = intel_disable_dp;
intel_encoder->get_hw_state = intel_dp_get_hw_state;
intel_connector->get_hw_state = intel_connector_get_hw_state;
/* Set up the DDC bus. */ /* Set up the DDC bus. */
switch (port) { switch (port) {
case PORT_A: case PORT_A:

View File

@ -41,7 +41,11 @@
ret__ = -ETIMEDOUT; \ ret__ = -ETIMEDOUT; \
break; \ break; \
} \ } \
if (W && drm_can_sleep()) msleep(W); \ if (W && drm_can_sleep()) { \
msleep(W); \
} else { \
cpu_relax(); \
} \
} \ } \
ret__; \ ret__; \
}) })
@ -133,6 +137,12 @@ struct intel_fbdev {
struct intel_encoder { struct intel_encoder {
struct drm_encoder base; struct drm_encoder base;
/*
* The new crtc this encoder will be driven from. Only differs from
* base->crtc while a modeset is in progress.
*/
struct intel_crtc *new_crtc;
int type; int type;
bool needs_tv_clock; bool needs_tv_clock;
/* /*
@ -140,13 +150,33 @@ struct intel_encoder {
* simple flag is enough to compute the possible_clones mask. * simple flag is enough to compute the possible_clones mask.
*/ */
bool cloneable; bool cloneable;
bool connectors_active;
void (*hot_plug)(struct intel_encoder *); void (*hot_plug)(struct intel_encoder *);
void (*enable)(struct intel_encoder *);
void (*disable)(struct intel_encoder *);
/* Read out the current hw state of this connector, returning true if
* the encoder is active. If the encoder is enabled it also set the pipe
* it is connected to in the pipe parameter. */
bool (*get_hw_state)(struct intel_encoder *, enum pipe *pipe);
int crtc_mask; int crtc_mask;
}; };
struct intel_connector { struct intel_connector {
struct drm_connector base; struct drm_connector base;
/*
* The fixed encoder this connector is connected to.
*/
struct intel_encoder *encoder; struct intel_encoder *encoder;
/*
* The new encoder this connector will be driven. Only differs from
* encoder while a modeset is in progress.
*/
struct intel_encoder *new_encoder;
/* Reads out the current hw, returning true if the connector is enabled
* and active (i.e. dpms ON state). */
bool (*get_hw_state)(struct intel_connector *);
}; };
struct intel_crtc { struct intel_crtc {
@ -154,8 +184,12 @@ struct intel_crtc {
enum pipe pipe; enum pipe pipe;
enum plane plane; enum plane plane;
u8 lut_r[256], lut_g[256], lut_b[256]; u8 lut_r[256], lut_g[256], lut_b[256];
int dpms_mode; /*
bool active; /* is the crtc on? independent of the dpms mode */ * Whether the crtc and the connected output pipeline is active. Implies
* that crtc->enabled is set, i.e. the current mode configuration has
* some outputs connected to this crtc.
*/
bool active;
bool primary_disabled; /* is the crtc obscured by a plane? */ bool primary_disabled; /* is the crtc obscured by a plane? */
bool lowfreq_avail; bool lowfreq_avail;
struct intel_overlay *overlay; struct intel_overlay *overlay;
@ -307,7 +341,6 @@ struct intel_dp {
enum hdmi_force_audio force_audio; enum hdmi_force_audio force_audio;
enum port port; enum port port;
uint32_t color_range; uint32_t color_range;
int dpms_mode;
uint8_t link_bw; uint8_t link_bw;
uint8_t lane_count; uint8_t lane_count;
uint8_t dpcd[DP_RECEIVER_CAP_SIZE]; uint8_t dpcd[DP_RECEIVER_CAP_SIZE];
@ -409,10 +442,27 @@ extern void intel_panel_disable_backlight(struct drm_device *dev);
extern void intel_panel_destroy_backlight(struct drm_device *dev); extern void intel_panel_destroy_backlight(struct drm_device *dev);
extern enum drm_connector_status intel_panel_detect(struct drm_device *dev); extern enum drm_connector_status intel_panel_detect(struct drm_device *dev);
struct intel_set_config {
struct drm_encoder **save_connector_encoders;
struct drm_crtc **save_encoder_crtcs;
bool fb_changed;
bool mode_changed;
};
extern bool intel_set_mode(struct drm_crtc *crtc, struct drm_display_mode *mode,
int x, int y, struct drm_framebuffer *old_fb);
extern void intel_modeset_disable(struct drm_device *dev);
extern void intel_crtc_load_lut(struct drm_crtc *crtc); extern void intel_crtc_load_lut(struct drm_crtc *crtc);
extern void intel_encoder_prepare(struct drm_encoder *encoder); extern void intel_crtc_update_dpms(struct drm_crtc *crtc);
extern void intel_encoder_commit(struct drm_encoder *encoder); extern void intel_encoder_noop(struct drm_encoder *encoder);
extern void intel_encoder_destroy(struct drm_encoder *encoder); extern void intel_encoder_destroy(struct drm_encoder *encoder);
extern void intel_encoder_dpms(struct intel_encoder *encoder, int mode);
extern bool intel_encoder_check_is_cloned(struct intel_encoder *encoder);
extern void intel_connector_dpms(struct drm_connector *, int mode);
extern bool intel_connector_get_hw_state(struct intel_connector *connector);
extern void intel_modeset_check_state(struct drm_device *dev);
static inline struct intel_encoder *intel_attached_encoder(struct drm_connector *connector) static inline struct intel_encoder *intel_attached_encoder(struct drm_connector *connector)
{ {
@ -519,7 +569,10 @@ extern void intel_disable_gt_powersave(struct drm_device *dev);
extern void gen6_gt_check_fifodbg(struct drm_i915_private *dev_priv); extern void gen6_gt_check_fifodbg(struct drm_i915_private *dev_priv);
extern void ironlake_teardown_rc6(struct drm_device *dev); extern void ironlake_teardown_rc6(struct drm_device *dev);
extern void intel_ddi_dpms(struct drm_encoder *encoder, int mode); extern void intel_enable_ddi(struct intel_encoder *encoder);
extern void intel_disable_ddi(struct intel_encoder *encoder);
extern bool intel_ddi_get_hw_state(struct intel_encoder *encoder,
enum pipe *pipe);
extern void intel_ddi_mode_set(struct drm_encoder *encoder, extern void intel_ddi_mode_set(struct drm_encoder *encoder,
struct drm_display_mode *mode, struct drm_display_mode *mode,
struct drm_display_mode *adjusted_mode); struct drm_display_mode *adjusted_mode);

View File

@ -105,22 +105,91 @@ static struct intel_dvo *intel_attached_dvo(struct drm_connector *connector)
struct intel_dvo, base); struct intel_dvo, base);
} }
static void intel_dvo_dpms(struct drm_encoder *encoder, int mode) static bool intel_dvo_connector_get_hw_state(struct intel_connector *connector)
{ {
struct drm_i915_private *dev_priv = encoder->dev->dev_private; struct intel_dvo *intel_dvo = intel_attached_dvo(&connector->base);
struct intel_dvo *intel_dvo = enc_to_intel_dvo(encoder);
return intel_dvo->dev.dev_ops->get_hw_state(&intel_dvo->dev);
}
static bool intel_dvo_get_hw_state(struct intel_encoder *encoder,
enum pipe *pipe)
{
struct drm_device *dev = encoder->base.dev;
struct drm_i915_private *dev_priv = dev->dev_private;
struct intel_dvo *intel_dvo = enc_to_intel_dvo(&encoder->base);
u32 tmp;
tmp = I915_READ(intel_dvo->dev.dvo_reg);
if (!(tmp & DVO_ENABLE))
return false;
*pipe = PORT_TO_PIPE(tmp);
return true;
}
static void intel_disable_dvo(struct intel_encoder *encoder)
{
struct drm_i915_private *dev_priv = encoder->base.dev->dev_private;
struct intel_dvo *intel_dvo = enc_to_intel_dvo(&encoder->base);
u32 dvo_reg = intel_dvo->dev.dvo_reg; u32 dvo_reg = intel_dvo->dev.dvo_reg;
u32 temp = I915_READ(dvo_reg); u32 temp = I915_READ(dvo_reg);
intel_dvo->dev.dev_ops->dpms(&intel_dvo->dev, false);
I915_WRITE(dvo_reg, temp & ~DVO_ENABLE);
I915_READ(dvo_reg);
}
static void intel_enable_dvo(struct intel_encoder *encoder)
{
struct drm_i915_private *dev_priv = encoder->base.dev->dev_private;
struct intel_dvo *intel_dvo = enc_to_intel_dvo(&encoder->base);
u32 dvo_reg = intel_dvo->dev.dvo_reg;
u32 temp = I915_READ(dvo_reg);
I915_WRITE(dvo_reg, temp | DVO_ENABLE);
I915_READ(dvo_reg);
intel_dvo->dev.dev_ops->dpms(&intel_dvo->dev, true);
}
static void intel_dvo_dpms(struct drm_connector *connector, int mode)
{
struct intel_dvo *intel_dvo = intel_attached_dvo(connector);
struct drm_crtc *crtc;
/* dvo supports only 2 dpms states. */
if (mode != DRM_MODE_DPMS_ON)
mode = DRM_MODE_DPMS_OFF;
if (mode == connector->dpms)
return;
connector->dpms = mode;
/* Only need to change hw state when actually enabled */
crtc = intel_dvo->base.base.crtc;
if (!crtc) {
intel_dvo->base.connectors_active = false;
return;
}
if (mode == DRM_MODE_DPMS_ON) { if (mode == DRM_MODE_DPMS_ON) {
I915_WRITE(dvo_reg, temp | DVO_ENABLE); intel_dvo->base.connectors_active = true;
I915_READ(dvo_reg);
intel_crtc_update_dpms(crtc);
intel_dvo->dev.dev_ops->dpms(&intel_dvo->dev, true); intel_dvo->dev.dev_ops->dpms(&intel_dvo->dev, true);
} else { } else {
intel_dvo->dev.dev_ops->dpms(&intel_dvo->dev, false); intel_dvo->dev.dev_ops->dpms(&intel_dvo->dev, false);
I915_WRITE(dvo_reg, temp & ~DVO_ENABLE);
I915_READ(dvo_reg); intel_dvo->base.connectors_active = false;
intel_crtc_update_dpms(crtc);
} }
intel_modeset_check_state(connector->dev);
} }
static int intel_dvo_mode_valid(struct drm_connector *connector, static int intel_dvo_mode_valid(struct drm_connector *connector,
@ -275,15 +344,13 @@ static void intel_dvo_destroy(struct drm_connector *connector)
} }
static const struct drm_encoder_helper_funcs intel_dvo_helper_funcs = { static const struct drm_encoder_helper_funcs intel_dvo_helper_funcs = {
.dpms = intel_dvo_dpms,
.mode_fixup = intel_dvo_mode_fixup, .mode_fixup = intel_dvo_mode_fixup,
.prepare = intel_encoder_prepare,
.mode_set = intel_dvo_mode_set, .mode_set = intel_dvo_mode_set,
.commit = intel_encoder_commit, .disable = intel_encoder_noop,
}; };
static const struct drm_connector_funcs intel_dvo_connector_funcs = { static const struct drm_connector_funcs intel_dvo_connector_funcs = {
.dpms = drm_helper_connector_dpms, .dpms = intel_dvo_dpms,
.detect = intel_dvo_detect, .detect = intel_dvo_detect,
.destroy = intel_dvo_destroy, .destroy = intel_dvo_destroy,
.fill_modes = drm_helper_probe_single_connector_modes, .fill_modes = drm_helper_probe_single_connector_modes,
@ -372,6 +439,11 @@ void intel_dvo_init(struct drm_device *dev)
drm_encoder_init(dev, &intel_encoder->base, drm_encoder_init(dev, &intel_encoder->base,
&intel_dvo_enc_funcs, encoder_type); &intel_dvo_enc_funcs, encoder_type);
intel_encoder->disable = intel_disable_dvo;
intel_encoder->enable = intel_enable_dvo;
intel_encoder->get_hw_state = intel_dvo_get_hw_state;
intel_connector->get_hw_state = intel_dvo_connector_get_hw_state;
/* Now, try to find a controller */ /* Now, try to find a controller */
for (i = 0; i < ARRAY_SIZE(intel_dvo_devices); i++) { for (i = 0; i < ARRAY_SIZE(intel_dvo_devices); i++) {
struct drm_connector *connector = &intel_connector->base; struct drm_connector *connector = &intel_connector->base;

View File

@ -601,11 +601,32 @@ static void intel_hdmi_mode_set(struct drm_encoder *encoder,
intel_hdmi->set_infoframes(encoder, adjusted_mode); intel_hdmi->set_infoframes(encoder, adjusted_mode);
} }
static void intel_hdmi_dpms(struct drm_encoder *encoder, int mode) static bool intel_hdmi_get_hw_state(struct intel_encoder *encoder,
enum pipe *pipe)
{ {
struct drm_device *dev = encoder->dev; struct drm_device *dev = encoder->base.dev;
struct drm_i915_private *dev_priv = dev->dev_private; struct drm_i915_private *dev_priv = dev->dev_private;
struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder); struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(&encoder->base);
u32 tmp;
tmp = I915_READ(intel_hdmi->sdvox_reg);
if (!(tmp & SDVO_ENABLE))
return false;
if (HAS_PCH_CPT(dev))
*pipe = PORT_TO_PIPE_CPT(tmp);
else
*pipe = PORT_TO_PIPE(tmp);
return true;
}
static void intel_enable_hdmi(struct intel_encoder *encoder)
{
struct drm_device *dev = encoder->base.dev;
struct drm_i915_private *dev_priv = dev->dev_private;
struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(&encoder->base);
u32 temp; u32 temp;
u32 enable_bits = SDVO_ENABLE; u32 enable_bits = SDVO_ENABLE;
@ -617,30 +638,70 @@ static void intel_hdmi_dpms(struct drm_encoder *encoder, int mode)
/* HW workaround for IBX, we need to move the port to transcoder A /* HW workaround for IBX, we need to move the port to transcoder A
* before disabling it. */ * before disabling it. */
if (HAS_PCH_IBX(dev)) { if (HAS_PCH_IBX(dev)) {
struct drm_crtc *crtc = encoder->crtc; struct drm_crtc *crtc = encoder->base.crtc;
int pipe = crtc ? to_intel_crtc(crtc)->pipe : -1; int pipe = crtc ? to_intel_crtc(crtc)->pipe : -1;
if (mode != DRM_MODE_DPMS_ON) { /* Restore the transcoder select bit. */
if (temp & SDVO_PIPE_B_SELECT) { if (pipe == PIPE_B)
temp &= ~SDVO_PIPE_B_SELECT; enable_bits |= SDVO_PIPE_B_SELECT;
I915_WRITE(intel_hdmi->sdvox_reg, temp); }
POSTING_READ(intel_hdmi->sdvox_reg);
/* Again we need to write this twice. */ /* HW workaround, need to toggle enable bit off and on for 12bpc, but
I915_WRITE(intel_hdmi->sdvox_reg, temp); * we do this anyway which shows more stable in testing.
POSTING_READ(intel_hdmi->sdvox_reg); */
if (HAS_PCH_SPLIT(dev)) {
I915_WRITE(intel_hdmi->sdvox_reg, temp & ~SDVO_ENABLE);
POSTING_READ(intel_hdmi->sdvox_reg);
}
/* Transcoder selection bits only update temp |= enable_bits;
* effectively on vblank. */
if (crtc) I915_WRITE(intel_hdmi->sdvox_reg, temp);
intel_wait_for_vblank(dev, pipe); POSTING_READ(intel_hdmi->sdvox_reg);
else
msleep(50); /* HW workaround, need to write this twice for issue that may result
} * in first write getting masked.
} else { */
/* Restore the transcoder select bit. */ if (HAS_PCH_SPLIT(dev)) {
if (pipe == PIPE_B) I915_WRITE(intel_hdmi->sdvox_reg, temp);
enable_bits |= SDVO_PIPE_B_SELECT; POSTING_READ(intel_hdmi->sdvox_reg);
}
}
static void intel_disable_hdmi(struct intel_encoder *encoder)
{
struct drm_device *dev = encoder->base.dev;
struct drm_i915_private *dev_priv = dev->dev_private;
struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(&encoder->base);
u32 temp;
u32 enable_bits = SDVO_ENABLE;
if (intel_hdmi->has_audio)
enable_bits |= SDVO_AUDIO_ENABLE;
temp = I915_READ(intel_hdmi->sdvox_reg);
/* HW workaround for IBX, we need to move the port to transcoder A
* before disabling it. */
if (HAS_PCH_IBX(dev)) {
struct drm_crtc *crtc = encoder->base.crtc;
int pipe = crtc ? to_intel_crtc(crtc)->pipe : -1;
if (temp & SDVO_PIPE_B_SELECT) {
temp &= ~SDVO_PIPE_B_SELECT;
I915_WRITE(intel_hdmi->sdvox_reg, temp);
POSTING_READ(intel_hdmi->sdvox_reg);
/* Again we need to write this twice. */
I915_WRITE(intel_hdmi->sdvox_reg, temp);
POSTING_READ(intel_hdmi->sdvox_reg);
/* Transcoder selection bits only update
* effectively on vblank. */
if (crtc)
intel_wait_for_vblank(dev, pipe);
else
msleep(50);
} }
} }
@ -652,11 +713,7 @@ static void intel_hdmi_dpms(struct drm_encoder *encoder, int mode)
POSTING_READ(intel_hdmi->sdvox_reg); POSTING_READ(intel_hdmi->sdvox_reg);
} }
if (mode != DRM_MODE_DPMS_ON) { temp &= ~enable_bits;
temp &= ~enable_bits;
} else {
temp |= enable_bits;
}
I915_WRITE(intel_hdmi->sdvox_reg, temp); I915_WRITE(intel_hdmi->sdvox_reg, temp);
POSTING_READ(intel_hdmi->sdvox_reg); POSTING_READ(intel_hdmi->sdvox_reg);
@ -830,9 +887,8 @@ intel_hdmi_set_property(struct drm_connector *connector,
done: done:
if (intel_hdmi->base.base.crtc) { if (intel_hdmi->base.base.crtc) {
struct drm_crtc *crtc = intel_hdmi->base.base.crtc; struct drm_crtc *crtc = intel_hdmi->base.base.crtc;
drm_crtc_helper_set_mode(crtc, &crtc->mode, intel_set_mode(crtc, &crtc->mode,
crtc->x, crtc->y, crtc->x, crtc->y, crtc->fb);
crtc->fb);
} }
return 0; return 0;
@ -846,23 +902,19 @@ static void intel_hdmi_destroy(struct drm_connector *connector)
} }
static const struct drm_encoder_helper_funcs intel_hdmi_helper_funcs_hsw = { static const struct drm_encoder_helper_funcs intel_hdmi_helper_funcs_hsw = {
.dpms = intel_ddi_dpms,
.mode_fixup = intel_hdmi_mode_fixup, .mode_fixup = intel_hdmi_mode_fixup,
.prepare = intel_encoder_prepare,
.mode_set = intel_ddi_mode_set, .mode_set = intel_ddi_mode_set,
.commit = intel_encoder_commit, .disable = intel_encoder_noop,
}; };
static const struct drm_encoder_helper_funcs intel_hdmi_helper_funcs = { static const struct drm_encoder_helper_funcs intel_hdmi_helper_funcs = {
.dpms = intel_hdmi_dpms,
.mode_fixup = intel_hdmi_mode_fixup, .mode_fixup = intel_hdmi_mode_fixup,
.prepare = intel_encoder_prepare,
.mode_set = intel_hdmi_mode_set, .mode_set = intel_hdmi_mode_set,
.commit = intel_encoder_commit, .disable = intel_encoder_noop,
}; };
static const struct drm_connector_funcs intel_hdmi_connector_funcs = { static const struct drm_connector_funcs intel_hdmi_connector_funcs = {
.dpms = drm_helper_connector_dpms, .dpms = intel_connector_dpms,
.detect = intel_hdmi_detect, .detect = intel_hdmi_detect,
.fill_modes = drm_helper_probe_single_connector_modes, .fill_modes = drm_helper_probe_single_connector_modes,
.set_property = intel_hdmi_set_property, .set_property = intel_hdmi_set_property,
@ -961,10 +1013,21 @@ void intel_hdmi_init(struct drm_device *dev, int sdvox_reg, enum port port)
intel_hdmi->set_infoframes = cpt_set_infoframes; intel_hdmi->set_infoframes = cpt_set_infoframes;
} }
if (IS_HASWELL(dev)) if (IS_HASWELL(dev)) {
drm_encoder_helper_add(&intel_encoder->base, &intel_hdmi_helper_funcs_hsw); intel_encoder->enable = intel_enable_ddi;
else intel_encoder->disable = intel_disable_ddi;
drm_encoder_helper_add(&intel_encoder->base, &intel_hdmi_helper_funcs); intel_encoder->get_hw_state = intel_ddi_get_hw_state;
drm_encoder_helper_add(&intel_encoder->base,
&intel_hdmi_helper_funcs_hsw);
} else {
intel_encoder->enable = intel_enable_hdmi;
intel_encoder->disable = intel_disable_hdmi;
intel_encoder->get_hw_state = intel_hdmi_get_hw_state;
drm_encoder_helper_add(&intel_encoder->base,
&intel_hdmi_helper_funcs);
}
intel_connector->get_hw_state = intel_connector_get_hw_state;
intel_hdmi_add_properties(intel_hdmi, connector); intel_hdmi_add_properties(intel_hdmi, connector);

View File

@ -65,13 +65,40 @@ static struct intel_lvds *intel_attached_lvds(struct drm_connector *connector)
struct intel_lvds, base); struct intel_lvds, base);
} }
static bool intel_lvds_get_hw_state(struct intel_encoder *encoder,
enum pipe *pipe)
{
struct drm_device *dev = encoder->base.dev;
struct drm_i915_private *dev_priv = dev->dev_private;
u32 lvds_reg, tmp;
if (HAS_PCH_SPLIT(dev)) {
lvds_reg = PCH_LVDS;
} else {
lvds_reg = LVDS;
}
tmp = I915_READ(lvds_reg);
if (!(tmp & LVDS_PORT_EN))
return false;
if (HAS_PCH_CPT(dev))
*pipe = PORT_TO_PIPE_CPT(tmp);
else
*pipe = PORT_TO_PIPE(tmp);
return true;
}
/** /**
* Sets the power state for the panel. * Sets the power state for the panel.
*/ */
static void intel_lvds_enable(struct intel_lvds *intel_lvds) static void intel_enable_lvds(struct intel_encoder *encoder)
{ {
struct drm_device *dev = intel_lvds->base.base.dev; struct drm_device *dev = encoder->base.dev;
struct intel_crtc *intel_crtc = to_intel_crtc(intel_lvds->base.base.crtc); struct intel_lvds *intel_lvds = to_intel_lvds(&encoder->base);
struct intel_crtc *intel_crtc = to_intel_crtc(encoder->base.crtc);
struct drm_i915_private *dev_priv = dev->dev_private; struct drm_i915_private *dev_priv = dev->dev_private;
u32 ctl_reg, lvds_reg, stat_reg; u32 ctl_reg, lvds_reg, stat_reg;
@ -111,9 +138,10 @@ static void intel_lvds_enable(struct intel_lvds *intel_lvds)
intel_panel_enable_backlight(dev, intel_crtc->pipe); intel_panel_enable_backlight(dev, intel_crtc->pipe);
} }
static void intel_lvds_disable(struct intel_lvds *intel_lvds) static void intel_disable_lvds(struct intel_encoder *encoder)
{ {
struct drm_device *dev = intel_lvds->base.base.dev; struct drm_device *dev = encoder->base.dev;
struct intel_lvds *intel_lvds = to_intel_lvds(&encoder->base);
struct drm_i915_private *dev_priv = dev->dev_private; struct drm_i915_private *dev_priv = dev->dev_private;
u32 ctl_reg, lvds_reg, stat_reg; u32 ctl_reg, lvds_reg, stat_reg;
@ -142,18 +170,6 @@ static void intel_lvds_disable(struct intel_lvds *intel_lvds)
POSTING_READ(lvds_reg); POSTING_READ(lvds_reg);
} }
static void intel_lvds_dpms(struct drm_encoder *encoder, int mode)
{
struct intel_lvds *intel_lvds = to_intel_lvds(encoder);
if (mode == DRM_MODE_DPMS_ON)
intel_lvds_enable(intel_lvds);
else
intel_lvds_disable(intel_lvds);
/* XXX: We never power down the LVDS pairs. */
}
static int intel_lvds_mode_valid(struct drm_connector *connector, static int intel_lvds_mode_valid(struct drm_connector *connector,
struct drm_display_mode *mode) struct drm_display_mode *mode)
{ {
@ -234,9 +250,8 @@ static bool intel_lvds_mode_fixup(struct drm_encoder *encoder,
{ {
struct drm_device *dev = encoder->dev; struct drm_device *dev = encoder->dev;
struct drm_i915_private *dev_priv = dev->dev_private; struct drm_i915_private *dev_priv = dev->dev_private;
struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc);
struct intel_lvds *intel_lvds = to_intel_lvds(encoder); struct intel_lvds *intel_lvds = to_intel_lvds(encoder);
struct intel_encoder *tmp_encoder; struct intel_crtc *intel_crtc = intel_lvds->base.new_crtc;
u32 pfit_control = 0, pfit_pgm_ratios = 0, border = 0; u32 pfit_control = 0, pfit_pgm_ratios = 0, border = 0;
int pipe; int pipe;
@ -246,14 +261,8 @@ static bool intel_lvds_mode_fixup(struct drm_encoder *encoder,
return false; return false;
} }
/* Should never happen!! */ if (intel_encoder_check_is_cloned(&intel_lvds->base))
for_each_encoder_on_crtc(dev, encoder->crtc, tmp_encoder) { return false;
if (&tmp_encoder->base != encoder) {
DRM_ERROR("Can't enable LVDS and another "
"encoder on the same pipe\n");
return false;
}
}
/* /*
* We have timings from the BIOS for the panel, put them in * We have timings from the BIOS for the panel, put them in
@ -405,23 +414,6 @@ static bool intel_lvds_mode_fixup(struct drm_encoder *encoder,
return true; return true;
} }
static void intel_lvds_prepare(struct drm_encoder *encoder)
{
struct intel_lvds *intel_lvds = to_intel_lvds(encoder);
intel_lvds_disable(intel_lvds);
}
static void intel_lvds_commit(struct drm_encoder *encoder)
{
struct intel_lvds *intel_lvds = to_intel_lvds(encoder);
/* Always do a full power on as we do not know what state
* we were left in.
*/
intel_lvds_enable(intel_lvds);
}
static void intel_lvds_mode_set(struct drm_encoder *encoder, static void intel_lvds_mode_set(struct drm_encoder *encoder,
struct drm_display_mode *mode, struct drm_display_mode *mode,
struct drm_display_mode *adjusted_mode) struct drm_display_mode *adjusted_mode)
@ -535,7 +527,7 @@ static int intel_lid_notify(struct notifier_block *nb, unsigned long val,
dev_priv->modeset_on_lid = 0; dev_priv->modeset_on_lid = 0;
mutex_lock(&dev->mode_config.mutex); mutex_lock(&dev->mode_config.mutex);
drm_helper_resume_force_mode(dev); intel_modeset_check_state(dev);
mutex_unlock(&dev->mode_config.mutex); mutex_unlock(&dev->mode_config.mutex);
return NOTIFY_OK; return NOTIFY_OK;
@ -587,8 +579,8 @@ static int intel_lvds_set_property(struct drm_connector *connector,
* If the CRTC is enabled, the display will be changed * If the CRTC is enabled, the display will be changed
* according to the new panel fitting mode. * according to the new panel fitting mode.
*/ */
drm_crtc_helper_set_mode(crtc, &crtc->mode, intel_set_mode(crtc, &crtc->mode,
crtc->x, crtc->y, crtc->fb); crtc->x, crtc->y, crtc->fb);
} }
} }
@ -596,11 +588,9 @@ static int intel_lvds_set_property(struct drm_connector *connector,
} }
static const struct drm_encoder_helper_funcs intel_lvds_helper_funcs = { static const struct drm_encoder_helper_funcs intel_lvds_helper_funcs = {
.dpms = intel_lvds_dpms,
.mode_fixup = intel_lvds_mode_fixup, .mode_fixup = intel_lvds_mode_fixup,
.prepare = intel_lvds_prepare,
.mode_set = intel_lvds_mode_set, .mode_set = intel_lvds_mode_set,
.commit = intel_lvds_commit, .disable = intel_encoder_noop,
}; };
static const struct drm_connector_helper_funcs intel_lvds_connector_helper_funcs = { static const struct drm_connector_helper_funcs intel_lvds_connector_helper_funcs = {
@ -610,7 +600,7 @@ static const struct drm_connector_helper_funcs intel_lvds_connector_helper_funcs
}; };
static const struct drm_connector_funcs intel_lvds_connector_funcs = { static const struct drm_connector_funcs intel_lvds_connector_funcs = {
.dpms = drm_helper_connector_dpms, .dpms = intel_connector_dpms,
.detect = intel_lvds_detect, .detect = intel_lvds_detect,
.fill_modes = drm_helper_probe_single_connector_modes, .fill_modes = drm_helper_probe_single_connector_modes,
.set_property = intel_lvds_set_property, .set_property = intel_lvds_set_property,
@ -964,6 +954,11 @@ bool intel_lvds_init(struct drm_device *dev)
drm_encoder_init(dev, &intel_encoder->base, &intel_lvds_enc_funcs, drm_encoder_init(dev, &intel_encoder->base, &intel_lvds_enc_funcs,
DRM_MODE_ENCODER_LVDS); DRM_MODE_ENCODER_LVDS);
intel_encoder->enable = intel_enable_lvds;
intel_encoder->disable = intel_disable_lvds;
intel_encoder->get_hw_state = intel_lvds_get_hw_state;
intel_connector->get_hw_state = intel_connector_get_hw_state;
intel_connector_attach_encoder(intel_connector, intel_encoder); intel_connector_attach_encoder(intel_connector, intel_encoder);
intel_encoder->type = INTEL_OUTPUT_LVDS; intel_encoder->type = INTEL_OUTPUT_LVDS;

View File

@ -31,6 +31,8 @@
#include "../../../platform/x86/intel_ips.h" #include "../../../platform/x86/intel_ips.h"
#include <linux/module.h> #include <linux/module.h>
#define FORCEWAKE_ACK_TIMEOUT_MS 2
/* FBC, or Frame Buffer Compression, is a technique employed to compress the /* FBC, or Frame Buffer Compression, is a technique employed to compress the
* framebuffer contents in-memory, aiming at reducing the required bandwidth * framebuffer contents in-memory, aiming at reducing the required bandwidth
* during in-memory transfers and, therefore, reduce the power packet. * during in-memory transfers and, therefore, reduce the power packet.
@ -593,7 +595,7 @@ static void i915_ironlake_get_mem_freq(struct drm_device *dev)
break; break;
} }
dev_priv->r_t = dev_priv->mem_freq; dev_priv->ips.r_t = dev_priv->mem_freq;
switch (csipll & 0x3ff) { switch (csipll & 0x3ff) {
case 0x00c: case 0x00c:
@ -625,11 +627,11 @@ static void i915_ironlake_get_mem_freq(struct drm_device *dev)
} }
if (dev_priv->fsb_freq == 3200) { if (dev_priv->fsb_freq == 3200) {
dev_priv->c_m = 0; dev_priv->ips.c_m = 0;
} else if (dev_priv->fsb_freq > 3200 && dev_priv->fsb_freq <= 4800) { } else if (dev_priv->fsb_freq > 3200 && dev_priv->fsb_freq <= 4800) {
dev_priv->c_m = 1; dev_priv->ips.c_m = 1;
} else { } else {
dev_priv->c_m = 2; dev_priv->ips.c_m = 2;
} }
} }
@ -2162,12 +2164,6 @@ intel_alloc_context_page(struct drm_device *dev)
/** /**
* Lock protecting IPS related data structures * Lock protecting IPS related data structures
* - i915_mch_dev
* - dev_priv->max_delay
* - dev_priv->min_delay
* - dev_priv->fmax
* - dev_priv->gpu_busy
* - dev_priv->gfx_power
*/ */
DEFINE_SPINLOCK(mchdev_lock); DEFINE_SPINLOCK(mchdev_lock);
@ -2230,12 +2226,12 @@ static void ironlake_enable_drps(struct drm_device *dev)
vstart = (I915_READ(PXVFREQ_BASE + (fstart * 4)) & PXVFREQ_PX_MASK) >> vstart = (I915_READ(PXVFREQ_BASE + (fstart * 4)) & PXVFREQ_PX_MASK) >>
PXVFREQ_PX_SHIFT; PXVFREQ_PX_SHIFT;
dev_priv->fmax = fmax; /* IPS callback will increase this */ dev_priv->ips.fmax = fmax; /* IPS callback will increase this */
dev_priv->fstart = fstart; dev_priv->ips.fstart = fstart;
dev_priv->max_delay = fstart; dev_priv->ips.max_delay = fstart;
dev_priv->min_delay = fmin; dev_priv->ips.min_delay = fmin;
dev_priv->cur_delay = fstart; dev_priv->ips.cur_delay = fstart;
DRM_DEBUG_DRIVER("fmax: %d, fmin: %d, fstart: %d\n", DRM_DEBUG_DRIVER("fmax: %d, fmin: %d, fstart: %d\n",
fmax, fmin, fstart); fmax, fmin, fstart);
@ -2258,11 +2254,11 @@ static void ironlake_enable_drps(struct drm_device *dev)
ironlake_set_drps(dev, fstart); ironlake_set_drps(dev, fstart);
dev_priv->last_count1 = I915_READ(0x112e4) + I915_READ(0x112e8) + dev_priv->ips.last_count1 = I915_READ(0x112e4) + I915_READ(0x112e8) +
I915_READ(0x112e0); I915_READ(0x112e0);
dev_priv->last_time1 = jiffies_to_msecs(jiffies); dev_priv->ips.last_time1 = jiffies_to_msecs(jiffies);
dev_priv->last_count2 = I915_READ(0x112f4); dev_priv->ips.last_count2 = I915_READ(0x112f4);
getrawmonotonic(&dev_priv->last_time2); getrawmonotonic(&dev_priv->ips.last_time2);
spin_unlock_irq(&mchdev_lock); spin_unlock_irq(&mchdev_lock);
} }
@ -2284,7 +2280,7 @@ static void ironlake_disable_drps(struct drm_device *dev)
I915_WRITE(DEIMR, I915_READ(DEIMR) | DE_PCU_EVENT); I915_WRITE(DEIMR, I915_READ(DEIMR) | DE_PCU_EVENT);
/* Go back to the starting frequency */ /* Go back to the starting frequency */
ironlake_set_drps(dev, dev_priv->fstart); ironlake_set_drps(dev, dev_priv->ips.fstart);
mdelay(1); mdelay(1);
rgvswctl |= MEMCTL_CMD_STS; rgvswctl |= MEMCTL_CMD_STS;
I915_WRITE(MEMSWCTL, rgvswctl); I915_WRITE(MEMSWCTL, rgvswctl);
@ -2343,6 +2339,8 @@ void gen6_set_rps(struct drm_device *dev, u8 val)
I915_WRITE(GEN6_RP_INTERRUPT_LIMITS, limits); I915_WRITE(GEN6_RP_INTERRUPT_LIMITS, limits);
dev_priv->rps.cur_delay = val; dev_priv->rps.cur_delay = val;
trace_intel_gpu_freq_change(val * 50);
} }
static void gen6_disable_rps(struct drm_device *dev) static void gen6_disable_rps(struct drm_device *dev)
@ -2741,7 +2739,7 @@ unsigned long i915_chipset_val(struct drm_i915_private *dev_priv)
assert_spin_locked(&mchdev_lock); assert_spin_locked(&mchdev_lock);
diff1 = now - dev_priv->last_time1; diff1 = now - dev_priv->ips.last_time1;
/* Prevent division-by-zero if we are asking too fast. /* Prevent division-by-zero if we are asking too fast.
* Also, we don't get interesting results if we are polling * Also, we don't get interesting results if we are polling
@ -2749,7 +2747,7 @@ unsigned long i915_chipset_val(struct drm_i915_private *dev_priv)
* in such cases. * in such cases.
*/ */
if (diff1 <= 10) if (diff1 <= 10)
return dev_priv->chipset_power; return dev_priv->ips.chipset_power;
count1 = I915_READ(DMIEC); count1 = I915_READ(DMIEC);
count2 = I915_READ(DDREC); count2 = I915_READ(DDREC);
@ -2758,16 +2756,16 @@ unsigned long i915_chipset_val(struct drm_i915_private *dev_priv)
total_count = count1 + count2 + count3; total_count = count1 + count2 + count3;
/* FIXME: handle per-counter overflow */ /* FIXME: handle per-counter overflow */
if (total_count < dev_priv->last_count1) { if (total_count < dev_priv->ips.last_count1) {
diff = ~0UL - dev_priv->last_count1; diff = ~0UL - dev_priv->ips.last_count1;
diff += total_count; diff += total_count;
} else { } else {
diff = total_count - dev_priv->last_count1; diff = total_count - dev_priv->ips.last_count1;
} }
for (i = 0; i < ARRAY_SIZE(cparams); i++) { for (i = 0; i < ARRAY_SIZE(cparams); i++) {
if (cparams[i].i == dev_priv->c_m && if (cparams[i].i == dev_priv->ips.c_m &&
cparams[i].t == dev_priv->r_t) { cparams[i].t == dev_priv->ips.r_t) {
m = cparams[i].m; m = cparams[i].m;
c = cparams[i].c; c = cparams[i].c;
break; break;
@ -2778,10 +2776,10 @@ unsigned long i915_chipset_val(struct drm_i915_private *dev_priv)
ret = ((m * diff) + c); ret = ((m * diff) + c);
ret = div_u64(ret, 10); ret = div_u64(ret, 10);
dev_priv->last_count1 = total_count; dev_priv->ips.last_count1 = total_count;
dev_priv->last_time1 = now; dev_priv->ips.last_time1 = now;
dev_priv->chipset_power = ret; dev_priv->ips.chipset_power = ret;
return ret; return ret;
} }
@ -2952,7 +2950,7 @@ static void __i915_update_gfx_val(struct drm_i915_private *dev_priv)
assert_spin_locked(&mchdev_lock); assert_spin_locked(&mchdev_lock);
getrawmonotonic(&now); getrawmonotonic(&now);
diff1 = timespec_sub(now, dev_priv->last_time2); diff1 = timespec_sub(now, dev_priv->ips.last_time2);
/* Don't divide by 0 */ /* Don't divide by 0 */
diffms = diff1.tv_sec * 1000 + diff1.tv_nsec / 1000000; diffms = diff1.tv_sec * 1000 + diff1.tv_nsec / 1000000;
@ -2961,20 +2959,20 @@ static void __i915_update_gfx_val(struct drm_i915_private *dev_priv)
count = I915_READ(GFXEC); count = I915_READ(GFXEC);
if (count < dev_priv->last_count2) { if (count < dev_priv->ips.last_count2) {
diff = ~0UL - dev_priv->last_count2; diff = ~0UL - dev_priv->ips.last_count2;
diff += count; diff += count;
} else { } else {
diff = count - dev_priv->last_count2; diff = count - dev_priv->ips.last_count2;
} }
dev_priv->last_count2 = count; dev_priv->ips.last_count2 = count;
dev_priv->last_time2 = now; dev_priv->ips.last_time2 = now;
/* More magic constants... */ /* More magic constants... */
diff = diff * 1181; diff = diff * 1181;
diff = div_u64(diff, diffms * 10); diff = div_u64(diff, diffms * 10);
dev_priv->gfx_power = diff; dev_priv->ips.gfx_power = diff;
} }
void i915_update_gfx_val(struct drm_i915_private *dev_priv) void i915_update_gfx_val(struct drm_i915_private *dev_priv)
@ -3016,14 +3014,14 @@ unsigned long i915_gfx_val(struct drm_i915_private *dev_priv)
corr = corr * ((150142 * state1) / 10000 - 78642); corr = corr * ((150142 * state1) / 10000 - 78642);
corr /= 100000; corr /= 100000;
corr2 = (corr * dev_priv->corr); corr2 = (corr * dev_priv->ips.corr);
state2 = (corr2 * state1) / 10000; state2 = (corr2 * state1) / 10000;
state2 /= 100; /* convert to mW */ state2 /= 100; /* convert to mW */
__i915_update_gfx_val(dev_priv); __i915_update_gfx_val(dev_priv);
return dev_priv->gfx_power + state2; return dev_priv->ips.gfx_power + state2;
} }
/** /**
@ -3071,8 +3069,8 @@ bool i915_gpu_raise(void)
} }
dev_priv = i915_mch_dev; dev_priv = i915_mch_dev;
if (dev_priv->max_delay > dev_priv->fmax) if (dev_priv->ips.max_delay > dev_priv->ips.fmax)
dev_priv->max_delay--; dev_priv->ips.max_delay--;
out_unlock: out_unlock:
spin_unlock_irq(&mchdev_lock); spin_unlock_irq(&mchdev_lock);
@ -3099,8 +3097,8 @@ bool i915_gpu_lower(void)
} }
dev_priv = i915_mch_dev; dev_priv = i915_mch_dev;
if (dev_priv->max_delay < dev_priv->min_delay) if (dev_priv->ips.max_delay < dev_priv->ips.min_delay)
dev_priv->max_delay++; dev_priv->ips.max_delay++;
out_unlock: out_unlock:
spin_unlock_irq(&mchdev_lock); spin_unlock_irq(&mchdev_lock);
@ -3154,9 +3152,9 @@ bool i915_gpu_turbo_disable(void)
} }
dev_priv = i915_mch_dev; dev_priv = i915_mch_dev;
dev_priv->max_delay = dev_priv->fstart; dev_priv->ips.max_delay = dev_priv->ips.fstart;
if (!ironlake_set_drps(dev_priv->dev, dev_priv->fstart)) if (!ironlake_set_drps(dev_priv->dev, dev_priv->ips.fstart))
ret = false; ret = false;
out_unlock: out_unlock:
@ -3271,7 +3269,7 @@ static void intel_init_emon(struct drm_device *dev)
lcfuse = I915_READ(LCFUSE02); lcfuse = I915_READ(LCFUSE02);
dev_priv->corr = (lcfuse & LCFUSE_HIV_MASK); dev_priv->ips.corr = (lcfuse & LCFUSE_HIV_MASK);
} }
void intel_disable_gt_powersave(struct drm_device *dev) void intel_disable_gt_powersave(struct drm_device *dev)
@ -3966,14 +3964,16 @@ static void __gen6_gt_force_wake_get(struct drm_i915_private *dev_priv)
else else
forcewake_ack = FORCEWAKE_ACK; forcewake_ack = FORCEWAKE_ACK;
if (wait_for_atomic_us((I915_READ_NOTRACE(forcewake_ack) & 1) == 0, 500)) if (wait_for_atomic((I915_READ_NOTRACE(forcewake_ack) & 1) == 0,
DRM_ERROR("Force wake wait timed out\n"); FORCEWAKE_ACK_TIMEOUT_MS))
DRM_ERROR("Timed out waiting for forcewake old ack to clear.\n");
I915_WRITE_NOTRACE(FORCEWAKE, 1); I915_WRITE_NOTRACE(FORCEWAKE, 1);
POSTING_READ(FORCEWAKE); POSTING_READ(ECOBUS); /* something from same cacheline, but !FORCEWAKE */
if (wait_for_atomic_us((I915_READ_NOTRACE(forcewake_ack) & 1), 500)) if (wait_for_atomic((I915_READ_NOTRACE(forcewake_ack) & 1),
DRM_ERROR("Force wake wait timed out\n"); FORCEWAKE_ACK_TIMEOUT_MS))
DRM_ERROR("Timed out waiting for forcewake to ack request.\n");
__gen6_gt_wait_for_thread_c0(dev_priv); __gen6_gt_wait_for_thread_c0(dev_priv);
} }
@ -3987,14 +3987,16 @@ static void __gen6_gt_force_wake_mt_get(struct drm_i915_private *dev_priv)
else else
forcewake_ack = FORCEWAKE_MT_ACK; forcewake_ack = FORCEWAKE_MT_ACK;
if (wait_for_atomic_us((I915_READ_NOTRACE(forcewake_ack) & 1) == 0, 500)) if (wait_for_atomic((I915_READ_NOTRACE(forcewake_ack) & 1) == 0,
DRM_ERROR("Force wake wait timed out\n"); FORCEWAKE_ACK_TIMEOUT_MS))
DRM_ERROR("Timed out waiting for forcewake old ack to clear.\n");
I915_WRITE_NOTRACE(FORCEWAKE_MT, _MASKED_BIT_ENABLE(1)); I915_WRITE_NOTRACE(FORCEWAKE_MT, _MASKED_BIT_ENABLE(1));
POSTING_READ(FORCEWAKE_MT); POSTING_READ(ECOBUS); /* something from same cacheline, but !FORCEWAKE */
if (wait_for_atomic_us((I915_READ_NOTRACE(forcewake_ack) & 1), 500)) if (wait_for_atomic((I915_READ_NOTRACE(forcewake_ack) & 1),
DRM_ERROR("Force wake wait timed out\n"); FORCEWAKE_ACK_TIMEOUT_MS))
DRM_ERROR("Timed out waiting for forcewake to ack request.\n");
__gen6_gt_wait_for_thread_c0(dev_priv); __gen6_gt_wait_for_thread_c0(dev_priv);
} }
@ -4027,14 +4029,14 @@ void gen6_gt_check_fifodbg(struct drm_i915_private *dev_priv)
static void __gen6_gt_force_wake_put(struct drm_i915_private *dev_priv) static void __gen6_gt_force_wake_put(struct drm_i915_private *dev_priv)
{ {
I915_WRITE_NOTRACE(FORCEWAKE, 0); I915_WRITE_NOTRACE(FORCEWAKE, 0);
POSTING_READ(FORCEWAKE); /* gen6_gt_check_fifodbg doubles as the POSTING_READ */
gen6_gt_check_fifodbg(dev_priv); gen6_gt_check_fifodbg(dev_priv);
} }
static void __gen6_gt_force_wake_mt_put(struct drm_i915_private *dev_priv) static void __gen6_gt_force_wake_mt_put(struct drm_i915_private *dev_priv)
{ {
I915_WRITE_NOTRACE(FORCEWAKE_MT, _MASKED_BIT_DISABLE(1)); I915_WRITE_NOTRACE(FORCEWAKE_MT, _MASKED_BIT_DISABLE(1));
POSTING_READ(FORCEWAKE_MT); /* gen6_gt_check_fifodbg doubles as the POSTING_READ */
gen6_gt_check_fifodbg(dev_priv); gen6_gt_check_fifodbg(dev_priv);
} }
@ -4073,24 +4075,24 @@ int __gen6_gt_wait_for_fifo(struct drm_i915_private *dev_priv)
static void vlv_force_wake_get(struct drm_i915_private *dev_priv) static void vlv_force_wake_get(struct drm_i915_private *dev_priv)
{ {
/* Already awake? */ if (wait_for_atomic((I915_READ_NOTRACE(FORCEWAKE_ACK_VLV) & 1) == 0,
if ((I915_READ(0x130094) & 0xa1) == 0xa1) FORCEWAKE_ACK_TIMEOUT_MS))
return; DRM_ERROR("Timed out waiting for forcewake old ack to clear.\n");
I915_WRITE_NOTRACE(FORCEWAKE_VLV, 0xffffffff); I915_WRITE_NOTRACE(FORCEWAKE_VLV, _MASKED_BIT_ENABLE(1));
POSTING_READ(FORCEWAKE_VLV);
if (wait_for_atomic_us((I915_READ_NOTRACE(FORCEWAKE_ACK_VLV) & 1), 500)) if (wait_for_atomic((I915_READ_NOTRACE(FORCEWAKE_ACK_VLV) & 1),
DRM_ERROR("Force wake wait timed out\n"); FORCEWAKE_ACK_TIMEOUT_MS))
DRM_ERROR("Timed out waiting for forcewake to ack request.\n");
__gen6_gt_wait_for_thread_c0(dev_priv); __gen6_gt_wait_for_thread_c0(dev_priv);
} }
static void vlv_force_wake_put(struct drm_i915_private *dev_priv) static void vlv_force_wake_put(struct drm_i915_private *dev_priv)
{ {
I915_WRITE_NOTRACE(FORCEWAKE_VLV, 0xffff0000); I915_WRITE_NOTRACE(FORCEWAKE_VLV, _MASKED_BIT_DISABLE(1));
/* FIXME: confirm VLV behavior with Punit folks */ /* The below doubles as a POSTING_READ */
POSTING_READ(FORCEWAKE_VLV); gen6_gt_check_fifodbg(dev_priv);
} }
void intel_gt_init(struct drm_device *dev) void intel_gt_init(struct drm_device *dev)

View File

@ -218,6 +218,11 @@ gen6_render_ring_flush(struct intel_ring_buffer *ring,
u32 scratch_addr = pc->gtt_offset + 128; u32 scratch_addr = pc->gtt_offset + 128;
int ret; int ret;
/* Force SNB workarounds for PIPE_CONTROL flushes */
ret = intel_emit_post_sync_nonzero_flush(ring);
if (ret)
return ret;
/* Just flush everything. Experiments have shown that reducing the /* Just flush everything. Experiments have shown that reducing the
* number of bits based on the write domains has little performance * number of bits based on the write domains has little performance
* impact. * impact.
@ -258,17 +263,80 @@ gen6_render_ring_flush(struct intel_ring_buffer *ring,
} }
static int static int
gen6_render_ring_flush__wa(struct intel_ring_buffer *ring, gen7_render_ring_cs_stall_wa(struct intel_ring_buffer *ring)
u32 invalidate_domains, u32 flush_domains)
{ {
int ret; int ret;
/* Force SNB workarounds for PIPE_CONTROL flushes */ ret = intel_ring_begin(ring, 4);
ret = intel_emit_post_sync_nonzero_flush(ring);
if (ret) if (ret)
return ret; return ret;
return gen6_render_ring_flush(ring, invalidate_domains, flush_domains); intel_ring_emit(ring, GFX_OP_PIPE_CONTROL(4));
intel_ring_emit(ring, PIPE_CONTROL_CS_STALL |
PIPE_CONTROL_STALL_AT_SCOREBOARD);
intel_ring_emit(ring, 0);
intel_ring_emit(ring, 0);
intel_ring_advance(ring);
return 0;
}
static int
gen7_render_ring_flush(struct intel_ring_buffer *ring,
u32 invalidate_domains, u32 flush_domains)
{
u32 flags = 0;
struct pipe_control *pc = ring->private;
u32 scratch_addr = pc->gtt_offset + 128;
int ret;
/*
* Ensure that any following seqno writes only happen when the render
* cache is indeed flushed.
*
* Workaround: 4th PIPE_CONTROL command (except the ones with only
* read-cache invalidate bits set) must have the CS_STALL bit set. We
* don't try to be clever and just set it unconditionally.
*/
flags |= PIPE_CONTROL_CS_STALL;
/* Just flush everything. Experiments have shown that reducing the
* number of bits based on the write domains has little performance
* impact.
*/
if (flush_domains) {
flags |= PIPE_CONTROL_RENDER_TARGET_CACHE_FLUSH;
flags |= PIPE_CONTROL_DEPTH_CACHE_FLUSH;
}
if (invalidate_domains) {
flags |= PIPE_CONTROL_TLB_INVALIDATE;
flags |= PIPE_CONTROL_INSTRUCTION_CACHE_INVALIDATE;
flags |= PIPE_CONTROL_TEXTURE_CACHE_INVALIDATE;
flags |= PIPE_CONTROL_VF_CACHE_INVALIDATE;
flags |= PIPE_CONTROL_CONST_CACHE_INVALIDATE;
flags |= PIPE_CONTROL_STATE_CACHE_INVALIDATE;
/*
* TLB invalidate requires a post-sync write.
*/
flags |= PIPE_CONTROL_QW_WRITE;
/* Workaround: we must issue a pipe_control with CS-stall bit
* set before a pipe_control command that has the state cache
* invalidate bit set. */
gen7_render_ring_cs_stall_wa(ring);
}
ret = intel_ring_begin(ring, 4);
if (ret)
return ret;
intel_ring_emit(ring, GFX_OP_PIPE_CONTROL(4));
intel_ring_emit(ring, flags);
intel_ring_emit(ring, scratch_addr | PIPE_CONTROL_GLOBAL_GTT);
intel_ring_emit(ring, 0);
intel_ring_advance(ring);
return 0;
} }
static void ring_write_tail(struct intel_ring_buffer *ring, static void ring_write_tail(struct intel_ring_buffer *ring,
@ -1385,9 +1453,9 @@ int intel_init_render_ring_buffer(struct drm_device *dev)
if (INTEL_INFO(dev)->gen >= 6) { if (INTEL_INFO(dev)->gen >= 6) {
ring->add_request = gen6_add_request; ring->add_request = gen6_add_request;
ring->flush = gen6_render_ring_flush; ring->flush = gen7_render_ring_flush;
if (INTEL_INFO(dev)->gen == 6) if (INTEL_INFO(dev)->gen == 6)
ring->flush = gen6_render_ring_flush__wa; ring->flush = gen6_render_ring_flush;
ring->irq_get = gen6_ring_get_irq; ring->irq_get = gen6_ring_get_irq;
ring->irq_put = gen6_ring_put_irq; ring->irq_put = gen6_ring_put_irq;
ring->irq_enable_mask = GT_USER_INTERRUPT; ring->irq_enable_mask = GT_USER_INTERRUPT;

View File

@ -97,7 +97,7 @@ struct intel_sdvo {
/* /*
* Hotplug activation bits for this device * Hotplug activation bits for this device
*/ */
uint8_t hotplug_active[2]; uint16_t hotplug_active;
/** /**
* This is used to select the color range of RBG outputs in HDMI mode. * This is used to select the color range of RBG outputs in HDMI mode.
@ -628,6 +628,14 @@ static bool intel_sdvo_set_active_outputs(struct intel_sdvo *intel_sdvo,
&outputs, sizeof(outputs)); &outputs, sizeof(outputs));
} }
static bool intel_sdvo_get_active_outputs(struct intel_sdvo *intel_sdvo,
u16 *outputs)
{
return intel_sdvo_get_value(intel_sdvo,
SDVO_CMD_GET_ACTIVE_OUTPUTS,
outputs, sizeof(*outputs));
}
static bool intel_sdvo_set_encoder_power_state(struct intel_sdvo *intel_sdvo, static bool intel_sdvo_set_encoder_power_state(struct intel_sdvo *intel_sdvo,
int mode) int mode)
{ {
@ -1142,51 +1150,132 @@ static void intel_sdvo_mode_set(struct drm_encoder *encoder,
intel_sdvo_write_sdvox(intel_sdvo, sdvox); intel_sdvo_write_sdvox(intel_sdvo, sdvox);
} }
static void intel_sdvo_dpms(struct drm_encoder *encoder, int mode) static bool intel_sdvo_connector_get_hw_state(struct intel_connector *connector)
{ {
struct drm_device *dev = encoder->dev; struct intel_sdvo_connector *intel_sdvo_connector =
to_intel_sdvo_connector(&connector->base);
struct intel_sdvo *intel_sdvo = intel_attached_sdvo(&connector->base);
u16 active_outputs;
intel_sdvo_get_active_outputs(intel_sdvo, &active_outputs);
if (active_outputs & intel_sdvo_connector->output_flag)
return true;
else
return false;
}
static bool intel_sdvo_get_hw_state(struct intel_encoder *encoder,
enum pipe *pipe)
{
struct drm_device *dev = encoder->base.dev;
struct drm_i915_private *dev_priv = dev->dev_private; struct drm_i915_private *dev_priv = dev->dev_private;
struct intel_sdvo *intel_sdvo = to_intel_sdvo(encoder); struct intel_sdvo *intel_sdvo = to_intel_sdvo(&encoder->base);
struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc); u32 tmp;
tmp = I915_READ(intel_sdvo->sdvo_reg);
if (!(tmp & SDVO_ENABLE))
return false;
if (HAS_PCH_CPT(dev))
*pipe = PORT_TO_PIPE_CPT(tmp);
else
*pipe = PORT_TO_PIPE(tmp);
return true;
}
static void intel_disable_sdvo(struct intel_encoder *encoder)
{
struct drm_i915_private *dev_priv = encoder->base.dev->dev_private;
struct intel_sdvo *intel_sdvo = to_intel_sdvo(&encoder->base);
u32 temp; u32 temp;
intel_sdvo_set_active_outputs(intel_sdvo, 0);
if (0)
intel_sdvo_set_encoder_power_state(intel_sdvo,
DRM_MODE_DPMS_OFF);
temp = I915_READ(intel_sdvo->sdvo_reg);
if ((temp & SDVO_ENABLE) != 0) {
intel_sdvo_write_sdvox(intel_sdvo, temp & ~SDVO_ENABLE);
}
}
static void intel_enable_sdvo(struct intel_encoder *encoder)
{
struct drm_device *dev = encoder->base.dev;
struct drm_i915_private *dev_priv = dev->dev_private;
struct intel_sdvo *intel_sdvo = to_intel_sdvo(&encoder->base);
struct intel_crtc *intel_crtc = to_intel_crtc(encoder->base.crtc);
u32 temp;
bool input1, input2;
int i;
u8 status;
temp = I915_READ(intel_sdvo->sdvo_reg);
if ((temp & SDVO_ENABLE) == 0)
intel_sdvo_write_sdvox(intel_sdvo, temp | SDVO_ENABLE);
for (i = 0; i < 2; i++)
intel_wait_for_vblank(dev, intel_crtc->pipe);
status = intel_sdvo_get_trained_inputs(intel_sdvo, &input1, &input2);
/* Warn if the device reported failure to sync.
* A lot of SDVO devices fail to notify of sync, but it's
* a given it the status is a success, we succeeded.
*/
if (status == SDVO_CMD_STATUS_SUCCESS && !input1) {
DRM_DEBUG_KMS("First %s output reported failure to "
"sync\n", SDVO_NAME(intel_sdvo));
}
if (0)
intel_sdvo_set_encoder_power_state(intel_sdvo,
DRM_MODE_DPMS_ON);
intel_sdvo_set_active_outputs(intel_sdvo, intel_sdvo->attached_output);
}
static void intel_sdvo_dpms(struct drm_connector *connector, int mode)
{
struct drm_crtc *crtc;
struct intel_sdvo *intel_sdvo = intel_attached_sdvo(connector);
/* dvo supports only 2 dpms states. */
if (mode != DRM_MODE_DPMS_ON)
mode = DRM_MODE_DPMS_OFF;
if (mode == connector->dpms)
return;
connector->dpms = mode;
/* Only need to change hw state when actually enabled */
crtc = intel_sdvo->base.base.crtc;
if (!crtc) {
intel_sdvo->base.connectors_active = false;
return;
}
if (mode != DRM_MODE_DPMS_ON) { if (mode != DRM_MODE_DPMS_ON) {
intel_sdvo_set_active_outputs(intel_sdvo, 0); intel_sdvo_set_active_outputs(intel_sdvo, 0);
if (0) if (0)
intel_sdvo_set_encoder_power_state(intel_sdvo, mode); intel_sdvo_set_encoder_power_state(intel_sdvo, mode);
if (mode == DRM_MODE_DPMS_OFF) { intel_sdvo->base.connectors_active = false;
temp = I915_READ(intel_sdvo->sdvo_reg);
if ((temp & SDVO_ENABLE) != 0) { intel_crtc_update_dpms(crtc);
intel_sdvo_write_sdvox(intel_sdvo, temp & ~SDVO_ENABLE);
}
}
} else { } else {
bool input1, input2; intel_sdvo->base.connectors_active = true;
int i;
u8 status;
temp = I915_READ(intel_sdvo->sdvo_reg); intel_crtc_update_dpms(crtc);
if ((temp & SDVO_ENABLE) == 0)
intel_sdvo_write_sdvox(intel_sdvo, temp | SDVO_ENABLE);
for (i = 0; i < 2; i++)
intel_wait_for_vblank(dev, intel_crtc->pipe);
status = intel_sdvo_get_trained_inputs(intel_sdvo, &input1, &input2);
/* Warn if the device reported failure to sync.
* A lot of SDVO devices fail to notify of sync, but it's
* a given it the status is a success, we succeeded.
*/
if (status == SDVO_CMD_STATUS_SUCCESS && !input1) {
DRM_DEBUG_KMS("First %s output reported failure to "
"sync\n", SDVO_NAME(intel_sdvo));
}
if (0) if (0)
intel_sdvo_set_encoder_power_state(intel_sdvo, mode); intel_sdvo_set_encoder_power_state(intel_sdvo, mode);
intel_sdvo_set_active_outputs(intel_sdvo, intel_sdvo->attached_output); intel_sdvo_set_active_outputs(intel_sdvo, intel_sdvo->attached_output);
} }
return;
intel_modeset_check_state(connector->dev);
} }
static int intel_sdvo_mode_valid(struct drm_connector *connector, static int intel_sdvo_mode_valid(struct drm_connector *connector,
@ -1251,25 +1340,29 @@ static bool intel_sdvo_get_capabilities(struct intel_sdvo *intel_sdvo, struct in
return true; return true;
} }
static int intel_sdvo_supports_hotplug(struct intel_sdvo *intel_sdvo) static uint16_t intel_sdvo_get_hotplug_support(struct intel_sdvo *intel_sdvo)
{ {
struct drm_device *dev = intel_sdvo->base.base.dev; struct drm_device *dev = intel_sdvo->base.base.dev;
u8 response[2]; uint16_t hotplug;
/* HW Erratum: SDVO Hotplug is broken on all i945G chips, there's noise /* HW Erratum: SDVO Hotplug is broken on all i945G chips, there's noise
* on the line. */ * on the line. */
if (IS_I945G(dev) || IS_I945GM(dev)) if (IS_I945G(dev) || IS_I945GM(dev))
return false; return 0;
return intel_sdvo_get_value(intel_sdvo, SDVO_CMD_GET_HOT_PLUG_SUPPORT, if (!intel_sdvo_get_value(intel_sdvo, SDVO_CMD_GET_HOT_PLUG_SUPPORT,
&response, 2) && response[0]; &hotplug, sizeof(hotplug)))
return 0;
return hotplug;
} }
static void intel_sdvo_enable_hotplug(struct intel_encoder *encoder) static void intel_sdvo_enable_hotplug(struct intel_encoder *encoder)
{ {
struct intel_sdvo *intel_sdvo = to_intel_sdvo(&encoder->base); struct intel_sdvo *intel_sdvo = to_intel_sdvo(&encoder->base);
intel_sdvo_write_cmd(intel_sdvo, SDVO_CMD_SET_ACTIVE_HOT_PLUG, &intel_sdvo->hotplug_active, 2); intel_sdvo_write_cmd(intel_sdvo, SDVO_CMD_SET_ACTIVE_HOT_PLUG,
&intel_sdvo->hotplug_active, 2);
} }
static bool static bool
@ -1834,8 +1927,8 @@ intel_sdvo_set_property(struct drm_connector *connector,
done: done:
if (intel_sdvo->base.base.crtc) { if (intel_sdvo->base.base.crtc) {
struct drm_crtc *crtc = intel_sdvo->base.base.crtc; struct drm_crtc *crtc = intel_sdvo->base.base.crtc;
drm_crtc_helper_set_mode(crtc, &crtc->mode, crtc->x, intel_set_mode(crtc, &crtc->mode,
crtc->y, crtc->fb); crtc->x, crtc->y, crtc->fb);
} }
return 0; return 0;
@ -1843,15 +1936,13 @@ intel_sdvo_set_property(struct drm_connector *connector,
} }
static const struct drm_encoder_helper_funcs intel_sdvo_helper_funcs = { static const struct drm_encoder_helper_funcs intel_sdvo_helper_funcs = {
.dpms = intel_sdvo_dpms,
.mode_fixup = intel_sdvo_mode_fixup, .mode_fixup = intel_sdvo_mode_fixup,
.prepare = intel_encoder_prepare,
.mode_set = intel_sdvo_mode_set, .mode_set = intel_sdvo_mode_set,
.commit = intel_encoder_commit, .disable = intel_encoder_noop,
}; };
static const struct drm_connector_funcs intel_sdvo_connector_funcs = { static const struct drm_connector_funcs intel_sdvo_connector_funcs = {
.dpms = drm_helper_connector_dpms, .dpms = intel_sdvo_dpms,
.detect = intel_sdvo_detect, .detect = intel_sdvo_detect,
.fill_modes = drm_helper_probe_single_connector_modes, .fill_modes = drm_helper_probe_single_connector_modes,
.set_property = intel_sdvo_set_property, .set_property = intel_sdvo_set_property,
@ -2023,6 +2114,7 @@ intel_sdvo_connector_init(struct intel_sdvo_connector *connector,
connector->base.base.interlace_allowed = 1; connector->base.base.interlace_allowed = 1;
connector->base.base.doublescan_allowed = 0; connector->base.base.doublescan_allowed = 0;
connector->base.base.display_info.subpixel_order = SubPixelHorizontalRGB; connector->base.base.display_info.subpixel_order = SubPixelHorizontalRGB;
connector->base.get_hw_state = intel_sdvo_connector_get_hw_state;
intel_connector_attach_encoder(&connector->base, &encoder->base); intel_connector_attach_encoder(&connector->base, &encoder->base);
drm_sysfs_connector_add(&connector->base.base); drm_sysfs_connector_add(&connector->base.base);
@ -2061,17 +2153,18 @@ intel_sdvo_dvi_init(struct intel_sdvo *intel_sdvo, int device)
intel_connector = &intel_sdvo_connector->base; intel_connector = &intel_sdvo_connector->base;
connector = &intel_connector->base; connector = &intel_connector->base;
if (intel_sdvo_supports_hotplug(intel_sdvo) & (1 << device)) { if (intel_sdvo_get_hotplug_support(intel_sdvo) &
intel_sdvo_connector->output_flag) {
connector->polled = DRM_CONNECTOR_POLL_HPD; connector->polled = DRM_CONNECTOR_POLL_HPD;
intel_sdvo->hotplug_active[0] |= 1 << device; intel_sdvo->hotplug_active |= intel_sdvo_connector->output_flag;
/* Some SDVO devices have one-shot hotplug interrupts. /* Some SDVO devices have one-shot hotplug interrupts.
* Ensure that they get re-enabled when an interrupt happens. * Ensure that they get re-enabled when an interrupt happens.
*/ */
intel_encoder->hot_plug = intel_sdvo_enable_hotplug; intel_encoder->hot_plug = intel_sdvo_enable_hotplug;
intel_sdvo_enable_hotplug(intel_encoder); intel_sdvo_enable_hotplug(intel_encoder);
} } else {
else
connector->polled = DRM_CONNECTOR_POLL_CONNECT | DRM_CONNECTOR_POLL_DISCONNECT; connector->polled = DRM_CONNECTOR_POLL_CONNECT | DRM_CONNECTOR_POLL_DISCONNECT;
}
encoder->encoder_type = DRM_MODE_ENCODER_TMDS; encoder->encoder_type = DRM_MODE_ENCODER_TMDS;
connector->connector_type = DRM_MODE_CONNECTOR_DVID; connector->connector_type = DRM_MODE_CONNECTOR_DVID;
@ -2570,22 +2663,17 @@ bool intel_sdvo_init(struct drm_device *dev, uint32_t sdvo_reg, bool is_sdvob)
hotplug_mask = intel_sdvo->is_sdvob ? hotplug_mask = intel_sdvo->is_sdvob ?
SDVOB_HOTPLUG_INT_STATUS_I915 : SDVOC_HOTPLUG_INT_STATUS_I915; SDVOB_HOTPLUG_INT_STATUS_I915 : SDVOC_HOTPLUG_INT_STATUS_I915;
} }
dev_priv->hotplug_supported_mask |= hotplug_mask;
drm_encoder_helper_add(&intel_encoder->base, &intel_sdvo_helper_funcs); drm_encoder_helper_add(&intel_encoder->base, &intel_sdvo_helper_funcs);
intel_encoder->disable = intel_disable_sdvo;
intel_encoder->enable = intel_enable_sdvo;
intel_encoder->get_hw_state = intel_sdvo_get_hw_state;
/* In default case sdvo lvds is false */ /* In default case sdvo lvds is false */
if (!intel_sdvo_get_capabilities(intel_sdvo, &intel_sdvo->caps)) if (!intel_sdvo_get_capabilities(intel_sdvo, &intel_sdvo->caps))
goto err; goto err;
/* Set up hotplug command - note paranoia about contents of reply.
* We assume that the hardware is in a sane state, and only touch
* the bits we think we understand.
*/
intel_sdvo_get_value(intel_sdvo, SDVO_CMD_GET_ACTIVE_HOT_PLUG,
&intel_sdvo->hotplug_active, 2);
intel_sdvo->hotplug_active[0] &= ~0x3;
if (intel_sdvo_output_setup(intel_sdvo, if (intel_sdvo_output_setup(intel_sdvo,
intel_sdvo->caps.output_flags) != true) { intel_sdvo->caps.output_flags) != true) {
DRM_DEBUG_KMS("SDVO output failed to setup on %s\n", DRM_DEBUG_KMS("SDVO output failed to setup on %s\n",
@ -2593,6 +2681,12 @@ bool intel_sdvo_init(struct drm_device *dev, uint32_t sdvo_reg, bool is_sdvob)
goto err; goto err;
} }
/* Only enable the hotplug irq if we need it, to work around noisy
* hotplug lines.
*/
if (intel_sdvo->hotplug_active)
dev_priv->hotplug_supported_mask |= hotplug_mask;
intel_sdvo_select_ddc_bus(dev_priv, intel_sdvo, sdvo_reg); intel_sdvo_select_ddc_bus(dev_priv, intel_sdvo, sdvo_reg);
/* Set the input timing to the screen. Assume always input 0. */ /* Set the input timing to the screen. Assume always input 0. */

View File

@ -836,22 +836,37 @@ static struct intel_tv *intel_attached_tv(struct drm_connector *connector)
base); base);
} }
static void static bool
intel_tv_dpms(struct drm_encoder *encoder, int mode) intel_tv_get_hw_state(struct intel_encoder *encoder, enum pipe *pipe)
{ {
struct drm_device *dev = encoder->dev; struct drm_device *dev = encoder->base.dev;
struct drm_i915_private *dev_priv = dev->dev_private;
u32 tmp = I915_READ(TV_CTL);
if (!(tmp & TV_ENC_ENABLE))
return false;
*pipe = PORT_TO_PIPE(tmp);
return true;
}
static void
intel_enable_tv(struct intel_encoder *encoder)
{
struct drm_device *dev = encoder->base.dev;
struct drm_i915_private *dev_priv = dev->dev_private; struct drm_i915_private *dev_priv = dev->dev_private;
switch (mode) { I915_WRITE(TV_CTL, I915_READ(TV_CTL) | TV_ENC_ENABLE);
case DRM_MODE_DPMS_ON: }
I915_WRITE(TV_CTL, I915_READ(TV_CTL) | TV_ENC_ENABLE);
break; static void
case DRM_MODE_DPMS_STANDBY: intel_disable_tv(struct intel_encoder *encoder)
case DRM_MODE_DPMS_SUSPEND: {
case DRM_MODE_DPMS_OFF: struct drm_device *dev = encoder->base.dev;
I915_WRITE(TV_CTL, I915_READ(TV_CTL) & ~TV_ENC_ENABLE); struct drm_i915_private *dev_priv = dev->dev_private;
break;
} I915_WRITE(TV_CTL, I915_READ(TV_CTL) & ~TV_ENC_ENABLE);
} }
static const struct tv_mode * static const struct tv_mode *
@ -895,17 +910,14 @@ intel_tv_mode_fixup(struct drm_encoder *encoder,
const struct drm_display_mode *mode, const struct drm_display_mode *mode,
struct drm_display_mode *adjusted_mode) struct drm_display_mode *adjusted_mode)
{ {
struct drm_device *dev = encoder->dev;
struct intel_tv *intel_tv = enc_to_intel_tv(encoder); struct intel_tv *intel_tv = enc_to_intel_tv(encoder);
const struct tv_mode *tv_mode = intel_tv_mode_find(intel_tv); const struct tv_mode *tv_mode = intel_tv_mode_find(intel_tv);
struct intel_encoder *other_encoder;
if (!tv_mode) if (!tv_mode)
return false; return false;
for_each_encoder_on_crtc(dev, encoder->crtc, other_encoder) if (intel_encoder_check_is_cloned(&intel_tv->base))
if (&other_encoder->base != encoder) return false;
return false;
adjusted_mode->clock = tv_mode->clock; adjusted_mode->clock = tv_mode->clock;
return true; return true;
@ -1471,22 +1483,20 @@ intel_tv_set_property(struct drm_connector *connector, struct drm_property *prop
} }
if (changed && crtc) if (changed && crtc)
drm_crtc_helper_set_mode(crtc, &crtc->mode, crtc->x, intel_set_mode(crtc, &crtc->mode,
crtc->y, crtc->fb); crtc->x, crtc->y, crtc->fb);
out: out:
return ret; return ret;
} }
static const struct drm_encoder_helper_funcs intel_tv_helper_funcs = { static const struct drm_encoder_helper_funcs intel_tv_helper_funcs = {
.dpms = intel_tv_dpms,
.mode_fixup = intel_tv_mode_fixup, .mode_fixup = intel_tv_mode_fixup,
.prepare = intel_encoder_prepare,
.mode_set = intel_tv_mode_set, .mode_set = intel_tv_mode_set,
.commit = intel_encoder_commit, .disable = intel_encoder_noop,
}; };
static const struct drm_connector_funcs intel_tv_connector_funcs = { static const struct drm_connector_funcs intel_tv_connector_funcs = {
.dpms = drm_helper_connector_dpms, .dpms = intel_connector_dpms,
.detect = intel_tv_detect, .detect = intel_tv_detect,
.destroy = intel_tv_destroy, .destroy = intel_tv_destroy,
.set_property = intel_tv_set_property, .set_property = intel_tv_set_property,
@ -1616,6 +1626,11 @@ intel_tv_init(struct drm_device *dev)
drm_encoder_init(dev, &intel_encoder->base, &intel_tv_enc_funcs, drm_encoder_init(dev, &intel_encoder->base, &intel_tv_enc_funcs,
DRM_MODE_ENCODER_TVDAC); DRM_MODE_ENCODER_TVDAC);
intel_encoder->enable = intel_enable_tv;
intel_encoder->disable = intel_disable_tv;
intel_encoder->get_hw_state = intel_tv_get_hw_state;
intel_connector->get_hw_state = intel_connector_get_hw_state;
intel_connector_attach_encoder(intel_connector, intel_encoder); intel_connector_attach_encoder(intel_connector, intel_encoder);
intel_encoder->type = INTEL_OUTPUT_TVOUT; intel_encoder->type = INTEL_OUTPUT_TVOUT;
intel_encoder->crtc_mask = (1 << 0) | (1 << 1); intel_encoder->crtc_mask = (1 << 0) | (1 << 1);