summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/i810_reg.h13
-rw-r--r--src/i830_lvds.c124
-rw-r--r--src/i830_randr.c21
-rw-r--r--src/i830_xf86Crtc.h15
4 files changed, 156 insertions, 17 deletions
diff --git a/src/i810_reg.h b/src/i810_reg.h
index c2eb8546..33b059d6 100644
--- a/src/i810_reg.h
+++ b/src/i810_reg.h
@@ -937,8 +937,21 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#define BLC_PWM_CTL 0x61254
#define BACKLIGHT_MODULATION_FREQ_SHIFT (17)
+/**
+ * This is the most significant 15 bits of the number of backlight cycles in a
+ * complete cycle of the modulated backlight control.
+ *
+ * The actual value is this field multiplied by two.
+ */
#define BACKLIGHT_MODULATION_FREQ_MASK (0x7fff << 17)
#define BLM_LEGACY_MODE (1 << 16)
+/**
+ * This is the number of cycles out of the backlight modulation cycle for which
+ * the backlight is on.
+ *
+ * This field must be no greater than the number of cycles in the complete
+ * backlight modulation cycle.
+ */
#define BACKLIGHT_DUTY_CYCLE_SHIFT (0)
#define BACKLIGHT_DUTY_CYCLE_MASK (0xffff)
diff --git a/src/i830_lvds.c b/src/i830_lvds.c
index 18ac76bf..223c6ab9 100644
--- a/src/i830_lvds.c
+++ b/src/i830_lvds.c
@@ -32,6 +32,34 @@
#include "xf86.h"
#include "i830.h"
#include "i830_bios.h"
+#include "X11/Xatom.h"
+
+/**
+ * Sets the backlight level.
+ *
+ * \param level backlight level, from 0 to i830_lvds_get_max_backlight().
+ */
+static void
+i830_lvds_set_backlight(ScrnInfoPtr pScrn, int level)
+{
+ I830Ptr pI830 = I830PTR(pScrn);
+ CARD32 blc_pwm_ctl;
+
+ blc_pwm_ctl = INREG(BLC_PWM_CTL) & ~BACKLIGHT_DUTY_CYCLE_MASK;
+ OUTREG(BLC_PWM_CTL, blc_pwm_ctl | (level << BACKLIGHT_DUTY_CYCLE_SHIFT));
+}
+
+/**
+ * Returns the maximum level of the backlight duty cycle field.
+ */
+static CARD32
+i830_lvds_get_max_backlight(ScrnInfoPtr pScrn)
+{
+ I830Ptr pI830 = I830PTR(pScrn);
+
+ return ((INREG(BLC_PWM_CTL) & BACKLIGHT_MODULATION_FREQ_MASK) >>
+ BACKLIGHT_MODULATION_FREQ_SHIFT) * 2;
+}
/**
* Sets the power state for the panel.
@@ -41,25 +69,16 @@ i830SetLVDSPanelPower(ScrnInfoPtr pScrn, Bool on)
{
I830Ptr pI830 = I830PTR(pScrn);
CARD32 pp_status;
- CARD32 blc_pwm_ctl;
- int backlight_duty_cycle;
-
- blc_pwm_ctl = INREG (BLC_PWM_CTL);
- backlight_duty_cycle = blc_pwm_ctl & BACKLIGHT_DUTY_CYCLE_MASK;
- if (backlight_duty_cycle)
- pI830->backlight_duty_cycle = backlight_duty_cycle;
if (on) {
OUTREG(PP_CONTROL, INREG(PP_CONTROL) | POWER_TARGET_ON);
do {
pp_status = INREG(PP_STATUS);
} while ((pp_status & PP_ON) == 0);
- OUTREG(BLC_PWM_CTL,
- (blc_pwm_ctl & ~BACKLIGHT_DUTY_CYCLE_MASK) |
- pI830->backlight_duty_cycle);
+
+ i830_lvds_set_backlight(pScrn, pI830->backlight_duty_cycle);
} else {
- OUTREG(BLC_PWM_CTL,
- (blc_pwm_ctl & ~BACKLIGHT_DUTY_CYCLE_MASK));
+ i830_lvds_set_backlight(pScrn, 0);
OUTREG(PP_CONTROL, INREG(PP_CONTROL) & ~POWER_TARGET_ON);
do {
@@ -99,11 +118,8 @@ i830_lvds_save (xf86OutputPtr output)
/*
* If the light is off at server startup, just make it full brightness
*/
- if (pI830->backlight_duty_cycle == 0) {
- pI830->backlight_duty_cycle =
- (pI830->saveBLC_PWM_CTL & BACKLIGHT_MODULATION_FREQ_MASK) >>
- BACKLIGHT_MODULATION_FREQ_SHIFT;
- }
+ if (pI830->backlight_duty_cycle == 0)
+ pI830->backlight_duty_cycle = i830_lvds_get_max_backlight(pScrn);
}
static void
@@ -294,7 +310,80 @@ i830_lvds_destroy (xf86OutputPtr output)
xfree (intel_output);
}
+#ifdef RANDR_12_INTERFACE
+#define BACKLIGHT_NAME "BACKLIGHT"
+static Atom backlight_atom;
+#endif /* RANDR_12_INTERFACE */
+
+static void
+i830_lvds_create_resources(xf86OutputPtr output)
+{
+#ifdef RANDR_12_INTERFACE
+ ScrnInfoPtr pScrn = output->scrn;
+ I830Ptr pI830 = I830PTR(pScrn);
+ INT32 range[2];
+ int data, err;
+
+ /* Set up the backlight property, which takes effect immediately
+ * and accepts values only within the range.
+ *
+ * XXX: Currently, RandR doesn't verify that properties set are
+ * within the range.
+ */
+ backlight_atom = MakeAtom(BACKLIGHT_NAME, sizeof(BACKLIGHT_NAME) - 1,
+ TRUE);
+
+ range[0] = 0;
+ range[1] = i830_lvds_get_max_backlight(pScrn);
+ err = RRConfigureOutputProperty(output->randr_output, backlight_atom,
+ FALSE, TRUE, FALSE, 2, range);
+ if (err != 0) {
+ xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
+ "RRConfigureOutputProperty error, %d\n", err);
+ }
+ /* Set the current value of the backlight property */
+ data = pI830->backlight_duty_cycle;
+ err = RRChangeOutputProperty(output->randr_output, backlight_atom,
+ XA_INTEGER, 32, PropModeReplace, 4, &data,
+ FALSE);
+ if (err != 0) {
+ xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
+ "RRChangeOutputProperty error, %d\n", err);
+ }
+
+#endif /* RANDR_12_INTERFACE */
+}
+
+static Bool
+i830_lvds_set_property(xf86OutputPtr output, Atom property,
+ RRPropertyValuePtr value)
+{
+ ScrnInfoPtr pScrn = output->scrn;
+ I830Ptr pI830 = I830PTR(pScrn);
+
+ if (property == backlight_atom) {
+ INT32 val;
+
+ if (value->type != XA_INTEGER || value->format != 32 ||
+ value->size != 1)
+ {
+ return FALSE;
+ }
+
+ val = *(INT32 *)value->data;
+ if (val < 0 || val > i830_lvds_get_max_backlight(pScrn))
+ return FALSE;
+
+ i830_lvds_set_backlight(pScrn, val);
+ pI830->backlight_duty_cycle = val;
+ return TRUE;
+ }
+
+ return TRUE;
+}
+
static const xf86OutputFuncsRec i830_lvds_output_funcs = {
+ .create_resources = i830_lvds_create_resources,
.dpms = i830_lvds_dpms,
.save = i830_lvds_save,
.restore = i830_lvds_restore,
@@ -303,6 +392,7 @@ static const xf86OutputFuncsRec i830_lvds_output_funcs = {
.mode_set = i830_lvds_mode_set,
.detect = i830_lvds_detect,
.get_modes = i830_lvds_get_modes,
+ .set_property = i830_lvds_set_property,
.destroy = i830_lvds_destroy
};
diff --git a/src/i830_randr.c b/src/i830_randr.c
index 18f84c49..63888494 100644
--- a/src/i830_randr.c
+++ b/src/i830_randr.c
@@ -672,6 +672,23 @@ xf86RandR12CrtcSetGamma (ScreenPtr pScreen,
return TRUE;
}
+static Bool
+xf86RandR12OutputSetProperty (ScreenPtr pScreen,
+ RROutputPtr randr_output,
+ Atom property,
+ RRPropertyValuePtr value)
+{
+ xf86OutputPtr output = randr_output->devPrivate;
+
+ /* If we don't have any property handler, then we don't care what the
+ * user is setting properties to.
+ */
+ if (output->funcs->set_property == NULL)
+ return TRUE;
+
+ return output->funcs->set_property(output, property, value);
+}
+
/**
* Given a list of xf86 modes and a RandR Output object, construct
* RandR modes and assign them to the output
@@ -861,6 +878,9 @@ xf86RandR12CreateObjects12 (ScreenPtr pScreen)
strlen (output->name),
output);
RROutputAttachScreen (output->randr_output, pScreen);
+
+ if (output->funcs->create_resources != NULL)
+ output->funcs->create_resources(output);
}
return TRUE;
}
@@ -897,6 +917,7 @@ xf86RandR12Init12 (ScreenPtr pScreen)
rp->rrScreenSetSize = xf86RandR12ScreenSetSize;
rp->rrCrtcSet = xf86RandR12CrtcSet;
rp->rrCrtcSetGamma = xf86RandR12CrtcSetGamma;
+ rp->rrOutputSetProperty = xf86RandR12OutputSetProperty;
rp->rrSetConfig = NULL;
pScrn->PointerMoved = xf86RandR12PointerMoved;
if (!xf86RandR12CreateObjects12 (pScreen))
diff --git a/src/i830_xf86Crtc.h b/src/i830_xf86Crtc.h
index 8fea162e..b5f2fc20 100644
--- a/src/i830_xf86Crtc.h
+++ b/src/i830_xf86Crtc.h
@@ -171,6 +171,13 @@ struct _xf86Crtc {
typedef struct _xf86OutputFuncs {
/**
+ * Called to allow the output a chance to create properties after the
+ * RandR objects have been created.
+ */
+ void
+ (*create_resources)(xf86OutputPtr output);
+
+ /**
* Turns the output on/off, or sets intermediate power levels if available.
*
* Unsupported intermediate modes drop to the lower power setting. If the
@@ -246,6 +253,14 @@ typedef struct _xf86OutputFuncs {
(*get_modes)(xf86OutputPtr output);
/**
+ * Callback when an output's property has changed.
+ */
+ Bool
+ (*set_property)(xf86OutputPtr output,
+ Atom property,
+ RRPropertyValuePtr value);
+
+ /**
* Clean up driver-specific bits of the output
*/
void