forked from luck/tmp_suning_uos_patched
Merge branch 'drm-intel-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/keithp/linux-2.6
* 'drm-intel-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/keithp/linux-2.6: drm/i915: Cannot set clock gating under UMS drm/i915: Can't do accurate vblank timestamps with UMS Not all systems expose a firmware or platform mechanism for changing the backlight intensity on i915, so add native driver support. drm/i915: split out PCH refclk update code drm/i915: show interrupt info on IVB drm/i915: Remove unused 'reg' argument to dp_pipe_enabled drm/i915: Fix PCH port pipe select in CPT disable paths drm/i915: Leave LVDS registers unlocked drm/i915: Wait for LVDS panel power sequence
This commit is contained in:
commit
291b63c86a
@ -499,7 +499,7 @@ static int i915_interrupt_info(struct seq_file *m, void *data)
|
||||
seq_printf(m, "Interrupts received: %d\n",
|
||||
atomic_read(&dev_priv->irq_received));
|
||||
for (i = 0; i < I915_NUM_RINGS; i++) {
|
||||
if (IS_GEN6(dev)) {
|
||||
if (IS_GEN6(dev) || IS_GEN7(dev)) {
|
||||
seq_printf(m, "Graphics Interrupt mask (%s): %08x\n",
|
||||
dev_priv->ring[i].name,
|
||||
I915_READ_IMR(&dev_priv->ring[i]));
|
||||
|
@ -36,6 +36,7 @@
|
||||
#include <linux/io-mapping.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <drm/intel-gtt.h>
|
||||
#include <linux/backlight.h>
|
||||
|
||||
/* General customization:
|
||||
*/
|
||||
@ -690,6 +691,7 @@ typedef struct drm_i915_private {
|
||||
int child_dev_num;
|
||||
struct child_device_config *child_dev;
|
||||
struct drm_connector *int_lvds_connector;
|
||||
struct drm_connector *int_edp_connector;
|
||||
|
||||
bool mchbar_need_disable;
|
||||
|
||||
@ -723,6 +725,8 @@ typedef struct drm_i915_private {
|
||||
/* list of fbdev register on this device */
|
||||
struct intel_fbdev *fbdev;
|
||||
|
||||
struct backlight_device *backlight;
|
||||
|
||||
struct drm_property *broadcast_rgb_property;
|
||||
struct drm_property *force_audio_property;
|
||||
|
||||
|
@ -2058,8 +2058,10 @@ void intel_irq_init(struct drm_device *dev)
|
||||
dev->driver->get_vblank_counter = gm45_get_vblank_counter;
|
||||
}
|
||||
|
||||
|
||||
dev->driver->get_vblank_timestamp = i915_get_vblank_timestamp;
|
||||
if (drm_core_check_feature(dev, DRIVER_MODESET))
|
||||
dev->driver->get_vblank_timestamp = i915_get_vblank_timestamp;
|
||||
else
|
||||
dev->driver->get_vblank_timestamp = NULL;
|
||||
dev->driver->get_scanout_position = i915_get_crtc_scanoutpos;
|
||||
|
||||
if (IS_IVYBRIDGE(dev)) {
|
||||
|
@ -1318,6 +1318,7 @@
|
||||
#define ADPA_PIPE_SELECT_MASK (1<<30)
|
||||
#define ADPA_PIPE_A_SELECT 0
|
||||
#define ADPA_PIPE_B_SELECT (1<<30)
|
||||
#define ADPA_PIPE_SELECT(pipe) ((pipe) << 30)
|
||||
#define ADPA_USE_VGA_HVPOLARITY (1<<15)
|
||||
#define ADPA_SETS_HVPOLARITY 0
|
||||
#define ADPA_VSYNC_CNTL_DISABLE (1<<11)
|
||||
@ -1460,6 +1461,7 @@
|
||||
/* Selects pipe B for LVDS data. Must be set on pre-965. */
|
||||
#define LVDS_PIPEB_SELECT (1 << 30)
|
||||
#define LVDS_PIPE_MASK (1 << 30)
|
||||
#define LVDS_PIPE(pipe) ((pipe) << 30)
|
||||
/* LVDS dithering flag on 965/g4x platform */
|
||||
#define LVDS_ENABLE_DITHER (1 << 25)
|
||||
/* LVDS sync polarity flags. Set to invert (i.e. negative) */
|
||||
@ -1499,9 +1501,6 @@
|
||||
#define LVDS_B0B3_POWER_DOWN (0 << 2)
|
||||
#define LVDS_B0B3_POWER_UP (3 << 2)
|
||||
|
||||
#define LVDS_PIPE_ENABLED(V, P) \
|
||||
(((V) & (LVDS_PIPE_MASK | LVDS_PORT_EN)) == ((P) << 30 | LVDS_PORT_EN))
|
||||
|
||||
/* Video Data Island Packet control */
|
||||
#define VIDEO_DIP_DATA 0x61178
|
||||
#define VIDEO_DIP_CTL 0x61170
|
||||
@ -3256,14 +3255,12 @@
|
||||
#define ADPA_CRT_HOTPLUG_VOLREF_475MV (1<<17)
|
||||
#define ADPA_CRT_HOTPLUG_FORCE_TRIGGER (1<<16)
|
||||
|
||||
#define ADPA_PIPE_ENABLED(V, P) \
|
||||
(((V) & (ADPA_TRANS_SELECT_MASK | ADPA_DAC_ENABLE)) == ((P) << 30 | ADPA_DAC_ENABLE))
|
||||
|
||||
/* or SDVOB */
|
||||
#define HDMIB 0xe1140
|
||||
#define PORT_ENABLE (1 << 31)
|
||||
#define TRANSCODER_A (0)
|
||||
#define TRANSCODER_B (1 << 30)
|
||||
#define TRANSCODER(pipe) ((pipe) << 30)
|
||||
#define TRANSCODER_MASK (1 << 30)
|
||||
#define COLOR_FORMAT_8bpc (0)
|
||||
#define COLOR_FORMAT_12bpc (3 << 26)
|
||||
@ -3280,9 +3277,6 @@
|
||||
#define HSYNC_ACTIVE_HIGH (1 << 3)
|
||||
#define PORT_DETECTED (1 << 2)
|
||||
|
||||
#define HDMI_PIPE_ENABLED(V, P) \
|
||||
(((V) & (TRANSCODER_MASK | PORT_ENABLE)) == ((P) << 30 | PORT_ENABLE))
|
||||
|
||||
/* PCH SDVOB multiplex with HDMIB */
|
||||
#define PCH_SDVOB HDMIB
|
||||
|
||||
@ -3349,6 +3343,7 @@
|
||||
#define PORT_TRANS_B_SEL_CPT (1<<29)
|
||||
#define PORT_TRANS_C_SEL_CPT (2<<29)
|
||||
#define PORT_TRANS_SEL_MASK (3<<29)
|
||||
#define PORT_TRANS_SEL_CPT(pipe) ((pipe) << 29)
|
||||
|
||||
#define TRANS_DP_CTL_A 0xe0300
|
||||
#define TRANS_DP_CTL_B 0xe1300
|
||||
|
@ -871,7 +871,8 @@ int i915_restore_state(struct drm_device *dev)
|
||||
}
|
||||
mutex_unlock(&dev->struct_mutex);
|
||||
|
||||
intel_init_clock_gating(dev);
|
||||
if (drm_core_check_feature(dev, DRIVER_MODESET))
|
||||
intel_init_clock_gating(dev);
|
||||
|
||||
if (IS_IRONLAKE_M(dev)) {
|
||||
ironlake_enable_drps(dev);
|
||||
|
@ -980,8 +980,8 @@ static void assert_transcoder_disabled(struct drm_i915_private *dev_priv,
|
||||
pipe_name(pipe));
|
||||
}
|
||||
|
||||
static bool dp_pipe_enabled(struct drm_i915_private *dev_priv, enum pipe pipe,
|
||||
int reg, u32 port_sel, u32 val)
|
||||
static bool dp_pipe_enabled(struct drm_i915_private *dev_priv,
|
||||
enum pipe pipe, u32 port_sel, u32 val)
|
||||
{
|
||||
if ((val & DP_PORT_EN) == 0)
|
||||
return false;
|
||||
@ -998,11 +998,58 @@ static bool dp_pipe_enabled(struct drm_i915_private *dev_priv, enum pipe pipe,
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool hdmi_pipe_enabled(struct drm_i915_private *dev_priv,
|
||||
enum pipe pipe, u32 val)
|
||||
{
|
||||
if ((val & PORT_ENABLE) == 0)
|
||||
return false;
|
||||
|
||||
if (HAS_PCH_CPT(dev_priv->dev)) {
|
||||
if ((val & PORT_TRANS_SEL_MASK) != PORT_TRANS_SEL_CPT(pipe))
|
||||
return false;
|
||||
} else {
|
||||
if ((val & TRANSCODER_MASK) != TRANSCODER(pipe))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool lvds_pipe_enabled(struct drm_i915_private *dev_priv,
|
||||
enum pipe pipe, u32 val)
|
||||
{
|
||||
if ((val & LVDS_PORT_EN) == 0)
|
||||
return false;
|
||||
|
||||
if (HAS_PCH_CPT(dev_priv->dev)) {
|
||||
if ((val & PORT_TRANS_SEL_MASK) != PORT_TRANS_SEL_CPT(pipe))
|
||||
return false;
|
||||
} else {
|
||||
if ((val & LVDS_PIPE_MASK) != LVDS_PIPE(pipe))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool adpa_pipe_enabled(struct drm_i915_private *dev_priv,
|
||||
enum pipe pipe, u32 val)
|
||||
{
|
||||
if ((val & ADPA_DAC_ENABLE) == 0)
|
||||
return false;
|
||||
if (HAS_PCH_CPT(dev_priv->dev)) {
|
||||
if ((val & PORT_TRANS_SEL_MASK) != PORT_TRANS_SEL_CPT(pipe))
|
||||
return false;
|
||||
} else {
|
||||
if ((val & ADPA_PIPE_SELECT_MASK) != ADPA_PIPE_SELECT(pipe))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static void assert_pch_dp_disabled(struct drm_i915_private *dev_priv,
|
||||
enum pipe pipe, int reg, u32 port_sel)
|
||||
{
|
||||
u32 val = I915_READ(reg);
|
||||
WARN(dp_pipe_enabled(dev_priv, pipe, reg, port_sel, val),
|
||||
WARN(dp_pipe_enabled(dev_priv, pipe, port_sel, val),
|
||||
"PCH DP (0x%08x) enabled on transcoder %c, should be disabled\n",
|
||||
reg, pipe_name(pipe));
|
||||
}
|
||||
@ -1011,7 +1058,7 @@ static void assert_pch_hdmi_disabled(struct drm_i915_private *dev_priv,
|
||||
enum pipe pipe, int reg)
|
||||
{
|
||||
u32 val = I915_READ(reg);
|
||||
WARN(HDMI_PIPE_ENABLED(val, pipe),
|
||||
WARN(hdmi_pipe_enabled(dev_priv, val, pipe),
|
||||
"PCH DP (0x%08x) enabled on transcoder %c, should be disabled\n",
|
||||
reg, pipe_name(pipe));
|
||||
}
|
||||
@ -1028,13 +1075,13 @@ static void assert_pch_ports_disabled(struct drm_i915_private *dev_priv,
|
||||
|
||||
reg = PCH_ADPA;
|
||||
val = I915_READ(reg);
|
||||
WARN(ADPA_PIPE_ENABLED(val, pipe),
|
||||
WARN(adpa_pipe_enabled(dev_priv, val, pipe),
|
||||
"PCH VGA enabled on transcoder %c, should be disabled\n",
|
||||
pipe_name(pipe));
|
||||
|
||||
reg = PCH_LVDS;
|
||||
val = I915_READ(reg);
|
||||
WARN(LVDS_PIPE_ENABLED(val, pipe),
|
||||
WARN(lvds_pipe_enabled(dev_priv, val, pipe),
|
||||
"PCH LVDS enabled on transcoder %c, should be disabled\n",
|
||||
pipe_name(pipe));
|
||||
|
||||
@ -1360,7 +1407,7 @@ static void disable_pch_dp(struct drm_i915_private *dev_priv,
|
||||
enum pipe pipe, int reg, u32 port_sel)
|
||||
{
|
||||
u32 val = I915_READ(reg);
|
||||
if (dp_pipe_enabled(dev_priv, pipe, reg, port_sel, val)) {
|
||||
if (dp_pipe_enabled(dev_priv, pipe, port_sel, val)) {
|
||||
DRM_DEBUG_KMS("Disabling pch dp %x on pipe %d\n", reg, pipe);
|
||||
I915_WRITE(reg, val & ~DP_PORT_EN);
|
||||
}
|
||||
@ -1370,7 +1417,7 @@ static void disable_pch_hdmi(struct drm_i915_private *dev_priv,
|
||||
enum pipe pipe, int reg)
|
||||
{
|
||||
u32 val = I915_READ(reg);
|
||||
if (HDMI_PIPE_ENABLED(val, pipe)) {
|
||||
if (hdmi_pipe_enabled(dev_priv, val, pipe)) {
|
||||
DRM_DEBUG_KMS("Disabling pch HDMI %x on pipe %d\n",
|
||||
reg, pipe);
|
||||
I915_WRITE(reg, val & ~PORT_ENABLE);
|
||||
@ -1392,12 +1439,13 @@ static void intel_disable_pch_ports(struct drm_i915_private *dev_priv,
|
||||
|
||||
reg = PCH_ADPA;
|
||||
val = I915_READ(reg);
|
||||
if (ADPA_PIPE_ENABLED(val, pipe))
|
||||
if (adpa_pipe_enabled(dev_priv, val, pipe))
|
||||
I915_WRITE(reg, val & ~ADPA_DAC_ENABLE);
|
||||
|
||||
reg = PCH_LVDS;
|
||||
val = I915_READ(reg);
|
||||
if (LVDS_PIPE_ENABLED(val, pipe)) {
|
||||
if (lvds_pipe_enabled(dev_priv, val, pipe)) {
|
||||
DRM_DEBUG_KMS("disable lvds on pipe %d val 0x%08x\n", pipe, val);
|
||||
I915_WRITE(reg, val & ~LVDS_PORT_EN);
|
||||
POSTING_READ(reg);
|
||||
udelay(100);
|
||||
@ -5049,6 +5097,81 @@ static int i9xx_crtc_mode_set(struct drm_crtc *crtc,
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void ironlake_update_pch_refclk(struct drm_device *dev)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
struct drm_mode_config *mode_config = &dev->mode_config;
|
||||
struct drm_crtc *crtc;
|
||||
struct intel_encoder *encoder;
|
||||
struct intel_encoder *has_edp_encoder = NULL;
|
||||
u32 temp;
|
||||
bool has_lvds = false;
|
||||
|
||||
/* We need to take the global config into account */
|
||||
list_for_each_entry(crtc, &mode_config->crtc_list, head) {
|
||||
if (!crtc->enabled)
|
||||
continue;
|
||||
|
||||
list_for_each_entry(encoder, &mode_config->encoder_list,
|
||||
base.head) {
|
||||
if (encoder->base.crtc != crtc)
|
||||
continue;
|
||||
|
||||
switch (encoder->type) {
|
||||
case INTEL_OUTPUT_LVDS:
|
||||
has_lvds = true;
|
||||
case INTEL_OUTPUT_EDP:
|
||||
has_edp_encoder = encoder;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Ironlake: try to setup display ref clock before DPLL
|
||||
* enabling. This is only under driver's control after
|
||||
* PCH B stepping, previous chipset stepping should be
|
||||
* ignoring this setting.
|
||||
*/
|
||||
temp = I915_READ(PCH_DREF_CONTROL);
|
||||
/* Always enable nonspread source */
|
||||
temp &= ~DREF_NONSPREAD_SOURCE_MASK;
|
||||
temp |= DREF_NONSPREAD_SOURCE_ENABLE;
|
||||
temp &= ~DREF_SSC_SOURCE_MASK;
|
||||
temp |= DREF_SSC_SOURCE_ENABLE;
|
||||
I915_WRITE(PCH_DREF_CONTROL, temp);
|
||||
|
||||
POSTING_READ(PCH_DREF_CONTROL);
|
||||
udelay(200);
|
||||
|
||||
if (has_edp_encoder) {
|
||||
if (intel_panel_use_ssc(dev_priv)) {
|
||||
temp |= DREF_SSC1_ENABLE;
|
||||
I915_WRITE(PCH_DREF_CONTROL, temp);
|
||||
|
||||
POSTING_READ(PCH_DREF_CONTROL);
|
||||
udelay(200);
|
||||
}
|
||||
temp &= ~DREF_CPU_SOURCE_OUTPUT_MASK;
|
||||
|
||||
/* Enable CPU source on CPU attached eDP */
|
||||
if (!intel_encoder_is_pch_edp(&has_edp_encoder->base)) {
|
||||
if (intel_panel_use_ssc(dev_priv))
|
||||
temp |= DREF_CPU_SOURCE_OUTPUT_DOWNSPREAD;
|
||||
else
|
||||
temp |= DREF_CPU_SOURCE_OUTPUT_NONSPREAD;
|
||||
} else {
|
||||
/* Enable SSC on PCH eDP if needed */
|
||||
if (intel_panel_use_ssc(dev_priv)) {
|
||||
DRM_ERROR("enabling SSC on PCH\n");
|
||||
temp |= DREF_SUPERSPREAD_SOURCE_ENABLE;
|
||||
}
|
||||
}
|
||||
I915_WRITE(PCH_DREF_CONTROL, temp);
|
||||
POSTING_READ(PCH_DREF_CONTROL);
|
||||
udelay(200);
|
||||
}
|
||||
}
|
||||
|
||||
static int ironlake_crtc_mode_set(struct drm_crtc *crtc,
|
||||
struct drm_display_mode *mode,
|
||||
struct drm_display_mode *adjusted_mode,
|
||||
@ -5244,49 +5367,7 @@ static int ironlake_crtc_mode_set(struct drm_crtc *crtc,
|
||||
ironlake_compute_m_n(intel_crtc->bpp, lane, target_clock, link_bw,
|
||||
&m_n);
|
||||
|
||||
/* Ironlake: try to setup display ref clock before DPLL
|
||||
* enabling. This is only under driver's control after
|
||||
* PCH B stepping, previous chipset stepping should be
|
||||
* ignoring this setting.
|
||||
*/
|
||||
temp = I915_READ(PCH_DREF_CONTROL);
|
||||
/* Always enable nonspread source */
|
||||
temp &= ~DREF_NONSPREAD_SOURCE_MASK;
|
||||
temp |= DREF_NONSPREAD_SOURCE_ENABLE;
|
||||
temp &= ~DREF_SSC_SOURCE_MASK;
|
||||
temp |= DREF_SSC_SOURCE_ENABLE;
|
||||
I915_WRITE(PCH_DREF_CONTROL, temp);
|
||||
|
||||
POSTING_READ(PCH_DREF_CONTROL);
|
||||
udelay(200);
|
||||
|
||||
if (has_edp_encoder) {
|
||||
if (intel_panel_use_ssc(dev_priv)) {
|
||||
temp |= DREF_SSC1_ENABLE;
|
||||
I915_WRITE(PCH_DREF_CONTROL, temp);
|
||||
|
||||
POSTING_READ(PCH_DREF_CONTROL);
|
||||
udelay(200);
|
||||
}
|
||||
temp &= ~DREF_CPU_SOURCE_OUTPUT_MASK;
|
||||
|
||||
/* Enable CPU source on CPU attached eDP */
|
||||
if (!intel_encoder_is_pch_edp(&has_edp_encoder->base)) {
|
||||
if (intel_panel_use_ssc(dev_priv))
|
||||
temp |= DREF_CPU_SOURCE_OUTPUT_DOWNSPREAD;
|
||||
else
|
||||
temp |= DREF_CPU_SOURCE_OUTPUT_NONSPREAD;
|
||||
} else {
|
||||
/* Enable SSC on PCH eDP if needed */
|
||||
if (intel_panel_use_ssc(dev_priv)) {
|
||||
DRM_ERROR("enabling SSC on PCH\n");
|
||||
temp |= DREF_SUPERSPREAD_SOURCE_ENABLE;
|
||||
}
|
||||
}
|
||||
I915_WRITE(PCH_DREF_CONTROL, temp);
|
||||
POSTING_READ(PCH_DREF_CONTROL);
|
||||
udelay(200);
|
||||
}
|
||||
ironlake_update_pch_refclk(dev);
|
||||
|
||||
fp = clock.n << 16 | clock.m1 << 8 | clock.m2;
|
||||
if (has_reduced_clock)
|
||||
|
@ -1841,6 +1841,11 @@ intel_dp_set_property(struct drm_connector *connector,
|
||||
static void
|
||||
intel_dp_destroy (struct drm_connector *connector)
|
||||
{
|
||||
struct drm_device *dev = connector->dev;
|
||||
|
||||
if (intel_dpd_is_edp(dev))
|
||||
intel_panel_destroy_backlight(dev);
|
||||
|
||||
drm_sysfs_connector_remove(connector);
|
||||
drm_connector_cleanup(connector);
|
||||
kfree(connector);
|
||||
@ -2072,6 +2077,8 @@ intel_dp_init(struct drm_device *dev, int output_reg)
|
||||
DRM_MODE_TYPE_PREFERRED;
|
||||
}
|
||||
}
|
||||
dev_priv->int_edp_connector = connector;
|
||||
intel_panel_setup_backlight(dev);
|
||||
}
|
||||
|
||||
intel_dp_add_properties(intel_dp, connector);
|
||||
|
@ -297,9 +297,10 @@ extern void intel_pch_panel_fitting(struct drm_device *dev,
|
||||
extern u32 intel_panel_get_max_backlight(struct drm_device *dev);
|
||||
extern u32 intel_panel_get_backlight(struct drm_device *dev);
|
||||
extern void intel_panel_set_backlight(struct drm_device *dev, u32 level);
|
||||
extern void intel_panel_setup_backlight(struct drm_device *dev);
|
||||
extern int intel_panel_setup_backlight(struct drm_device *dev);
|
||||
extern void intel_panel_enable_backlight(struct drm_device *dev);
|
||||
extern void intel_panel_disable_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 void intel_crtc_load_lut(struct drm_crtc *crtc);
|
||||
|
@ -72,14 +72,16 @@ static void intel_lvds_enable(struct intel_lvds *intel_lvds)
|
||||
{
|
||||
struct drm_device *dev = intel_lvds->base.base.dev;
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
u32 ctl_reg, lvds_reg;
|
||||
u32 ctl_reg, lvds_reg, stat_reg;
|
||||
|
||||
if (HAS_PCH_SPLIT(dev)) {
|
||||
ctl_reg = PCH_PP_CONTROL;
|
||||
lvds_reg = PCH_LVDS;
|
||||
stat_reg = PCH_PP_STATUS;
|
||||
} else {
|
||||
ctl_reg = PP_CONTROL;
|
||||
lvds_reg = LVDS;
|
||||
stat_reg = PP_STATUS;
|
||||
}
|
||||
|
||||
I915_WRITE(lvds_reg, I915_READ(lvds_reg) | LVDS_PORT_EN);
|
||||
@ -94,17 +96,16 @@ static void intel_lvds_enable(struct intel_lvds *intel_lvds)
|
||||
DRM_DEBUG_KMS("applying panel-fitter: %x, %x\n",
|
||||
intel_lvds->pfit_control,
|
||||
intel_lvds->pfit_pgm_ratios);
|
||||
if (wait_for((I915_READ(PP_STATUS) & PP_ON) == 0, 1000)) {
|
||||
DRM_ERROR("timed out waiting for panel to power off\n");
|
||||
} else {
|
||||
I915_WRITE(PFIT_PGM_RATIOS, intel_lvds->pfit_pgm_ratios);
|
||||
I915_WRITE(PFIT_CONTROL, intel_lvds->pfit_control);
|
||||
intel_lvds->pfit_dirty = false;
|
||||
}
|
||||
|
||||
I915_WRITE(PFIT_PGM_RATIOS, intel_lvds->pfit_pgm_ratios);
|
||||
I915_WRITE(PFIT_CONTROL, intel_lvds->pfit_control);
|
||||
intel_lvds->pfit_dirty = false;
|
||||
}
|
||||
|
||||
I915_WRITE(ctl_reg, I915_READ(ctl_reg) | POWER_TARGET_ON);
|
||||
POSTING_READ(lvds_reg);
|
||||
if (wait_for((I915_READ(stat_reg) & PP_ON) != 0, 1000))
|
||||
DRM_ERROR("timed out waiting for panel to power on\n");
|
||||
|
||||
intel_panel_enable_backlight(dev);
|
||||
}
|
||||
@ -113,24 +114,25 @@ static void intel_lvds_disable(struct intel_lvds *intel_lvds)
|
||||
{
|
||||
struct drm_device *dev = intel_lvds->base.base.dev;
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
u32 ctl_reg, lvds_reg;
|
||||
u32 ctl_reg, lvds_reg, stat_reg;
|
||||
|
||||
if (HAS_PCH_SPLIT(dev)) {
|
||||
ctl_reg = PCH_PP_CONTROL;
|
||||
lvds_reg = PCH_LVDS;
|
||||
stat_reg = PCH_PP_STATUS;
|
||||
} else {
|
||||
ctl_reg = PP_CONTROL;
|
||||
lvds_reg = LVDS;
|
||||
stat_reg = PP_STATUS;
|
||||
}
|
||||
|
||||
intel_panel_disable_backlight(dev);
|
||||
|
||||
I915_WRITE(ctl_reg, I915_READ(ctl_reg) & ~POWER_TARGET_ON);
|
||||
if (wait_for((I915_READ(stat_reg) & PP_ON) == 0, 1000))
|
||||
DRM_ERROR("timed out waiting for panel to power off\n");
|
||||
|
||||
if (intel_lvds->pfit_control) {
|
||||
if (wait_for((I915_READ(PP_STATUS) & PP_ON) == 0, 1000))
|
||||
DRM_ERROR("timed out waiting for panel to power off\n");
|
||||
|
||||
I915_WRITE(PFIT_CONTROL, 0);
|
||||
intel_lvds->pfit_dirty = true;
|
||||
}
|
||||
@ -398,53 +400,21 @@ static bool intel_lvds_mode_fixup(struct drm_encoder *encoder,
|
||||
|
||||
static void intel_lvds_prepare(struct drm_encoder *encoder)
|
||||
{
|
||||
struct drm_device *dev = encoder->dev;
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
struct intel_lvds *intel_lvds = to_intel_lvds(encoder);
|
||||
|
||||
/* We try to do the minimum that is necessary in order to unlock
|
||||
* the registers for mode setting.
|
||||
*
|
||||
* On Ironlake, this is quite simple as we just set the unlock key
|
||||
* and ignore all subtleties. (This may cause some issues...)
|
||||
*
|
||||
/*
|
||||
* Prior to Ironlake, we must disable the pipe if we want to adjust
|
||||
* the panel fitter. However at all other times we can just reset
|
||||
* the registers regardless.
|
||||
*/
|
||||
|
||||
if (HAS_PCH_SPLIT(dev)) {
|
||||
I915_WRITE(PCH_PP_CONTROL,
|
||||
I915_READ(PCH_PP_CONTROL) | PANEL_UNLOCK_REGS);
|
||||
} else if (intel_lvds->pfit_dirty) {
|
||||
I915_WRITE(PP_CONTROL,
|
||||
(I915_READ(PP_CONTROL) | PANEL_UNLOCK_REGS)
|
||||
& ~POWER_TARGET_ON);
|
||||
} else {
|
||||
I915_WRITE(PP_CONTROL,
|
||||
I915_READ(PP_CONTROL) | PANEL_UNLOCK_REGS);
|
||||
}
|
||||
if (!HAS_PCH_SPLIT(encoder->dev) && intel_lvds->pfit_dirty)
|
||||
intel_lvds_disable(intel_lvds);
|
||||
}
|
||||
|
||||
static void intel_lvds_commit(struct drm_encoder *encoder)
|
||||
{
|
||||
struct drm_device *dev = encoder->dev;
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
struct intel_lvds *intel_lvds = to_intel_lvds(encoder);
|
||||
|
||||
/* Undo any unlocking done in prepare to prevent accidental
|
||||
* adjustment of the registers.
|
||||
*/
|
||||
if (HAS_PCH_SPLIT(dev)) {
|
||||
u32 val = I915_READ(PCH_PP_CONTROL);
|
||||
if ((val & PANEL_UNLOCK_REGS) == PANEL_UNLOCK_REGS)
|
||||
I915_WRITE(PCH_PP_CONTROL, val & 0x3);
|
||||
} else {
|
||||
u32 val = I915_READ(PP_CONTROL);
|
||||
if ((val & PANEL_UNLOCK_REGS) == PANEL_UNLOCK_REGS)
|
||||
I915_WRITE(PP_CONTROL, val & 0x3);
|
||||
}
|
||||
|
||||
/* Always do a full power on as we do not know what state
|
||||
* we were left in.
|
||||
*/
|
||||
@ -582,6 +552,8 @@ static void intel_lvds_destroy(struct drm_connector *connector)
|
||||
struct drm_device *dev = connector->dev;
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
|
||||
intel_panel_destroy_backlight(dev);
|
||||
|
||||
if (dev_priv->lid_notifier.notifier_call)
|
||||
acpi_lid_notifier_unregister(&dev_priv->lid_notifier);
|
||||
drm_sysfs_connector_remove(connector);
|
||||
@ -1040,6 +1012,19 @@ bool intel_lvds_init(struct drm_device *dev)
|
||||
pwm = I915_READ(BLC_PWM_PCH_CTL1);
|
||||
pwm |= PWM_PCH_ENABLE;
|
||||
I915_WRITE(BLC_PWM_PCH_CTL1, pwm);
|
||||
/*
|
||||
* Unlock registers and just
|
||||
* leave them unlocked
|
||||
*/
|
||||
I915_WRITE(PCH_PP_CONTROL,
|
||||
I915_READ(PCH_PP_CONTROL) | PANEL_UNLOCK_REGS);
|
||||
} else {
|
||||
/*
|
||||
* Unlock registers and just
|
||||
* leave them unlocked
|
||||
*/
|
||||
I915_WRITE(PP_CONTROL,
|
||||
I915_READ(PP_CONTROL) | PANEL_UNLOCK_REGS);
|
||||
}
|
||||
dev_priv->lid_notifier.notifier_call = intel_lid_notify;
|
||||
if (acpi_lid_notifier_register(&dev_priv->lid_notifier)) {
|
||||
@ -1049,6 +1034,9 @@ bool intel_lvds_init(struct drm_device *dev)
|
||||
/* keep the LVDS connector */
|
||||
dev_priv->int_lvds_connector = connector;
|
||||
drm_sysfs_connector_add(connector);
|
||||
|
||||
intel_panel_setup_backlight(dev);
|
||||
|
||||
return true;
|
||||
|
||||
failed:
|
||||
|
@ -227,7 +227,6 @@ void intel_opregion_asle_intr(struct drm_device *dev)
|
||||
asle->aslc = asle_stat;
|
||||
}
|
||||
|
||||
/* Only present on Ironlake+ */
|
||||
void intel_opregion_gse_intr(struct drm_device *dev)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
|
@ -277,7 +277,7 @@ void intel_panel_enable_backlight(struct drm_device *dev)
|
||||
dev_priv->backlight_enabled = true;
|
||||
}
|
||||
|
||||
void intel_panel_setup_backlight(struct drm_device *dev)
|
||||
static void intel_panel_init_backlight(struct drm_device *dev)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
|
||||
@ -309,3 +309,73 @@ intel_panel_detect(struct drm_device *dev)
|
||||
|
||||
return connector_status_unknown;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_BACKLIGHT_CLASS_DEVICE
|
||||
static int intel_panel_update_status(struct backlight_device *bd)
|
||||
{
|
||||
struct drm_device *dev = bl_get_data(bd);
|
||||
intel_panel_set_backlight(dev, bd->props.brightness);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int intel_panel_get_brightness(struct backlight_device *bd)
|
||||
{
|
||||
struct drm_device *dev = bl_get_data(bd);
|
||||
return intel_panel_get_backlight(dev);
|
||||
}
|
||||
|
||||
static const struct backlight_ops intel_panel_bl_ops = {
|
||||
.update_status = intel_panel_update_status,
|
||||
.get_brightness = intel_panel_get_brightness,
|
||||
};
|
||||
|
||||
int intel_panel_setup_backlight(struct drm_device *dev)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
struct backlight_properties props;
|
||||
struct drm_connector *connector;
|
||||
|
||||
intel_panel_init_backlight(dev);
|
||||
|
||||
if (dev_priv->int_lvds_connector)
|
||||
connector = dev_priv->int_lvds_connector;
|
||||
else if (dev_priv->int_edp_connector)
|
||||
connector = dev_priv->int_edp_connector;
|
||||
else
|
||||
return -ENODEV;
|
||||
|
||||
props.type = BACKLIGHT_RAW;
|
||||
props.max_brightness = intel_panel_get_max_backlight(dev);
|
||||
dev_priv->backlight =
|
||||
backlight_device_register("intel_backlight",
|
||||
&connector->kdev, dev,
|
||||
&intel_panel_bl_ops, &props);
|
||||
|
||||
if (IS_ERR(dev_priv->backlight)) {
|
||||
DRM_ERROR("Failed to register backlight: %ld\n",
|
||||
PTR_ERR(dev_priv->backlight));
|
||||
dev_priv->backlight = NULL;
|
||||
return -ENODEV;
|
||||
}
|
||||
dev_priv->backlight->props.brightness = intel_panel_get_backlight(dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void intel_panel_destroy_backlight(struct drm_device *dev)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
if (dev_priv->backlight)
|
||||
backlight_device_unregister(dev_priv->backlight);
|
||||
}
|
||||
#else
|
||||
int intel_panel_setup_backlight(struct drm_device *dev)
|
||||
{
|
||||
intel_panel_init_backlight(dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void intel_panel_destroy_backlight(struct drm_device *dev)
|
||||
{
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
Loading…
Reference in New Issue
Block a user