From patchwork Fri Aug 14 17:54:05 2009 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Matthias Hopf X-Patchwork-Id: 41477 Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) by demeter.kernel.org (8.14.2/8.14.2) with ESMTP id n7EHsAUs008196 for ; Fri, 14 Aug 2009 17:54:10 GMT Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id D8F809F66B; Fri, 14 Aug 2009 10:54:09 -0700 (PDT) X-Original-To: intel-gfx@lists.freedesktop.org Delivered-To: intel-gfx@lists.freedesktop.org Received: from mx1.suse.de (cantor.suse.de [195.135.220.2]) by gabe.freedesktop.org (Postfix) with ESMTP id 8880F9E7FD for ; Fri, 14 Aug 2009 10:54:07 -0700 (PDT) Received: from relay1.suse.de (mail2.suse.de [195.135.221.8]) (using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.suse.de (Postfix) with ESMTP id B8C0193717 for ; Fri, 14 Aug 2009 19:54:05 +0200 (CEST) Date: Fri, 14 Aug 2009 19:54:05 +0200 From: Matthias Hopf To: intel-gfx@lists.freedesktop.org Message-ID: <20090814175405.GA31971@suse.de> MIME-Version: 1.0 Content-Disposition: inline Organization: SUSE LINUX Products GmbH, =?iso-8859-1?Q?G?= =?iso-8859-1?Q?F=3A_Markus_Rex=2C_HRB_16746_=28AG_N=FCrnberg=29?= User-Agent: Mutt/1.5.17 (2007-11-01) Subject: [Intel-gfx] Legacy backlight control with KMS and BACKLIGHT property X-BeenThere: intel-gfx@lists.freedesktop.org X-Mailman-Version: 2.1.9 Precedence: list List-Id: Intel graphics driver community testing & development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: intel-gfx-bounces@lists.freedesktop.org Errors-To: intel-gfx-bounces@lists.freedesktop.org Currently with KMS legacy backlight control isn't working at all. Also, the driver doesn't expose the BACKLIGHT RandR property in any case, so xbacklight doesn't work with KMS. I've been working on a patch as a quick-hack for this (attached; please DON'T apply), and am finally understanding enough to actually implement this correctly together with GregKH. What we're supposing is - a kernel driver for the /sys/class/backlight/ api for the legacy method - support in the driver to actually open this one (trivial) - support for the BACKLIGHT property in KMS case, *only* using the kernel api method for now (will need some abstraction) Also I noted that the BACKLIGHT property is - not preceeded with _ - not yet documented in randrproto.txt I suggest that I add this in randrproto.txt, as it seems plausible to me to actually make this a known property. Does this sound reasonable? Matthias diff -urp xf86-video-intel-2.8.0.orig/src/drmmode_display.c xf86-video-intel-2.8.0/src/drmmode_display.c --- xf86-video-intel-2.8.0.orig/src/drmmode_display.c 2009-07-11 01:31:10.000000000 -0400 +++ xf86-video-intel-2.8.0/src/drmmode_display.c 2009-08-14 17:15:56.000000000 -0400 @@ -74,6 +74,7 @@ typedef struct { drmmode_prop_ptr props; void *private_data; int dpms_mode; + struct backlight_ctrl *backlight; } drmmode_output_private_rec, *drmmode_output_private_ptr; static void @@ -712,11 +713,50 @@ drmmode_output_destroy(xf86OutputPtr out xfree(drmmode_output->private_data); drmmode_output->private_data = NULL; } + if (drmmode_output->backlight) { + drmmode_output->backlight->set_backlight(output, + drmmode_output->backlight->backlight_duty_cycle); + xfree(drmmode_output->backlight); + } xfree(drmmode_output); output->driver_private = NULL; } static void +drmmode_output_dpms_backlight(xf86OutputPtr output, struct backlight_ctrl *bl, + int oldmode, int mode) +{ + ScrnInfoPtr pScrn = output->scrn; + I830Ptr pI830 = I830PTR(pScrn); + + if (!bl) + return; + + if (mode == DPMSModeOn) { + /* + * If we're going from off->on we may need to turn on the backlight. + * We should use the saved value whenever possible, but on some + * machines 0 is a valid backlight value (due to an external + * backlight controller for example), so on them, when turning LVDS + * back on, they'll always re-maximize the brightness. + */ + if (mode != oldmode && + bl->backlight_duty_cycle == 0 && + pI830->backlight_control_method < BCM_KERNEL) + bl->backlight_duty_cycle = bl->backlight_max; + + bl->set_backlight(output, bl->backlight_duty_cycle); + } else { + /* + * Only save the current backlight value if we're going from on to off. + */ + if (mode != oldmode) + bl->backlight_duty_cycle = bl->get_backlight(output); + bl->set_backlight(output, 0); + } +} + +static void drmmode_output_dpms(xf86OutputPtr output, int mode) { drmmode_output_private_ptr drmmode_output = output->driver_private; @@ -735,8 +775,13 @@ drmmode_output_dpms(xf86OutputPtr output drmmode_output->output_id, props->prop_id, mode); + drmmode_output_dpms_backlight(output, + drmmode_output->backlight, + drmmode_output->dpms_mode, + mode); drmmode_output->dpms_mode = mode; drmModeFreeProperty(props); + return; } drmModeFreeProperty(props); @@ -767,6 +812,9 @@ drmmode_property_ignore(drmModePropertyP return FALSE; } +#define BACKLIGHT_NAME "BACKLIGHT" +static Atom backlight_atom; + static void drmmode_output_create_resources(xf86OutputPtr output) { @@ -774,7 +822,8 @@ drmmode_output_create_resources(xf86Outp drmModeConnectorPtr mode_output = drmmode_output->mode_output; drmmode_ptr drmmode = drmmode_output->drmmode; drmModePropertyPtr drmmode_prop; - int i, j, err; + int i, j, err, data; + INT32 backlight_range[2]; drmmode_output->props = xcalloc(mode_output->count_props, sizeof(drmmode_prop_rec)); if (!drmmode_output->props) @@ -851,6 +900,35 @@ drmmode_output_create_resources(xf86Outp } } } + + if (drmmode_output->backlight) { + /* Set up the backlight property, which takes effect immediately + * and accepts values only within the backlight_range. + * + * XXX: Currently, RandR doesn't verify that properties set are + * within the backlight_range. + */ + backlight_atom = MakeAtom(BACKLIGHT_NAME, sizeof(BACKLIGHT_NAME) - 1, + TRUE); + + backlight_range[0] = 0; + backlight_range[1] = drmmode_output->backlight->backlight_max; + err = RRConfigureOutputProperty(output->randr_output, backlight_atom, + FALSE, TRUE, FALSE, 2, backlight_range); + if (err != 0) { + xf86DrvMsg(output->scrn->scrnIndex, X_ERROR, + "RRConfigureOutputProperty error, %d\n", err); + } + /* Set the current value of the backlight property */ + data = drmmode_output->backlight->backlight_duty_cycle; + err = RRChangeOutputProperty(output->randr_output, backlight_atom, + XA_INTEGER, 32, PropModeReplace, 1, &data, + FALSE, TRUE); + if (err != 0) { + xf86DrvMsg(output->scrn->scrnIndex, X_ERROR, + "RRChangeOutputProperty error, %d\n", err); + } + } } static Bool @@ -861,6 +939,27 @@ drmmode_output_set_property(xf86OutputPt drmmode_ptr drmmode = drmmode_output->drmmode; int i; + if (property == backlight_atom) { + struct backlight_ctrl *bl = drmmode_output->backlight; + INT32 val; + + if (value->type != XA_INTEGER || value->format != 32 || + value->size != 1) + { + return FALSE; + } + + val = *(INT32 *)value->data; + if (val < 0 || val > bl->backlight_max) + return FALSE; + + if (val != bl->backlight_duty_cycle) { + bl->set_backlight(output, val); + bl->backlight_duty_cycle = val; + } + return TRUE; + } + for (i = 0; i < drmmode_output->num_props; i++) { drmmode_prop_ptr p = &drmmode_output->props[i]; @@ -996,6 +1095,10 @@ drmmode_output_init(ScrnInfoPtr pScrn, d if (!drmmode_output->private_data) xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Can't allocate private memory for LVDS.\n"); + i830_backlightonly_init(output, &drmmode_output->backlight); + if (!drmmode_output->backlight) + xf86DrvMsg(output->scrn->scrnIndex, X_ERROR, + "Can't allocate backlight control memory for LVDS.\n"); } drmmode_output->output_id = drmmode->mode_res->connectors[num]; drmmode_output->mode_output = koutput; diff -urp xf86-video-intel-2.8.0.orig/src/i830.h xf86-video-intel-2.8.0/src/i830.h --- xf86-video-intel-2.8.0.orig/src/i830.h 2009-07-21 01:41:16.000000000 -0400 +++ xf86-video-intel-2.8.0/src/i830.h 2009-08-14 16:51:32.000000000 -0400 @@ -316,6 +316,14 @@ enum backlight_control { BCM_COMBO, BCM_KERNEL, }; +struct backlight_ctrl { + void (*set_backlight)(xf86OutputPtr output, int level); + int (*get_backlight)(xf86OutputPtr output); + int backlight_max; + /* restore backlight to this value */ + int backlight_duty_cycle; +}; + enum dri_type { DRI_DISABLED, @@ -755,6 +763,7 @@ void i830_hdmi_init(ScrnInfoPtr pScrn, i /* i830_lvds.c */ void i830_lvds_init(ScrnInfoPtr pScrn); +void i830_backlightonly_init(xf86OutputPtr output, struct backlight_ctrl **backlight); /* i830_memory.c */ Bool i830_bind_all_memory(ScrnInfoPtr pScrn); diff -urp xf86-video-intel-2.8.0.orig/src/i830_lvds.c xf86-video-intel-2.8.0/src/i830_lvds.c --- xf86-video-intel-2.8.0.orig/src/i830_lvds.c 2009-06-26 12:30:59.000000000 -0400 +++ xf86-video-intel-2.8.0/src/i830_lvds.c 2009-08-14 17:12:40.000000000 -0400 @@ -1624,3 +1624,89 @@ disable_exit: xf86DestroyI2CBusRec(intel_output->pDDCBus, TRUE, TRUE); xf86OutputDestroy(output); } + +void +i830_backlightonly_init(xf86OutputPtr output, + struct backlight_ctrl **backlight) +{ + I830Ptr pI830 = I830PTR(output->scrn); + struct backlight_ctrl *ctrl; + + /* FIXME: this should still parse the bios. + * The function in i830_bios.c doesn't do that ATM either, though. */ + /* For mobile chip, set default as true */ + if (IS_MOBILE(pI830) && !IS_I830(pI830)) + pI830->integrated_lvds = TRUE; + + if (!pI830->integrated_lvds) { + xf86DrvMsg(output->scrn->scrnIndex, X_INFO, + "Skipping LVDS from driver feature BDB's LVDS config info.\n"); + return; + } + + if (pI830->quirk_flag & QUIRK_IGNORE_LVDS) + return; + + /* Blacklist machines with BIOSes that list an LVDS panel without actually + * having one. + */ + if (pI830->quirk_flag & QUIRK_IGNORE_MACMINI_LVDS) { + /* It's a Mac Mini or Macbook Pro. + * + * Apple hardware is out to get us. The macbook pro has a real + * LVDS panel, but the mac mini does not, and they have the same + * device IDs. We'll distinguish by panel size, on the assumption + * that Apple isn't about to make any machines with an 800x600 + * display. + */ + + if (pI830->lvds_fixed_mode != NULL && + pI830->lvds_fixed_mode->HDisplay == 800 && + pI830->lvds_fixed_mode->VDisplay == 600) + { + xf86DrvMsg(output->scrn->scrnIndex, X_INFO, + "Suspected Mac Mini, ignoring the LVDS\n"); + return; + } + } + + ctrl = xcalloc (1, sizeof (struct backlight_ctrl)); + if (!ctrl) + return; + + /* Try to figure out which backlight control method to use */ + /* Can't access VGA space due to KMS - assuming native method is handled by kernel */ + if (i830_kernel_backlight_available(output)) + pI830->backlight_control_method = BCM_KERNEL; + else + pI830->backlight_control_method = BCM_LEGACY; + + switch (pI830->backlight_control_method) { + case BCM_NATIVE: + ctrl->set_backlight = i830_lvds_set_backlight_native; + ctrl->get_backlight = i830_lvds_get_backlight_native; + ctrl->backlight_max = i830_lvds_get_backlight_max_native(output); + break; + case BCM_LEGACY: + ctrl->set_backlight = i830_lvds_set_backlight_legacy; + ctrl->get_backlight = i830_lvds_get_backlight_legacy; + ctrl->backlight_max = 0xff; + break; + case BCM_COMBO: + ctrl->set_backlight = i830_lvds_set_backlight_combo; + ctrl->get_backlight = i830_lvds_get_backlight_combo; + ctrl->backlight_max = i830_lvds_get_backlight_max_combo(output); + break; + case BCM_KERNEL: + ctrl->set_backlight = i830_lvds_set_backlight_kernel; + ctrl->get_backlight = i830_lvds_get_backlight_kernel; + ctrl->backlight_max = i830_lvds_get_backlight_max_kernel(output); + break; + default: + xf86DrvMsg(output->scrn->scrnIndex, X_ERROR, "bad backlight control method\n"); + break; + } + + ctrl->backlight_duty_cycle = ctrl->get_backlight(output); + *backlight = ctrl; +}