gma500/cdv: Add eDP support

Introduce the eDP support into the driver.

This has been reworked a bit because kernel driver proper uses encoder/connectors
while the legacy Intel driver uses the old output stuff.

It also diverges on the backlight handling. The legacy Intel driver adds a panel
abstraction based upon the i915 one. It's only really used for backlight bits
and we have a perfectly good backlight abstraction which can extend instead.

Signed-off-by: Zhao Yakui <yakui.zhao@intel.com>
[ported to upstream driver, redid backlight abstraction]
Signed-off-by: Alan Cox <alan@linux.intel.com>
Signed-off-by: Dave Airlie <airlied@redhat.com>
This commit is contained in:
Zhao Yakui 2012-08-08 13:55:55 +00:00 committed by Dave Airlie
parent 35659715c4
commit d112a8163f
14 changed files with 749 additions and 59 deletions

View File

@ -26,10 +26,55 @@
#include "intel_bios.h"
#include "power.h"
static void do_gma_backlight_set(struct drm_device *dev)
{
#ifdef CONFIG_BACKLIGHT_CLASS_DEVICE
struct drm_psb_private *dev_priv = dev->dev_private;
backlight_update_status(dev_priv->backlight_device);
#endif
}
void gma_backlight_enable(struct drm_device *dev)
{
#ifdef CONFIG_BACKLIGHT_CLASS_DEVICE
struct drm_psb_private *dev_priv = dev->dev_private;
dev_priv->backlight_enabled = true;
if (dev_priv->backlight_device) {
dev_priv->backlight_device->props.brightness = dev_priv->backlight_level;
do_gma_backlight_set(dev);
}
#endif
}
void gma_backlight_disable(struct drm_device *dev)
{
#ifdef CONFIG_BACKLIGHT_CLASS_DEVICE
struct drm_psb_private *dev_priv = dev->dev_private;
dev_priv->backlight_enabled = false;
if (dev_priv->backlight_device) {
dev_priv->backlight_device->props.brightness = 0;
do_gma_backlight_set(dev);
}
#endif
}
void gma_backlight_set(struct drm_device *dev, int v)
{
#ifdef CONFIG_BACKLIGHT_CLASS_DEVICE
struct drm_psb_private *dev_priv = dev->dev_private;
dev_priv->backlight_level = v;
if (dev_priv->backlight_device && dev_priv->backlight_enabled) {
dev_priv->backlight_device->props.brightness = v;
do_gma_backlight_set(dev);
}
#endif
}
int gma_backlight_init(struct drm_device *dev)
{
#ifdef CONFIG_BACKLIGHT_CLASS_DEVICE
struct drm_psb_private *dev_priv = dev->dev_private;
dev_priv->backlight_enabled = true;
return dev_priv->ops->backlight_init(dev);
#else
return 0;

View File

@ -170,6 +170,7 @@ static int cdv_backlight_init(struct drm_device *dev)
cdv_get_brightness(cdv_backlight_device);
backlight_update_status(cdv_backlight_device);
dev_priv->backlight_device = cdv_backlight_device;
dev_priv->backlight_enabled = true;
return 0;
}

View File

@ -438,7 +438,8 @@ static const struct cdv_intel_limit_t *cdv_intel_limit(struct drm_crtc *crtc,
limit = &cdv_intel_limits[CDV_LIMIT_SINGLE_LVDS_96];
else
limit = &cdv_intel_limits[CDV_LIMIT_SINGLE_LVDS_100];
} else if (psb_intel_pipe_has_type(crtc, INTEL_OUTPUT_DISPLAYPORT)) {
} else if (psb_intel_pipe_has_type(crtc, INTEL_OUTPUT_DISPLAYPORT) ||
psb_intel_pipe_has_type(crtc, INTEL_OUTPUT_EDP)) {
if (refclk == 27000)
limit = &cdv_intel_limits[CDV_LIMIT_DP_27];
else
@ -1045,6 +1046,7 @@ static int cdv_intel_crtc_mode_set(struct drm_crtc *crtc,
struct drm_connector *connector;
const struct cdv_intel_limit_t *limit;
u32 ddi_select = 0;
bool is_edp = false;
list_for_each_entry(connector, &mode_config->connector_list, head) {
struct psb_intel_encoder *psb_intel_encoder =
@ -1071,6 +1073,9 @@ static int cdv_intel_crtc_mode_set(struct drm_crtc *crtc,
case INTEL_OUTPUT_DISPLAYPORT:
is_dp = true;
break;
case INTEL_OUTPUT_EDP:
is_edp = true;
break;
default:
DRM_ERROR("invalid output type.\n");
return 0;
@ -1083,7 +1088,15 @@ static int cdv_intel_crtc_mode_set(struct drm_crtc *crtc,
else
/* high-end sku, 27/100 mhz */
refclk = 27000;
if (is_dp) {
if (is_dp || is_edp) {
/*
* Based on the spec the low-end SKU has only CRT/LVDS. So it is
* unnecessary to consider it for DP/eDP.
* On the high-end SKU, it will use the 27/100M reference clk
* for DP/eDP. When using SSC clock, the ref clk is 100MHz.Otherwise
* it will be 27MHz. From the VBIOS code it seems that the pipe A choose
* 27MHz for DP/eDP while the Pipe B chooses the 100MHz.
*/
if (pipe == 0)
refclk = 27000;
else
@ -1133,6 +1146,31 @@ static int cdv_intel_crtc_mode_set(struct drm_crtc *crtc,
/* setup pipeconf */
pipeconf = REG_READ(map->conf);
pipeconf &= ~(PIPE_BPC_MASK);
if (is_edp) {
switch (dev_priv->edp.bpp) {
case 24:
pipeconf |= PIPE_8BPC;
break;
case 18:
pipeconf |= PIPE_6BPC;
break;
case 30:
pipeconf |= PIPE_10BPC;
break;
default:
pipeconf |= PIPE_8BPC;
break;
}
} else if (is_lvds) {
/* the BPC will be 6 if it is 18-bit LVDS panel */
if ((REG_READ(LVDS) & LVDS_A3_POWER_MASK) == LVDS_A3_POWER_UP)
pipeconf |= PIPE_8BPC;
else
pipeconf |= PIPE_6BPC;
} else
pipeconf |= PIPE_8BPC;
/* Set up the display plane register */
dspcntr = DISPPLANE_GAMMA_ENABLE;

View File

@ -36,6 +36,20 @@
#include "psb_intel_reg.h"
#include "drm_dp_helper.h"
#define _wait_for(COND, MS, W) ({ \
unsigned long timeout__ = jiffies + msecs_to_jiffies(MS); \
int ret__ = 0; \
while (! (COND)) { \
if (time_after(jiffies, timeout__)) { \
ret__ = -ETIMEDOUT; \
break; \
} \
if (W && !in_dbg_master()) msleep(W); \
} \
ret__; \
})
#define wait_for(COND, MS) _wait_for(COND, MS, 1)
#define DP_LINK_STATUS_SIZE 6
#define DP_LINK_CHECK_TIMEOUT (10 * 1000)
@ -59,6 +73,13 @@ struct cdv_intel_dp {
struct i2c_algo_dp_aux_data algo;
uint8_t train_set[4];
uint8_t link_status[DP_LINK_STATUS_SIZE];
int panel_power_up_delay;
int panel_power_down_delay;
int panel_power_cycle_delay;
int backlight_on_delay;
int backlight_off_delay;
struct drm_display_mode *panel_fixed_mode; /* for eDP */
bool panel_on;
};
struct ddi_regoff {
@ -159,31 +180,166 @@ cdv_intel_dp_max_data_rate(int max_link_clock, int max_lanes)
return (max_link_clock * max_lanes * 19) / 20;
}
static void cdv_intel_edp_panel_vdd_on(struct psb_intel_encoder *intel_encoder)
{
struct drm_device *dev = intel_encoder->base.dev;
struct cdv_intel_dp *intel_dp = intel_encoder->dev_priv;
u32 pp;
if (intel_dp->panel_on) {
DRM_DEBUG_KMS("Skip VDD on because of panel on\n");
return;
}
DRM_DEBUG_KMS("\n");
pp = REG_READ(PP_CONTROL);
pp |= EDP_FORCE_VDD;
REG_WRITE(PP_CONTROL, pp);
REG_READ(PP_CONTROL);
msleep(intel_dp->panel_power_up_delay);
}
static void cdv_intel_edp_panel_vdd_off(struct psb_intel_encoder *intel_encoder)
{
struct drm_device *dev = intel_encoder->base.dev;
u32 pp;
DRM_DEBUG_KMS("\n");
pp = REG_READ(PP_CONTROL);
pp &= ~EDP_FORCE_VDD;
REG_WRITE(PP_CONTROL, pp);
REG_READ(PP_CONTROL);
}
/* Returns true if the panel was already on when called */
static bool cdv_intel_edp_panel_on(struct psb_intel_encoder *intel_encoder)
{
struct drm_device *dev = intel_encoder->base.dev;
struct cdv_intel_dp *intel_dp = intel_encoder->dev_priv;
u32 pp, idle_on_mask = PP_ON | PP_SEQUENCE_NONE;
if (intel_dp->panel_on)
return true;
DRM_DEBUG_KMS("\n");
pp = REG_READ(PP_CONTROL);
pp &= ~PANEL_UNLOCK_MASK;
pp |= (PANEL_UNLOCK_REGS | POWER_TARGET_ON);
REG_WRITE(PP_CONTROL, pp);
REG_READ(PP_CONTROL);
if (wait_for(((REG_READ(PP_STATUS) & idle_on_mask) == idle_on_mask), 1000)) {
DRM_DEBUG_KMS("Error in Powering up eDP panel, status %x\n", REG_READ(PP_STATUS));
intel_dp->panel_on = false;
} else
intel_dp->panel_on = true;
msleep(intel_dp->panel_power_up_delay);
return false;
}
static void cdv_intel_edp_panel_off (struct psb_intel_encoder *intel_encoder)
{
struct drm_device *dev = intel_encoder->base.dev;
u32 pp, idle_off_mask = PP_ON ;
struct cdv_intel_dp *intel_dp = intel_encoder->dev_priv;
DRM_DEBUG_KMS("\n");
pp = REG_READ(PP_CONTROL);
if ((pp & POWER_TARGET_ON) == 0)
return;
intel_dp->panel_on = false;
pp &= ~PANEL_UNLOCK_MASK;
/* ILK workaround: disable reset around power sequence */
pp &= ~POWER_TARGET_ON;
pp &= ~EDP_FORCE_VDD;
pp &= ~EDP_BLC_ENABLE;
REG_WRITE(PP_CONTROL, pp);
REG_READ(PP_CONTROL);
DRM_DEBUG_KMS("PP_STATUS %x\n", REG_READ(PP_STATUS));
if (wait_for((REG_READ(PP_STATUS) & idle_off_mask) == 0, 1000)) {
DRM_DEBUG_KMS("Error in turning off Panel\n");
}
msleep(intel_dp->panel_power_cycle_delay);
DRM_DEBUG_KMS("Over\n");
}
static void cdv_intel_edp_backlight_on (struct psb_intel_encoder *intel_encoder)
{
struct drm_device *dev = intel_encoder->base.dev;
u32 pp;
DRM_DEBUG_KMS("\n");
/*
* If we enable the backlight right away following a panel power
* on, we may see slight flicker as the panel syncs with the eDP
* link. So delay a bit to make sure the image is solid before
* allowing it to appear.
*/
msleep(300);
pp = REG_READ(PP_CONTROL);
pp |= EDP_BLC_ENABLE;
REG_WRITE(PP_CONTROL, pp);
gma_backlight_enable(dev);
}
static void cdv_intel_edp_backlight_off (struct psb_intel_encoder *intel_encoder)
{
struct drm_device *dev = intel_encoder->base.dev;
struct cdv_intel_dp *intel_dp = intel_encoder->dev_priv;
u32 pp;
DRM_DEBUG_KMS("\n");
gma_backlight_disable(dev);
msleep(10);
pp = REG_READ(PP_CONTROL);
pp &= ~EDP_BLC_ENABLE;
REG_WRITE(PP_CONTROL, pp);
msleep(intel_dp->backlight_off_delay);
}
static int
cdv_intel_dp_mode_valid(struct drm_connector *connector,
struct drm_display_mode *mode)
{
struct psb_intel_encoder *encoder = psb_intel_attached_encoder(connector);
struct drm_device *dev = connector->dev;
struct drm_psb_private *dev_priv = dev->dev_private;
struct cdv_intel_dp *intel_dp = encoder->dev_priv;
int max_link_clock = cdv_intel_dp_link_clock(cdv_intel_dp_max_link_bw(encoder));
int max_lanes = cdv_intel_dp_max_lane_count(encoder);
struct drm_psb_private *dev_priv = connector->dev->dev_private;
if (is_edp(encoder) && dev_priv->panel_fixed_mode) {
if (mode->hdisplay > dev_priv->panel_fixed_mode->hdisplay)
if (is_edp(encoder) && intel_dp->panel_fixed_mode) {
if (mode->hdisplay > intel_dp->panel_fixed_mode->hdisplay)
return MODE_PANEL;
if (mode->vdisplay > dev_priv->panel_fixed_mode->vdisplay)
if (mode->vdisplay > intel_dp->panel_fixed_mode->vdisplay)
return MODE_PANEL;
}
/* only refuse the mode on non eDP since we have seen some weird eDP panels
which are outside spec tolerances but somehow work by magic */
if (!is_edp(encoder) &&
(cdv_intel_dp_link_required(mode->clock, 24)
(cdv_intel_dp_link_required(mode->clock, dev_priv->edp.bpp)
> cdv_intel_dp_max_data_rate(max_link_clock, max_lanes)))
return MODE_CLOCK_HIGH;
if (is_edp(encoder)) {
if (cdv_intel_dp_link_required(mode->clock, 24)
> cdv_intel_dp_max_data_rate(max_link_clock, max_lanes))
return MODE_CLOCK_HIGH;
}
if (mode->clock < 10000)
return MODE_CLOCK_LOW;
@ -238,6 +394,8 @@ cdv_intel_dp_aux_ch(struct psb_intel_encoder *encoder,
aux_clock_divider = 200 / 2;
precharge = 4;
if (is_edp(encoder))
precharge = 10;
if (REG_READ(ch_ctl) & DP_AUX_CH_CTL_SEND_BUSY) {
DRM_ERROR("dp_aux_ch not started status 0x%08x\n",
@ -492,7 +650,10 @@ static int
cdv_intel_dp_i2c_init(struct psb_intel_connector *connector, struct psb_intel_encoder *encoder, const char *name)
{
struct cdv_intel_dp *intel_dp = encoder->dev_priv;
int ret;
DRM_DEBUG_KMS("i2c_init %s\n", name);
intel_dp->algo.running = false;
intel_dp->algo.address = 0;
intel_dp->algo.aux_ch = cdv_intel_dp_i2c_aux_ch;
@ -505,27 +666,58 @@ cdv_intel_dp_i2c_init(struct psb_intel_connector *connector, struct psb_intel_en
intel_dp->adapter.algo_data = &intel_dp->algo;
intel_dp->adapter.dev.parent = &connector->base.kdev;
return i2c_dp_aux_add_bus(&intel_dp->adapter);
if (is_edp(encoder))
cdv_intel_edp_panel_vdd_on(encoder);
ret = i2c_dp_aux_add_bus(&intel_dp->adapter);
if (is_edp(encoder))
cdv_intel_edp_panel_vdd_off(encoder);
return ret;
}
void cdv_intel_fixed_panel_mode(struct drm_display_mode *fixed_mode,
struct drm_display_mode *adjusted_mode)
{
adjusted_mode->hdisplay = fixed_mode->hdisplay;
adjusted_mode->hsync_start = fixed_mode->hsync_start;
adjusted_mode->hsync_end = fixed_mode->hsync_end;
adjusted_mode->htotal = fixed_mode->htotal;
adjusted_mode->vdisplay = fixed_mode->vdisplay;
adjusted_mode->vsync_start = fixed_mode->vsync_start;
adjusted_mode->vsync_end = fixed_mode->vsync_end;
adjusted_mode->vtotal = fixed_mode->vtotal;
adjusted_mode->clock = fixed_mode->clock;
drm_mode_set_crtcinfo(adjusted_mode, CRTC_INTERLACE_HALVE_V);
}
static bool
cdv_intel_dp_mode_fixup(struct drm_encoder *encoder, const struct drm_display_mode *mode,
struct drm_display_mode *adjusted_mode)
{
struct drm_psb_private *dev_priv = encoder->dev->dev_private;
struct psb_intel_encoder *intel_encoder = to_psb_intel_encoder(encoder);
struct cdv_intel_dp *intel_dp = intel_encoder->dev_priv;
int lane_count, clock;
int max_lane_count = cdv_intel_dp_max_lane_count(intel_encoder);
int max_clock = cdv_intel_dp_max_link_bw(intel_encoder) == DP_LINK_BW_2_7 ? 1 : 0;
static int bws[2] = { DP_LINK_BW_1_62, DP_LINK_BW_2_7 };
int refclock = mode->clock;
int bpp = 24;
if (is_edp(intel_encoder) && intel_dp->panel_fixed_mode) {
cdv_intel_fixed_panel_mode(intel_dp->panel_fixed_mode, adjusted_mode);
refclock = intel_dp->panel_fixed_mode->clock;
bpp = dev_priv->edp.bpp;
}
for (lane_count = 1; lane_count <= max_lane_count; lane_count <<= 1) {
for (clock = max_clock; clock >= 0; clock--) {
int link_avail = cdv_intel_dp_max_data_rate(cdv_intel_dp_link_clock(bws[clock]), lane_count);
if (cdv_intel_dp_link_required(mode->clock, 24)
<= link_avail) {
if (cdv_intel_dp_link_required(refclock, bpp) <= link_avail) {
intel_dp->link_bw = bws[clock];
intel_dp->lane_count = lane_count;
adjusted_mode->clock = cdv_intel_dp_link_clock(intel_dp->link_bw);
@ -537,7 +729,18 @@ cdv_intel_dp_mode_fixup(struct drm_encoder *encoder, const struct drm_display_mo
}
}
}
if (is_edp(intel_encoder)) {
/* okay we failed just pick the highest */
intel_dp->lane_count = max_lane_count;
intel_dp->link_bw = bws[max_clock];
adjusted_mode->clock = cdv_intel_dp_link_clock(intel_dp->link_bw);
DRM_DEBUG_KMS("Force picking display port link bw %02x lane "
"count %d clock %d\n",
intel_dp->link_bw, intel_dp->lane_count,
adjusted_mode->clock);
return true;
}
return false;
}
@ -550,7 +753,7 @@ struct cdv_intel_dp_m_n {
};
static void
psb_intel_reduce_ratio(uint32_t *num, uint32_t *den)
cdv_intel_reduce_ratio(uint32_t *num, uint32_t *den)
{
/*
while (*num > 0xffffff || *den > 0xffffff) {
@ -575,10 +778,10 @@ cdv_intel_dp_compute_m_n(int bpp,
m_n->tu = 64;
m_n->gmch_m = (pixel_clock * bpp + 7) >> 3;
m_n->gmch_n = link_clock * nlanes;
psb_intel_reduce_ratio(&m_n->gmch_m, &m_n->gmch_n);
cdv_intel_reduce_ratio(&m_n->gmch_m, &m_n->gmch_n);
m_n->link_m = pixel_clock;
m_n->link_n = link_clock;
psb_intel_reduce_ratio(&m_n->link_m, &m_n->link_n);
cdv_intel_reduce_ratio(&m_n->link_m, &m_n->link_n);
}
void
@ -586,6 +789,7 @@ cdv_intel_dp_set_m_n(struct drm_crtc *crtc, struct drm_display_mode *mode,
struct drm_display_mode *adjusted_mode)
{
struct drm_device *dev = crtc->dev;
struct drm_psb_private *dev_priv = dev->dev_private;
struct drm_mode_config *mode_config = &dev->mode_config;
struct drm_encoder *encoder;
struct psb_intel_crtc *intel_crtc = to_psb_intel_crtc(crtc);
@ -610,6 +814,7 @@ cdv_intel_dp_set_m_n(struct drm_crtc *crtc, struct drm_display_mode *mode,
break;
} else if (is_edp(intel_encoder)) {
lane_count = intel_dp->lane_count;
bpp = dev_priv->edp.bpp;
break;
}
}
@ -640,7 +845,7 @@ cdv_intel_dp_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode
struct drm_crtc *crtc = encoder->crtc;
struct psb_intel_crtc *intel_crtc = to_psb_intel_crtc(crtc);
struct cdv_intel_dp *intel_dp = intel_encoder->dev_priv;
struct drm_device *dev = encoder->dev;
intel_dp->DP = DP_VOLTAGE_0_4 | DP_PRE_EMPHASIS_0;
intel_dp->DP |= intel_dp->color_range;
@ -683,7 +888,22 @@ cdv_intel_dp_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode
if (intel_crtc->pipe == 1)
intel_dp->DP |= DP_PIPEB_SELECT;
REG_WRITE(intel_dp->output_reg, (intel_dp->DP | DP_PORT_EN));
DRM_DEBUG_KMS("DP expected reg is %x\n", intel_dp->DP);
if (is_edp(intel_encoder)) {
uint32_t pfit_control;
cdv_intel_edp_panel_on(intel_encoder);
if (mode->hdisplay != adjusted_mode->hdisplay ||
mode->vdisplay != adjusted_mode->vdisplay)
pfit_control = PFIT_ENABLE;
else
pfit_control = 0;
pfit_control |= intel_crtc->pipe << PFIT_PIPE_SHIFT;
REG_WRITE(PFIT_CONTROL, pfit_control);
}
}
@ -721,18 +941,31 @@ static void cdv_intel_dp_sink_dpms(struct psb_intel_encoder *encoder, int mode)
static void cdv_intel_dp_prepare(struct drm_encoder *encoder)
{
struct psb_intel_encoder *intel_encoder = to_psb_intel_encoder(encoder);
int edp = is_edp(intel_encoder);
if (edp) {
cdv_intel_edp_backlight_off(intel_encoder);
cdv_intel_edp_panel_off(intel_encoder);
cdv_intel_edp_panel_vdd_on(intel_encoder);
}
/* Wake up the sink first */
cdv_intel_dp_sink_dpms(intel_encoder, DRM_MODE_DPMS_ON);
cdv_intel_dp_link_down(intel_encoder);
if (edp)
cdv_intel_edp_panel_vdd_off(intel_encoder);
}
static void cdv_intel_dp_commit(struct drm_encoder *encoder)
{
struct psb_intel_encoder *intel_encoder = to_psb_intel_encoder(encoder);
int edp = is_edp(intel_encoder);
if (edp)
cdv_intel_edp_panel_on(intel_encoder);
cdv_intel_dp_start_link_train(intel_encoder);
cdv_intel_dp_complete_link_train(intel_encoder);
if (edp)
cdv_intel_edp_backlight_on(intel_encoder);
}
static void
@ -742,16 +975,29 @@ cdv_intel_dp_dpms(struct drm_encoder *encoder, int mode)
struct cdv_intel_dp *intel_dp = intel_encoder->dev_priv;
struct drm_device *dev = encoder->dev;
uint32_t dp_reg = REG_READ(intel_dp->output_reg);
int edp = is_edp(intel_encoder);
if (mode != DRM_MODE_DPMS_ON) {
if (edp) {
cdv_intel_edp_backlight_off(intel_encoder);
cdv_intel_edp_panel_vdd_on(intel_encoder);
}
cdv_intel_dp_sink_dpms(intel_encoder, mode);
cdv_intel_dp_link_down(intel_encoder);
if (edp) {
cdv_intel_edp_panel_vdd_off(intel_encoder);
cdv_intel_edp_panel_off(intel_encoder);
}
} else {
if (edp)
cdv_intel_edp_panel_on(intel_encoder);
cdv_intel_dp_sink_dpms(intel_encoder, mode);
if (!(dp_reg & DP_PORT_EN)) {
cdv_intel_dp_start_link_train(intel_encoder);
cdv_intel_dp_complete_link_train(intel_encoder);
}
if (edp)
cdv_intel_edp_backlight_on(intel_encoder);
}
}
@ -1090,6 +1336,10 @@ cdv_intel_dp_start_link_train(struct psb_intel_encoder *encoder)
for (;;) {
/* Use intel_dp->train_set[0] to set the voltage and pre emphasis values */
DRM_DEBUG_KMS("DP Link Train Set %x, Link_config %x, %x\n",
intel_dp->train_set[0],
intel_dp->link_configuration[0],
intel_dp->link_configuration[1]);
if (!cdv_intel_dp_set_link_train(encoder, reg, DP_TRAINING_PATTERN_1)) {
DRM_DEBUG_KMS("Failure in aux-transfer setting pattern 1\n");
@ -1103,6 +1353,10 @@ cdv_intel_dp_start_link_train(struct psb_intel_encoder *encoder)
if (!cdv_intel_dp_get_link_status(encoder))
break;
DRM_DEBUG_KMS("DP Link status %x, %x, %x, %x, %x, %x\n",
intel_dp->link_status[0], intel_dp->link_status[1], intel_dp->link_status[2],
intel_dp->link_status[3], intel_dp->link_status[4], intel_dp->link_status[5]);
if (cdv_intel_clock_recovery_ok(intel_dp->link_status, intel_dp->lane_count)) {
DRM_DEBUG_KMS("PT1 train is done\n");
clock_recovery = true;
@ -1156,7 +1410,13 @@ cdv_intel_dp_complete_link_train(struct psb_intel_encoder *encoder)
reg = DP | DP_LINK_TRAIN_PAT_2;
for (;;) {
/* channel eq pattern */
DRM_DEBUG_KMS("DP Link Train Set %x, Link_config %x, %x\n",
intel_dp->train_set[0],
intel_dp->link_configuration[0],
intel_dp->link_configuration[1]);
/* channel eq pattern */
if (!cdv_intel_dp_set_link_train(encoder, reg,
DP_TRAINING_PATTERN_2)) {
DRM_DEBUG_KMS("Failure in aux-transfer setting pattern 2\n");
@ -1177,6 +1437,10 @@ cdv_intel_dp_complete_link_train(struct psb_intel_encoder *encoder)
if (!cdv_intel_dp_get_link_status(encoder))
break;
DRM_DEBUG_KMS("DP Link status %x, %x, %x, %x, %x, %x\n",
intel_dp->link_status[0], intel_dp->link_status[1], intel_dp->link_status[2],
intel_dp->link_status[3], intel_dp->link_status[4], intel_dp->link_status[5]);
/* Make sure clock is still ok */
if (!cdv_intel_clock_recovery_ok(intel_dp->link_status, intel_dp->lane_count)) {
cdv_intel_dp_start_link_train(encoder);
@ -1271,12 +1535,18 @@ cdv_intel_dp_detect(struct drm_connector *connector, bool force)
struct cdv_intel_dp *intel_dp = encoder->dev_priv;
enum drm_connector_status status;
struct edid *edid = NULL;
int edp = is_edp(encoder);
intel_dp->has_audio = false;
if (edp)
cdv_intel_edp_panel_vdd_on(encoder);
status = cdv_dp_detect(encoder);
if (status != connector_status_connected)
if (status != connector_status_connected) {
if (edp)
cdv_intel_edp_panel_vdd_off(encoder);
return status;
}
if (intel_dp->force_audio) {
intel_dp->has_audio = intel_dp->force_audio > 0;
@ -1288,6 +1558,8 @@ cdv_intel_dp_detect(struct drm_connector *connector, bool force)
kfree(edid);
}
}
if (edp)
cdv_intel_edp_panel_vdd_off(encoder);
return connector_status_connected;
}
@ -1298,6 +1570,7 @@ static int cdv_intel_dp_get_modes(struct drm_connector *connector)
struct cdv_intel_dp *intel_dp = intel_encoder->dev_priv;
struct edid *edid = NULL;
int ret = 0;
int edp = is_edp(intel_encoder);
edid = drm_get_edid(connector, &intel_dp->adapter);
@ -1307,6 +1580,42 @@ static int cdv_intel_dp_get_modes(struct drm_connector *connector)
kfree(edid);
}
if (is_edp(intel_encoder)) {
struct drm_device *dev = connector->dev;
struct drm_psb_private *dev_priv = dev->dev_private;
cdv_intel_edp_panel_vdd_off(intel_encoder);
if (ret) {
if (edp && !intel_dp->panel_fixed_mode) {
struct drm_display_mode *newmode;
list_for_each_entry(newmode, &connector->probed_modes,
head) {
if (newmode->type & DRM_MODE_TYPE_PREFERRED) {
intel_dp->panel_fixed_mode =
drm_mode_duplicate(dev, newmode);
break;
}
}
}
return ret;
}
if (!intel_dp->panel_fixed_mode && dev_priv->lfp_lvds_vbt_mode) {
intel_dp->panel_fixed_mode =
drm_mode_duplicate(dev, dev_priv->lfp_lvds_vbt_mode);
if (intel_dp->panel_fixed_mode) {
intel_dp->panel_fixed_mode->type |=
DRM_MODE_TYPE_PREFERRED;
}
}
if (intel_dp->panel_fixed_mode != NULL) {
struct drm_display_mode *mode;
mode = drm_mode_duplicate(dev, intel_dp->panel_fixed_mode);
drm_mode_probed_add(connector, mode);
return 1;
}
}
return ret;
}
@ -1317,6 +1626,10 @@ cdv_intel_dp_detect_audio(struct drm_connector *connector)
struct cdv_intel_dp *intel_dp = encoder->dev_priv;
struct edid *edid;
bool has_audio = false;
int edp = is_edp(encoder);
if (edp)
cdv_intel_edp_panel_vdd_on(encoder);
edid = drm_get_edid(connector, &intel_dp->adapter);
if (edid) {
@ -1325,6 +1638,8 @@ cdv_intel_dp_detect_audio(struct drm_connector *connector)
connector->display_info.raw_edid = NULL;
kfree(edid);
}
if (edp)
cdv_intel_edp_panel_vdd_off(encoder);
return has_audio;
}
@ -1386,12 +1701,19 @@ done:
}
static void
cdv_intel_dp_destroy (struct drm_connector *connector)
cdv_intel_dp_destroy(struct drm_connector *connector)
{
struct psb_intel_encoder *psb_intel_encoder =
psb_intel_attached_encoder(connector);
struct cdv_intel_dp *intel_dp = psb_intel_encoder->dev_priv;
if (is_edp(psb_intel_encoder)) {
/* cdv_intel_panel_destroy_backlight(connector->dev); */
if (intel_dp->panel_fixed_mode) {
kfree(intel_dp->panel_fixed_mode);
intel_dp->panel_fixed_mode = NULL;
}
}
i2c_del_adapter(&intel_dp->adapter);
drm_sysfs_connector_remove(connector);
drm_connector_cleanup(connector);
@ -1436,6 +1758,26 @@ static void cdv_intel_dp_add_properties(struct drm_connector *connector)
cdv_intel_attach_broadcast_rgb_property(connector);
}
/* check the VBT to see whether the eDP is on DP-D port */
static bool cdv_intel_dpc_is_edp(struct drm_device *dev)
{
struct drm_psb_private *dev_priv = dev->dev_private;
struct child_device_config *p_child;
int i;
if (!dev_priv->child_dev_num)
return false;
for (i = 0; i < dev_priv->child_dev_num; i++) {
p_child = dev_priv->child_dev + i;
if (p_child->dvo_port == PORT_IDPC &&
p_child->device_type == DEVICE_TYPE_eDP)
return true;
}
return false;
}
void
cdv_intel_dp_init(struct drm_device *dev, struct psb_intel_mode_device *mode_dev, int output_reg)
{
@ -1445,6 +1787,7 @@ cdv_intel_dp_init(struct drm_device *dev, struct psb_intel_mode_device *mode_dev
struct drm_encoder *encoder;
struct cdv_intel_dp *intel_dp;
const char *name = NULL;
int type = DRM_MODE_CONNECTOR_DisplayPort;
psb_intel_encoder = kzalloc(sizeof(struct psb_intel_encoder), GFP_KERNEL);
if (!psb_intel_encoder)
@ -1456,14 +1799,22 @@ cdv_intel_dp_init(struct drm_device *dev, struct psb_intel_mode_device *mode_dev
if (!intel_dp)
goto err_priv;
if ((output_reg == DP_C) && cdv_intel_dpc_is_edp(dev))
type = DRM_MODE_CONNECTOR_eDP;
connector = &psb_intel_connector->base;
encoder = &psb_intel_encoder->base;
drm_connector_init(dev, connector, &cdv_intel_dp_connector_funcs, DRM_MODE_CONNECTOR_DisplayPort);
drm_connector_init(dev, connector, &cdv_intel_dp_connector_funcs, type);
drm_encoder_init(dev, encoder, &cdv_intel_dp_enc_funcs, DRM_MODE_ENCODER_TMDS);
psb_intel_connector_attach_encoder(psb_intel_connector, psb_intel_encoder);
psb_intel_encoder->type = INTEL_OUTPUT_DISPLAYPORT;
if (type == DRM_MODE_CONNECTOR_DisplayPort)
psb_intel_encoder->type = INTEL_OUTPUT_DISPLAYPORT;
else
psb_intel_encoder->type = INTEL_OUTPUT_EDP;
psb_intel_encoder->dev_priv=intel_dp;
intel_dp->encoder = psb_intel_encoder;
@ -1493,6 +1844,83 @@ cdv_intel_dp_init(struct drm_device *dev, struct psb_intel_mode_device *mode_dev
cdv_intel_dp_i2c_init(psb_intel_connector, psb_intel_encoder, name);
/* FIXME:fail check */
cdv_intel_dp_add_properties(connector);
if (is_edp(psb_intel_encoder)) {
int ret;
struct edp_power_seq cur;
u32 pp_on, pp_off, pp_div;
u32 pwm_ctrl;
pp_on = REG_READ(PP_CONTROL);
pp_on &= ~PANEL_UNLOCK_MASK;
pp_on |= PANEL_UNLOCK_REGS;
REG_WRITE(PP_CONTROL, pp_on);
pwm_ctrl = REG_READ(BLC_PWM_CTL2);
pwm_ctrl |= PWM_PIPE_B;
REG_WRITE(BLC_PWM_CTL2, pwm_ctrl);
pp_on = REG_READ(PP_ON_DELAYS);
pp_off = REG_READ(PP_OFF_DELAYS);
pp_div = REG_READ(PP_DIVISOR);
/* Pull timing values out of registers */
cur.t1_t3 = (pp_on & PANEL_POWER_UP_DELAY_MASK) >>
PANEL_POWER_UP_DELAY_SHIFT;
cur.t8 = (pp_on & PANEL_LIGHT_ON_DELAY_MASK) >>
PANEL_LIGHT_ON_DELAY_SHIFT;
cur.t9 = (pp_off & PANEL_LIGHT_OFF_DELAY_MASK) >>
PANEL_LIGHT_OFF_DELAY_SHIFT;
cur.t10 = (pp_off & PANEL_POWER_DOWN_DELAY_MASK) >>
PANEL_POWER_DOWN_DELAY_SHIFT;
cur.t11_t12 = ((pp_div & PANEL_POWER_CYCLE_DELAY_MASK) >>
PANEL_POWER_CYCLE_DELAY_SHIFT);
DRM_DEBUG_KMS("cur t1_t3 %d t8 %d t9 %d t10 %d t11_t12 %d\n",
cur.t1_t3, cur.t8, cur.t9, cur.t10, cur.t11_t12);
intel_dp->panel_power_up_delay = cur.t1_t3 / 10;
intel_dp->backlight_on_delay = cur.t8 / 10;
intel_dp->backlight_off_delay = cur.t9 / 10;
intel_dp->panel_power_down_delay = cur.t10 / 10;
intel_dp->panel_power_cycle_delay = (cur.t11_t12 - 1) * 100;
DRM_DEBUG_KMS("panel power up delay %d, power down delay %d, power cycle delay %d\n",
intel_dp->panel_power_up_delay, intel_dp->panel_power_down_delay,
intel_dp->panel_power_cycle_delay);
DRM_DEBUG_KMS("backlight on delay %d, off delay %d\n",
intel_dp->backlight_on_delay, intel_dp->backlight_off_delay);
cdv_intel_edp_panel_vdd_on(psb_intel_encoder);
ret = cdv_intel_dp_aux_native_read(psb_intel_encoder, DP_DPCD_REV,
intel_dp->dpcd,
sizeof(intel_dp->dpcd));
cdv_intel_edp_panel_vdd_off(psb_intel_encoder);
if (ret == 0) {
/* if this fails, presume the device is a ghost */
DRM_INFO("failed to retrieve link info, disabling eDP\n");
cdv_intel_dp_encoder_destroy(encoder);
cdv_intel_dp_destroy(connector);
goto err_priv;
} else {
DRM_DEBUG_KMS("DPCD: Rev=%x LN_Rate=%x LN_CNT=%x LN_DOWNSP=%x\n",
intel_dp->dpcd[0], intel_dp->dpcd[1],
intel_dp->dpcd[2], intel_dp->dpcd[3]);
}
/* The CDV reference driver moves pnale backlight setup into the displays that
have a backlight: this is a good idea and one we should probably adopt, however
we need to migrate all the drivers before we can do that */
/*cdv_intel_panel_setup_backlight(dev); */
}
return;
err_priv:

View File

@ -506,16 +506,8 @@ static int cdv_intel_lvds_set_property(struct drm_connector *connector,
property,
value))
return -1;
else {
#ifdef CONFIG_BACKLIGHT_CLASS_DEVICE
struct drm_psb_private *dev_priv =
encoder->dev->dev_private;
struct backlight_device *bd =
dev_priv->backlight_device;
bd->props.brightness = value;
backlight_update_status(bd);
#endif
}
else
gma_backlight_set(encoder->dev, value);
} else if (!strcmp(property->name, "DPMS") && encoder) {
struct drm_encoder_helper_funcs *helpers =
encoder->helper_private;

View File

@ -768,6 +768,9 @@ static void psb_setup_outputs(struct drm_device *dev)
crtc_mask = (1 << 0) | (1 << 1);
clone_mask = (1 << INTEL_OUTPUT_DISPLAYPORT);
break;
case INTEL_OUTPUT_EDP:
crtc_mask = (1 << 1);
clone_mask = (1 << INTEL_OUTPUT_EDP);
}
encoder->possible_crtcs = crtc_mask;
encoder->possible_clones =

View File

@ -54,6 +54,98 @@ static void *find_section(struct bdb_header *bdb, int section_id)
return NULL;
}
static void
parse_edp(struct drm_psb_private *dev_priv, struct bdb_header *bdb)
{
struct bdb_edp *edp;
struct edp_power_seq *edp_pps;
struct edp_link_params *edp_link_params;
uint8_t panel_type;
edp = find_section(bdb, BDB_EDP);
dev_priv->edp.bpp = 18;
if (!edp) {
if (dev_priv->edp.support) {
DRM_DEBUG_KMS("No eDP BDB found but eDP panel supported, assume %dbpp panel color depth.\n",
dev_priv->edp.bpp);
}
return;
}
panel_type = dev_priv->panel_type;
switch ((edp->color_depth >> (panel_type * 2)) & 3) {
case EDP_18BPP:
dev_priv->edp.bpp = 18;
break;
case EDP_24BPP:
dev_priv->edp.bpp = 24;
break;
case EDP_30BPP:
dev_priv->edp.bpp = 30;
break;
}
/* Get the eDP sequencing and link info */
edp_pps = &edp->power_seqs[panel_type];
edp_link_params = &edp->link_params[panel_type];
dev_priv->edp.pps = *edp_pps;
DRM_DEBUG_KMS("EDP timing in vbt t1_t3 %d t8 %d t9 %d t10 %d t11_t12 %d\n",
dev_priv->edp.pps.t1_t3, dev_priv->edp.pps.t8,
dev_priv->edp.pps.t9, dev_priv->edp.pps.t10,
dev_priv->edp.pps.t11_t12);
dev_priv->edp.rate = edp_link_params->rate ? DP_LINK_BW_2_7 :
DP_LINK_BW_1_62;
switch (edp_link_params->lanes) {
case 0:
dev_priv->edp.lanes = 1;
break;
case 1:
dev_priv->edp.lanes = 2;
break;
case 3:
default:
dev_priv->edp.lanes = 4;
break;
}
DRM_DEBUG_KMS("VBT reports EDP: Lane_count %d, Lane_rate %d, Bpp %d\n",
dev_priv->edp.lanes, dev_priv->edp.rate, dev_priv->edp.bpp);
switch (edp_link_params->preemphasis) {
case 0:
dev_priv->edp.preemphasis = DP_TRAIN_PRE_EMPHASIS_0;
break;
case 1:
dev_priv->edp.preemphasis = DP_TRAIN_PRE_EMPHASIS_3_5;
break;
case 2:
dev_priv->edp.preemphasis = DP_TRAIN_PRE_EMPHASIS_6;
break;
case 3:
dev_priv->edp.preemphasis = DP_TRAIN_PRE_EMPHASIS_9_5;
break;
}
switch (edp_link_params->vswing) {
case 0:
dev_priv->edp.vswing = DP_TRAIN_VOLTAGE_SWING_400;
break;
case 1:
dev_priv->edp.vswing = DP_TRAIN_VOLTAGE_SWING_600;
break;
case 2:
dev_priv->edp.vswing = DP_TRAIN_VOLTAGE_SWING_800;
break;
case 3:
dev_priv->edp.vswing = DP_TRAIN_VOLTAGE_SWING_1200;
break;
}
DRM_DEBUG_KMS("VBT reports EDP: VSwing %d, Preemph %d\n",
dev_priv->edp.vswing, dev_priv->edp.preemphasis);
}
static u16
get_blocksize(void *p)
{
@ -154,6 +246,8 @@ static void parse_lfp_panel_data(struct drm_psb_private *dev_priv,
return;
dev_priv->lvds_dither = lvds_options->pixel_dither;
dev_priv->panel_type = lvds_options->panel_type;
if (lvds_options->panel_type == 0xff)
return;
@ -340,6 +434,9 @@ parse_driver_features(struct drm_psb_private *dev_priv,
if (!driver)
return;
if (driver->lvds_config == BDB_DRIVER_FEATURE_EDP)
dev_priv->edp.support = 1;
/* This bit means to use 96Mhz for DPLL_A or not */
if (driver->primary_lfp_id)
dev_priv->dplla_96mhz = true;
@ -437,6 +534,9 @@ int psb_intel_init_bios(struct drm_device *dev)
size_t size;
int i;
dev_priv->panel_type = 0xff;
/* XXX Should this validation be moved to intel_opregion.c? */
if (dev_priv->opregion.vbt) {
struct vbt_header *vbt = dev_priv->opregion.vbt;
@ -477,6 +577,7 @@ int psb_intel_init_bios(struct drm_device *dev)
parse_sdvo_device_mapping(dev_priv, bdb);
parse_device_mapping(dev_priv, bdb);
parse_backlight_data(dev_priv, bdb);
parse_edp(dev_priv, bdb);
if (bios)
pci_unmap_rom(pdev, bios);

View File

@ -23,6 +23,7 @@
#define _I830_BIOS_H_
#include <drm/drmP.h>
#include <drm/drm_dp_helper.h>
struct vbt_header {
u8 signature[20]; /**< Always starts with 'VBT$' */
@ -93,6 +94,7 @@ struct vbios_data {
#define BDB_SDVO_LVDS_PNP_IDS 24
#define BDB_SDVO_LVDS_POWER_SEQ 25
#define BDB_TV_OPTIONS 26
#define BDB_EDP 27
#define BDB_LVDS_OPTIONS 40
#define BDB_LVDS_LFP_DATA_PTRS 41
#define BDB_LVDS_LFP_DATA 42
@ -391,6 +393,11 @@ struct bdb_sdvo_lvds_options {
u8 panel_misc_bits_4;
} __attribute__((packed));
#define BDB_DRIVER_FEATURE_NO_LVDS 0
#define BDB_DRIVER_FEATURE_INT_LVDS 1
#define BDB_DRIVER_FEATURE_SDVO_LVDS 2
#define BDB_DRIVER_FEATURE_EDP 3
struct bdb_driver_features {
u8 boot_dev_algorithm:1;
u8 block_display_switch:1;
@ -431,6 +438,45 @@ struct bdb_driver_features {
u8 custom_vbt_version;
} __attribute__((packed));
#define EDP_18BPP 0
#define EDP_24BPP 1
#define EDP_30BPP 2
#define EDP_RATE_1_62 0
#define EDP_RATE_2_7 1
#define EDP_LANE_1 0
#define EDP_LANE_2 1
#define EDP_LANE_4 3
#define EDP_PREEMPHASIS_NONE 0
#define EDP_PREEMPHASIS_3_5dB 1
#define EDP_PREEMPHASIS_6dB 2
#define EDP_PREEMPHASIS_9_5dB 3
#define EDP_VSWING_0_4V 0
#define EDP_VSWING_0_6V 1
#define EDP_VSWING_0_8V 2
#define EDP_VSWING_1_2V 3
struct edp_power_seq {
u16 t1_t3;
u16 t8;
u16 t9;
u16 t10;
u16 t11_t12;
} __attribute__ ((packed));
struct edp_link_params {
u8 rate:4;
u8 lanes:4;
u8 preemphasis:4;
u8 vswing:4;
} __attribute__ ((packed));
struct bdb_edp {
struct edp_power_seq power_seqs[16];
u32 color_depth;
u32 sdrrs_msa_timing_delay;
struct edp_link_params link_params[16];
} __attribute__ ((packed));
extern int psb_intel_init_bios(struct drm_device *dev);
extern void psb_intel_destroy_bios(struct drm_device *dev);

View File

@ -299,17 +299,8 @@ static int mdfld_dsi_connector_set_property(struct drm_connector *connector,
if (drm_connector_property_set_value(connector, property,
value))
goto set_prop_error;
else {
#ifdef CONFIG_BACKLIGHT_CLASS_DEVICE
struct backlight_device *psb_bd;
psb_bd = mdfld_get_backlight_device();
if (psb_bd) {
psb_bd->props.brightness = value;
mdfld_set_brightness(psb_bd);
}
#endif
}
else
gma_backlight_set(encoder->dev, value);
}
set_prop_done:
return 0;

View File

@ -118,20 +118,20 @@ static void mid_get_pci_revID(struct drm_psb_private *dev_priv)
dev_priv->platform_rev_id);
}
struct vbt_header {
struct mid_vbt_header {
u32 signature;
u8 revision;
} __packed;
/* The same for r0 and r1 */
struct vbt_r0 {
struct vbt_header vbt_header;
struct mid_vbt_header vbt_header;
u8 size;
u8 checksum;
} __packed;
struct vbt_r10 {
struct vbt_header vbt_header;
struct mid_vbt_header vbt_header;
u8 checksum;
u16 size;
u8 panel_count;
@ -281,7 +281,7 @@ static void mid_get_vbt_data(struct drm_psb_private *dev_priv)
struct drm_device *dev = dev_priv->dev;
u32 addr;
u8 __iomem *vbt_virtual;
struct vbt_header vbt_header;
struct mid_vbt_header vbt_header;
struct pci_dev *pci_gfx_root = pci_get_bus_and_slot(0, PCI_DEVFN(2, 0));
int ret = -1;

View File

@ -166,8 +166,7 @@ static u32 asle_set_backlight(struct drm_device *dev, u32 bclp)
if (config_enabled(CONFIG_BACKLIGHT_CLASS_DEVICE)) {
int max = bd->props.max_brightness;
bd->props.brightness = bclp * max / 255;
backlight_update_status(bd);
gma_backlight_set(dev, bclp * max / 255);
}
asle->cblv = (bclp * 0x64) / 0xff | ASLE_CBLV_VALID;

View File

@ -28,6 +28,7 @@
#include "gma_drm.h"
#include "psb_reg.h"
#include "psb_intel_drv.h"
#include "intel_bios.h"
#include "gtt.h"
#include "power.h"
#include "opregion.h"
@ -613,6 +614,8 @@ struct drm_psb_private {
*/
struct backlight_device *backlight_device;
struct drm_property *backlight_property;
bool backlight_enabled;
int backlight_level;
uint32_t blc_adj1;
uint32_t blc_adj2;
@ -640,6 +643,19 @@ struct drm_psb_private {
int mdfld_panel_id;
bool dplla_96mhz; /* DPLL data from the VBT */
struct {
int rate;
int lanes;
int preemphasis;
int vswing;
bool initialized;
bool support;
int bpp;
struct edp_power_seq pps;
} edp;
uint8_t panel_type;
};
@ -796,6 +812,9 @@ extern int psb_fbdev_init(struct drm_device *dev);
/* backlight.c */
int gma_backlight_init(struct drm_device *dev);
void gma_backlight_exit(struct drm_device *dev);
void gma_backlight_disable(struct drm_device *dev);
void gma_backlight_enable(struct drm_device *dev);
void gma_backlight_set(struct drm_device *dev, int v);
/* oaktrail_crtc.c */
extern const struct drm_crtc_helper_funcs oaktrail_helper_funcs;

View File

@ -630,17 +630,8 @@ int psb_intel_lvds_set_property(struct drm_connector *connector,
property,
value))
goto set_prop_error;
else {
#ifdef CONFIG_BACKLIGHT_CLASS_DEVICE
struct drm_psb_private *devp =
encoder->dev->dev_private;
struct backlight_device *bd = devp->backlight_device;
if (bd) {
bd->props.brightness = value;
backlight_update_status(bd);
}
#endif
}
else
gma_backlight_set(encoder->dev, value);
} else if (!strcmp(property->name, "DPMS")) {
struct drm_encoder_helper_funcs *hfuncs
= encoder->helper_private;

View File

@ -173,15 +173,46 @@
#define PP_SEQUENCE_ON (1 << 28)
#define PP_SEQUENCE_OFF (2 << 28)
#define PP_SEQUENCE_MASK 0x30000000
#define PP_CYCLE_DELAY_ACTIVE (1 << 27)
#define PP_SEQUENCE_STATE_ON_IDLE (1 << 3)
#define PP_SEQUENCE_STATE_MASK 0x0000000f
#define PP_CONTROL 0x61204
#define POWER_TARGET_ON (1 << 0)
#define PANEL_UNLOCK_REGS (0xabcd << 16)
#define PANEL_UNLOCK_MASK (0xffff << 16)
#define EDP_FORCE_VDD (1 << 3)
#define EDP_BLC_ENABLE (1 << 2)
#define PANEL_POWER_RESET (1 << 1)
#define PANEL_POWER_OFF (0 << 0)
#define PANEL_POWER_ON (1 << 0)
/* Poulsbo/Oaktrail */
#define LVDSPP_ON 0x61208
#define LVDSPP_OFF 0x6120c
#define PP_CYCLE 0x61210
/* Cedartrail */
#define PP_ON_DELAYS 0x61208 /* Cedartrail */
#define PANEL_PORT_SELECT_MASK (3 << 30)
#define PANEL_PORT_SELECT_LVDS (0 << 30)
#define PANEL_PORT_SELECT_EDP (1 << 30)
#define PANEL_POWER_UP_DELAY_MASK (0x1fff0000)
#define PANEL_POWER_UP_DELAY_SHIFT 16
#define PANEL_LIGHT_ON_DELAY_MASK (0x1fff)
#define PANEL_LIGHT_ON_DELAY_SHIFT 0
#define PP_OFF_DELAYS 0x6120c /* Cedartrail */
#define PANEL_POWER_DOWN_DELAY_MASK (0x1fff0000)
#define PANEL_POWER_DOWN_DELAY_SHIFT 16
#define PANEL_LIGHT_OFF_DELAY_MASK (0x1fff)
#define PANEL_LIGHT_OFF_DELAY_SHIFT 0
#define PP_DIVISOR 0x61210 /* Cedartrail */
#define PP_REFERENCE_DIVIDER_MASK (0xffffff00)
#define PP_REFERENCE_DIVIDER_SHIFT 8
#define PANEL_POWER_CYCLE_DELAY_MASK (0x1f)
#define PANEL_POWER_CYCLE_DELAY_SHIFT 0
#define PFIT_CONTROL 0x61230
#define PFIT_ENABLE (1 << 31)
@ -1503,4 +1534,9 @@ No status bits are changed.
#define PIPE_DP_LINK_M(pipe) _PIPE(pipe, _PIPEA_DP_LINK_M, _PIPEB_DP_LINK_M)
#define PIPE_DP_LINK_N(pipe) _PIPE(pipe, _PIPEA_DP_LINK_N, _PIPEB_DP_LINK_N)
#define PIPE_BPC_MASK (7 << 5)
#define PIPE_8BPC (0 << 5)
#define PIPE_10BPC (1 << 5)
#define PIPE_6BPC (2 << 5)
#endif