Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 25 Aug 2014 22:37:19 +0400 (AMT)
From:      Hrant Dadivanyan <hrant@dadivanyan.net>
To:        Adrian Chadd <adrian@freebsd.org>
Cc:        "freebsd-mobile@freebsd.org" <freebsd-mobile@freebsd.org>
Subject:   Re: Fwd: svn commit: r270516 - head/sys/dev/drm2/i915
Message-ID:  <E1XLz8p-000LdV-6g@pandora.amnic.net>
In-Reply-To: <CAJ-Vmonw6WRDU5qqa1ogOkbb_gj%2BHjMO7ANbWt4dnkxdNV8hMg@mail.gmail.com>

next in thread | previous in thread | raw e-mail | index | archive | help
> This fixes the brightness on a Lenovo X230. The buttons don't yet work
> - they end up setting the value +1 or -1 from the current setting, but
> no further.
> 

The same on Lenovo X1 Carbon with 10-STABLE - buttons do +1 or -1 only,
but hw.acpi.video.lcd0.brightness accepts any value. Not all values
actually changes the brightness, but some do - all tenths for example.
hw.acpi.video.lcd0.fullpower and .economy are also ignored, but custom
entry on /etc/devd.conf solves this by setting .brightness directly,
depending on AC status.

Finally can enjoy long battery life, thank you very much !
Hrant

> But, I can at least now control the brightness on this damned thing!
> 
> 
> -a
> 
> 
> ---------- Forwarded message ----------
> From: Adrian Chadd <adrian@freebsd.org>
> Date: 24 August 2014 22:03
> Subject: svn commit: r270516 - head/sys/dev/drm2/i915
> To: src-committers@freebsd.org, svn-src-all@freebsd.org,
> svn-src-head@freebsd.org
> 
> 
> Author: adrian
> Date: Mon Aug 25 05:03:10 2014
> New Revision: 270516
> URL: http://svnweb.freebsd.org/changeset/base/270516
> 
> Log:
>   i915 driver - enable opregion handle; program CADL.
> 
>   add opregion handling for drm2 - which exposes some ACPI video configuration
>   pieces that some Lenovo laptop models use to flesh out which video device
>   to speak to.  This enables the brightness control in ACPI to work
> these models.
> 
>   The CADL bits are also important - it's used to figure out which ACPI
>   events to hook the brightness buttons into.  It doesn't yet seem to work
>   for me, but it does for the OP.
> 
>   Tested:
> 
>   * Lenovo X230 (mine)
>   * OP: ASUS UX51VZ
> 
>   PR:   190186
>   Submitted by: Henry Hu <henry.hu.sh@gmail.com>
>   Reviewed by:  dumbbell
> 
> Modified:
>   head/sys/dev/drm2/i915/i915_drv.h
>   head/sys/dev/drm2/i915/i915_irq.c
>   head/sys/dev/drm2/i915/intel_opregion.c
> 
> Modified: head/sys/dev/drm2/i915/i915_drv.h
> ==============================================================================
> --- head/sys/dev/drm2/i915/i915_drv.h   Mon Aug 25 03:02:38 2014
>  (r270515)
> +++ head/sys/dev/drm2/i915/i915_drv.h   Mon Aug 25 05:03:10 2014
>  (r270516)
> @@ -1242,10 +1242,11 @@ extern void intel_iic_reset(struct drm_d
> 
>  /* intel_opregion.c */
>  int intel_opregion_setup(struct drm_device *dev);
> -extern int intel_opregion_init(struct drm_device *dev);
> +extern void intel_opregion_init(struct drm_device *dev);
>  extern void intel_opregion_fini(struct drm_device *dev);
> -extern void opregion_asle_intr(struct drm_device *dev);
> -extern void opregion_enable_asle(struct drm_device *dev);
> +extern void intel_opregion_asle_intr(struct drm_device *dev);
> +extern void intel_opregion_gse_intr(struct drm_device *dev);
> +extern void intel_opregion_enable_asle(struct drm_device *dev);
> 
>  /* i915_gem_gtt.c */
>  int i915_gem_init_aliasing_ppgtt(struct drm_device *dev);
> 
> Modified: head/sys/dev/drm2/i915/i915_irq.c
> ==============================================================================
> --- head/sys/dev/drm2/i915/i915_irq.c   Mon Aug 25 03:02:38 2014
>  (r270515)
> +++ head/sys/dev/drm2/i915/i915_irq.c   Mon Aug 25 05:03:10 2014
>  (r270516)
> @@ -537,11 +537,7 @@ ivybridge_irq_handler(void *arg)
>                 notify_ring(dev, &dev_priv->rings[BCS]);
> 
>         if (de_iir & DE_GSE_IVB) {
> -#if 1
> -               KIB_NOTYET();
> -#else
>                 intel_opregion_gse_intr(dev);
> -#endif
>         }
> 
>         if (de_iir & DE_PLANEA_FLIP_DONE_IVB) {
> @@ -649,11 +645,7 @@ ironlake_irq_handler(void *arg)
>                 notify_ring(dev, &dev_priv->rings[BCS]);
> 
>         if (de_iir & DE_GSE) {
> -#if 1
> -               KIB_NOTYET();
> -#else
>                 intel_opregion_gse_intr(dev);
> -#endif
>         }
> 
>         if (de_iir & DE_PLANEA_FLIP_DONE) {
> @@ -1055,11 +1047,7 @@ i915_driver_irq_handler(void *arg)
> 
> 
>                 if (blc_event || (iir & I915_ASLE_INTERRUPT)) {
> -#if 1
> -                       KIB_NOTYET();
> -#else
>                         intel_opregion_asle_intr(dev);
> -#endif
>                 }
> 
>                 /* With MSI, interrupts are only generated when iir
> @@ -1781,11 +1769,7 @@ i915_driver_irq_postinstall(struct drm_d
>                 I915_WRITE(PORT_HOTPLUG_EN, hotplug_en);
>         }
> 
> -#if 1
> -       KIB_NOTYET();
> -#else
>         intel_opregion_enable_asle(dev);
> -#endif
> 
>         return 0;
>  }
> 
> Modified: head/sys/dev/drm2/i915/intel_opregion.c
> ==============================================================================
> --- head/sys/dev/drm2/i915/intel_opregion.c     Mon Aug 25 03:02:38
> 2014        (r270515)
> +++ head/sys/dev/drm2/i915/intel_opregion.c     Mon Aug 25 05:03:10
> 2014        (r270516)
> @@ -32,6 +32,9 @@ __FBSDID("$FreeBSD$");
>  #include <dev/drm2/i915/i915_drm.h>
>  #include <dev/drm2/i915/i915_drv.h>
>  #include <dev/drm2/i915/intel_drv.h>
> +#include <contrib/dev/acpica/include/acpi.h>
> +#include <contrib/dev/acpica/include/accommon.h>
> +#include <dev/acpica/acpivar.h>
> 
>  #define PCI_ASLE 0xe4
>  #define PCI_ASLS 0xfc
> @@ -144,7 +147,7 @@ struct opregion_asle {
>  #define ACPI_DIGITAL_OUTPUT (3<<8)
>  #define ACPI_LVDS_OUTPUT (4<<8)
> 
> -#ifdef CONFIG_ACPI
> +#if 1
>  static u32 asle_set_backlight(struct drm_device *dev, u32 bclp)
>  {
>         struct drm_i915_private *dev_priv = dev->dev_private;
> @@ -289,6 +292,7 @@ void intel_opregion_enable_asle(struct d
> 
>  static struct intel_opregion *system_opregion;
> 
> +#if 0
>  static int intel_opregion_video_event(struct notifier_block *nb,
>                                       unsigned long val, void *data)
>  {
> @@ -319,6 +323,7 @@ static int intel_opregion_video_event(st
>  static struct notifier_block intel_opregion_notifier = {
>         .notifier_call = intel_opregion_video_event,
>  };
> +#endif
> 
>  /*
>   * Initialise the DIDL field in opregion. This passes a list of devices to
> @@ -326,37 +331,72 @@ static struct notifier_block intel_opreg
>   * (version 3)
>   */
> 
> +static int acpi_is_video_device(ACPI_HANDLE devh) {
> +       ACPI_HANDLE h;
> +       if (ACPI_FAILURE(AcpiGetHandle(devh, "_DOD", &h)) ||
> +               ACPI_FAILURE(AcpiGetHandle(devh, "_DOS", &h))) {
> +               return 0;
> +       }
> +       return 1;
> +}
> +
>  static void intel_didl_outputs(struct drm_device *dev)
>  {
>         struct drm_i915_private *dev_priv = dev->dev_private;
>         struct intel_opregion *opregion = &dev_priv->opregion;
>         struct drm_connector *connector;
> -       acpi_handle handle;
> -       struct acpi_device *acpi_dev, *acpi_cdev, *acpi_video_bus = NULL;
> -       unsigned long long device_id;
> -       acpi_status status;
> +       u32 device_id;
> +       ACPI_HANDLE handle, acpi_video_bus, acpi_cdev;
> +       ACPI_STATUS status;
>         int i = 0;
> 
> -       handle = DEVICE_ACPI_HANDLE(&dev->pdev->dev);
> -       if (!handle || ACPI_FAILURE(acpi_bus_get_device(handle, &acpi_dev)))
> +       handle = acpi_get_handle(dev->device);
> +       if (!handle)
>                 return;
> 
> -       if (acpi_is_video_device(acpi_dev))
> -               acpi_video_bus = acpi_dev;
> +       if (acpi_is_video_device(handle))
> +               acpi_video_bus = handle;
>         else {
> +               acpi_cdev = NULL;
> +               acpi_video_bus = NULL;
> +               while (AcpiGetNextObject(ACPI_TYPE_DEVICE, handle, acpi_cdev,
> +                                       &acpi_cdev) != AE_NOT_FOUND) {
> +                       if (acpi_is_video_device(acpi_cdev)) {
> +                               acpi_video_bus = acpi_cdev;
> +                               break;
> +                       }
> +               }
> +#if 0
>                 list_for_each_entry(acpi_cdev, &acpi_dev->children, node) {
>                         if (acpi_is_video_device(acpi_cdev)) {
>                                 acpi_video_bus = acpi_cdev;
>                                 break;
>                         }
>                 }
> +#endif
>         }
> 
>         if (!acpi_video_bus) {
> -               printk(KERN_WARNING "No ACPI video bus found\n");
> +               device_printf(dev->device, "No ACPI video bus found\n");
>                 return;
>         }
> 
> +       acpi_cdev = NULL;
> +       while (AcpiGetNextObject(ACPI_TYPE_DEVICE, acpi_video_bus, acpi_cdev,
> +                               &acpi_cdev) != AE_NOT_FOUND) {
> +               if (i >= 8) {
> +                       device_printf(dev->device, "More than 8
> outputs detected\n");
> +                       return;
> +               }
> +               status = acpi_GetInteger(acpi_cdev, "_ADR", &device_id);
> +               if (ACPI_SUCCESS(status)) {
> +                       if (!device_id)
> +                               goto blind_set;
> +                       opregion->acpi->didl[i] = (u32)(device_id & 0x0f0f);
> +                       i++;
> +               }
> +       }
> +#if 0
>         list_for_each_entry(acpi_cdev, &acpi_video_bus->children, node) {
>                 if (i >= 8) {
>                         dev_printk(KERN_ERR, &dev->pdev->dev,
> @@ -373,6 +413,7 @@ static void intel_didl_outputs(struct dr
>                         i++;
>                 }
>         }
> +#endif
> 
>  end:
>         /* If fewer than 8 outputs, the list must be null terminated */
> @@ -417,6 +458,25 @@ blind_set:
>         goto end;
>  }
> 
> +static void intel_setup_cadls(struct drm_device *dev)
> +{
> +       struct drm_i915_private *dev_priv = dev->dev_private;
> +       struct intel_opregion *opregion = &dev_priv->opregion;
> +       int i = 0;
> +       u32 disp_id;
> +
> +       /* Initialize the CADL field by duplicating the DIDL values.
> +        * Technically, this is not always correct as display outputs may exist,
> +        * but not active. This initialization is necessary for some Clevo
> +        * laptops that check this field before processing the brightness and
> +        * display switching hotkeys. Just like DIDL, CADL is NULL-terminated if
> +        * there are less than eight devices. */
> +       do {
> +               disp_id = opregion->acpi->didl[i];
> +               opregion->acpi->cadl[i] = disp_id;
> +       } while (++i < 8 && disp_id != 0);
> +}
> +
>  void intel_opregion_init(struct drm_device *dev)
>  {
>         struct drm_i915_private *dev_priv = dev->dev_private;
> @@ -426,8 +486,10 @@ void intel_opregion_init(struct drm_devi
>                 return;
> 
>         if (opregion->acpi) {
> -               if (drm_core_check_feature(dev, DRIVER_MODESET))
> +               if (drm_core_check_feature(dev, DRIVER_MODESET)) {
>                         intel_didl_outputs(dev);
> +                       intel_setup_cadls(dev);
> +               }
> 
>                 /* Notify BIOS we are ready to handle ACPI video ext notifs.
>                  * Right now, all the events are handled by the ACPI
> video module.
> @@ -436,7 +498,9 @@ void intel_opregion_init(struct drm_devi
>                 opregion->acpi->drdy = 1;
> 
>                 system_opregion = opregion;
> +#if 0
>                 register_acpi_notifier(&intel_opregion_notifier);
> +#endif
>         }
> 
>         if (opregion->asle)
> @@ -455,11 +519,13 @@ void intel_opregion_fini(struct drm_devi
>                 opregion->acpi->drdy = 0;
> 
>                 system_opregion = NULL;
> +#if 0
>                 unregister_acpi_notifier(&intel_opregion_notifier);
> +#endif
>         }
> 
>         /* just clear all opregion memory pointers now */
> -       iounmap(opregion->header);
> +       pmap_unmapdev((vm_offset_t)opregion->header, OPREGION_SIZE);
>         opregion->header = NULL;
>         opregion->acpi = NULL;
>         opregion->swsci = NULL;
> _______________________________________________
> freebsd-mobile@freebsd.org mailing list
> http://lists.freebsd.org/mailman/listinfo/freebsd-mobile
> To unsubscribe, send any mail to "freebsd-mobile-unsubscribe@freebsd.org"

-- 
Hrant Dadivanyan (aka Ran d'Adi)		hrant(at)dadivanyan.net
/* "Feci quod potui, faciant meliora potentes." */       ran(at)psg.com



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?E1XLz8p-000LdV-6g>