linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Jafar Akhondali <jafar.akhoondali@gmail.com>
To: Hans de Goede <hdegoede@redhat.com>
Cc: jlee@suse.com, linux-kernel@vger.kernel.org,
	platform-driver-x86@vger.kernel.org, mgross@linux.intel.com
Subject: Re: [PATCH v2] platform/x86: acer-wmi: Add Turbo Mode support for Acer PH315-53
Date: Wed, 28 Jul 2021 13:15:41 +0430	[thread overview]
Message-ID: <CAMW3L+03N2bFK2YFwQDgc_S9ajDpT2GbCL9H4+WWEchGq58Ogg@mail.gmail.com> (raw)
In-Reply-To: <CAMW3L+2yurdggGpYSHZw6x07SboxqYRrDA6B699=SagAVp6Euw@mail.gmail.com>

Hello,
I'm looking forward to comments on this patch.
Also as turbo mode is usually available only in gaming laptops, I've
also uploaded a demo video using this patch:
https://www.youtube.com/watch?v=sQ5TW30VuFc

Thanks in Advance


On Mon, Jul 12, 2021 at 2:55 AM Jafar Akhondali
<jafar.akhoondali@gmail.com> wrote:
>
> Looks like the previous patch got some indentation problems, here is
> the fixed version.
>
> The Acer Predator Helios series (usually denoted by PHxxx-yy) features
> a special key above the keyboard named "TURBO". The turbo key does 3
> things:
> 1. Set all fan's speeds to TURBO mode
> 2. Overclocks the CPU and GPU in the safe range
> 3. Turn on an LED just below the turbo button
>
> All of these actions are done by WMI function calls, and there is no
> custom OC level for turbo. It acts as a flag for enabling turbo
> mode instead of telling processors to use 1.3x of power.
>
> I've run some benchmark tests and it worked fine:
>
> GpuTest 0.7.0
> http://www.geeks3d.com
>
> Module: FurMark
> Normal mode Score: 7289 points (FPS: 121)
> Turbo mode Score: 7675 points (FPS: 127)
> Settings:
> - 1920x1080 fullscreen
> - antialiasing: Off
> - duration: 60000 ms
>
> Renderer:
> - GeForce RTX 2060/PCIe/SSE2
> - OpenGL: 4.6.0 NVIDIA 460.32.03
>
> This feature is presented by Acer officially and should not harm
> hardware in any case.
>
> A challenging part of implementing this feature is that calling overclocking
> the function requires knowing the exact count of fans for CPU and GPU
> for each model, which to the best of my knowledge is not available in
> the kernel.
>
> So after checking the official PredatorSense application methods, it
> turned out they have provided the software the list of fans in each model.
> I have access to the mentioned list, and all similar PH-iii-jj can be
> added easily by matching "DMI_PRODUCT_NAME".
>
> Creating a separate file for the gaming interface was not possible because
> the current WMI event GUID is needed for the turbo button, and it's not possible
> to register multiple functions on the same event GUID.
>
>
> Some small indent problems have been also fixed.
>
> Signed-off-by: JafarAkhondali <jafar.akhoondali@gmail.com>
> ---
>  drivers/platform/x86/acer-wmi.c | 243 ++++++++++++++++++++++++++++++--
>  1 file changed, 231 insertions(+), 12 deletions(-)
>
> diff --git a/drivers/platform/x86/acer-wmi.c b/drivers/platform/x86/acer-wmi.c
> index 85db9403cc14..06b25ddf04ee 100644
> --- a/drivers/platform/x86/acer-wmi.c
> +++ b/drivers/platform/x86/acer-wmi.c
> @@ -30,10 +30,12 @@
>  #include <linux/input/sparse-keymap.h>
>  #include <acpi/video.h>
>
> +
>  MODULE_AUTHOR("Carlos Corbacho");
>  MODULE_DESCRIPTION("Acer Laptop WMI Extras Driver");
>  MODULE_LICENSE("GPL");
>
> +
>  /*
>   * Magic Number
>   * Meaning is unknown - this number is required for writing to ACPI for AMW0
> @@ -59,7 +61,10 @@ MODULE_LICENSE("GPL");
>  #define ACER_WMID_SET_BRIGHTNESS_METHODID    6
>  #define ACER_WMID_GET_THREEG_METHODID        10
>  #define ACER_WMID_SET_THREEG_METHODID        11
> -
> +#define ACER_WMID_SET_GAMING_LED_METHODID 2
> +#define ACER_WMID_GET_GAMING_LED_METHODID 4
> +#define ACER_WMID_SET_GAMING_FAN_BEHAVIOR 14
> +#define ACER_WMID_SET_GAMING_MISC_SETTING_METHODID 22
>  /*
>   * Acer ACPI method GUIDs
>   */
> @@ -68,6 +73,7 @@ MODULE_LICENSE("GPL");
>  #define WMID_GUID1        "6AF4F258-B401-42FD-BE91-3D4AC2D7C0D3"
>  #define WMID_GUID2        "95764E09-FB56-4E83-B31A-37761F60994A"
>  #define WMID_GUID3        "61EF69EA-865C-4BC3-A502-A0DEBA0CB531"
> +#define WMID_GUID4        "7A4DDFE7-5B5D-40B4-8595-4408E0CC7F56"
>
>  /*
>   * Acer ACPI event GUIDs
> @@ -81,6 +87,7 @@ MODULE_ALIAS("wmi:676AA15E-6A47-4D9F-A2CC-1E6D18D14026");
>  enum acer_wmi_event_ids {
>      WMID_HOTKEY_EVENT = 0x1,
>      WMID_ACCEL_OR_KBD_DOCK_EVENT = 0x5,
> +    WMID_GAMING_TURBO_KEY_EVENT = 0x7,
>  };
>
>  static const struct key_entry acer_wmi_keymap[] __initconst = {
> @@ -144,6 +151,7 @@ struct event_return_value {
>
>  #define ACER_WMID3_GDS_TOUCHPAD        (1<<1)    /* Touchpad */
>
> +
>  /* Hotkey Customized Setting and Acer Application Status.
>   * Set Device Default Value and Report Acer Application Status.
>   * When Acer Application starts, it will run this method to inform
> @@ -215,6 +223,9 @@ struct hotkey_function_type_aa {
>  #define ACER_CAP_THREEG            BIT(4)
>  #define ACER_CAP_SET_FUNCTION_MODE    BIT(5)
>  #define ACER_CAP_KBD_DOCK        BIT(6)
> +#define ACER_CAP_TURBO_OC     BIT(7)
> +#define ACER_CAP_TURBO_LED     BIT(8)
> +#define ACER_CAP_TURBO_FAN     BIT(9)
>
>  /*
>   * Interface type flags
> @@ -224,6 +235,7 @@ enum interface_flags {
>      ACER_AMW0_V2,
>      ACER_WMID,
>      ACER_WMID_v2,
> +    ACER_WMID_GAMING,
>  };
>
>  #define ACER_DEFAULT_WIRELESS  0
> @@ -290,6 +302,9 @@ struct wmi_interface {
>  /* The static interface pointer, points to the currently detected interface */
>  static struct wmi_interface *interface;
>
> +/* The static gaming interface pointer, points to the currently
> detected gaming interface */
> +static struct wmi_interface *gaming_interface;
> +
>  /*
>   * Embedded Controller quirks
>   * Some laptops require us to directly access the EC to either enable or query
> @@ -301,6 +316,9 @@ struct quirk_entry {
>      u8 mailled;
>      s8 brightness;
>      u8 bluetooth;
> +    u8 turbo;
> +    u8 cpu_fans;
> +    u8 gpu_fans;
>  };
>
>  static struct quirk_entry *quirks;
> @@ -312,6 +330,10 @@ static void __init set_quirks(void)
>
>      if (quirks->brightness)
>          interface->capability |= ACER_CAP_BRIGHTNESS;
> +
> +    if (quirks->turbo)
> +        gaming_interface->capability |= ACER_CAP_TURBO_OC | ACER_CAP_TURBO_LED
> +                | ACER_CAP_TURBO_FAN;
>  }
>
>  static int __init dmi_matched(const struct dmi_system_id *dmi)
> @@ -340,6 +362,12 @@ static struct quirk_entry quirk_acer_travelmate_2490 = {
>      .mailled = 1,
>  };
>
> +static struct quirk_entry quirk_acer_predator_ph315_53 = {
> +    .turbo = 1,
> +    .cpu_fans = 1,
> +    .gpu_fans = 1,
> +};
> +
>  /* This AMW0 laptop has no bluetooth */
>  static struct quirk_entry quirk_medion_md_98300 = {
>      .wireless = 1,
> @@ -507,6 +535,15 @@ static const struct dmi_system_id acer_quirks[]
> __initconst = {
>          },
>          .driver_data = &quirk_acer_travelmate_2490,
>      },
> +    {
> +        .callback = dmi_matched,
> +        .ident = "Acer Predator PH315-53",
> +        .matches = {
> +            DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
> +            DMI_MATCH(DMI_PRODUCT_NAME, "Predator PH315-53"),
> +        },
> +        .driver_data = &quirk_acer_predator_ph315_53,
> +    },
>      {
>          .callback = set_force_caps,
>          .ident = "Acer Aspire Switch 10E SW3-016",
> @@ -903,7 +940,7 @@ static acpi_status __init AMW0_set_capabilities(void)
>       */
>      if (wmi_has_guid(AMW0_GUID2)) {
>          if ((quirks != &quirk_unknown) ||
> -            !AMW0_set_cap_acpi_check_device())
> +            !AMW0_set_cap_acpi_check_device())
>              interface->capability |= ACER_CAP_WIRELESS;
>          return AE_OK;
>      }
> @@ -1344,6 +1381,93 @@ static struct wmi_interface wmid_v2_interface = {
>      .type = ACER_WMID_v2,
>  };
>
> +
> +/*
> + * WMID Gaming interface
> + */
> +
> +static struct wmi_interface wmid_gaming_interface = {
> +    .type = ACER_WMID_GAMING
> +};
> +
> +static acpi_status
> +WMI_gaming_execute_u64(u32 method_id, u64 in, u64 *out)
> +{
> +    struct acpi_buffer input = { (acpi_size) sizeof(u64), (void *)(&in) };
> +    struct acpi_buffer result = { ACPI_ALLOCATE_BUFFER, NULL };
> +    union acpi_object *obj;
> +    u32 tmp = 0;
> +    acpi_status status;
> +
> +    status = wmi_evaluate_method(WMID_GUID4, 0, method_id, &input, &result);
> +
> +    if (ACPI_FAILURE(status))
> +        return status;
> +    obj = (union acpi_object *) result.pointer;
> +
> +    if (obj) {
> +        if (obj->type == ACPI_TYPE_BUFFER &&
> +            (obj->buffer.length == sizeof(u32) ||
> +             obj->buffer.length == sizeof(u64))) {
> +            tmp = *((u64 *) obj->buffer.pointer);
> +        } else if (obj->type == ACPI_TYPE_INTEGER) {
> +            tmp = (u64) obj->integer.value;
> +        }
> +    }
> +
> +    if (out)
> +        *out = tmp;
> +
> +    kfree(result.pointer);
> +
> +    return status;
> +}
> +
> +static acpi_status WMID_gaming_set_u64(u64 value, u32 cap)
> +{
> +    u32 method_id = 0;
> +
> +    switch (cap) {
> +    case ACER_CAP_TURBO_LED:
> +        method_id = ACER_WMID_SET_GAMING_LED_METHODID;
> +        break;
> +    case ACER_CAP_TURBO_FAN:
> +        method_id = ACER_WMID_SET_GAMING_FAN_BEHAVIOR;
> +        break;
> +    case ACER_CAP_TURBO_OC:
> +        method_id = ACER_WMID_SET_GAMING_MISC_SETTING_METHODID;
> +        break;
> +    default:
> +        return AE_ERROR;
> +    }
> +    return WMI_gaming_execute_u64(method_id, value, NULL);
> +}
> +
> +static acpi_status WMID_gaming_get_u64(u64 *value, u32 cap)
> +{
> +    acpi_status status;
> +    u64 result;
> +    u64 input;
> +    u32 method_id;
> +
> +
> +    switch (cap) {
> +    case ACER_CAP_TURBO_LED:
> +        method_id = ACER_WMID_GET_GAMING_LED_METHODID;
> +        input = 0x1;
> +        break;
> +    default:
> +        return AE_ERROR;
> +    }
> +
> +    status = WMI_gaming_execute_u64(method_id, input, &result);
> +    if (ACPI_SUCCESS(status))
> +        *value = (u64) result;
> +
> +    return status;
> +}
> +
> +
>  /*
>   * Generic Device (interface-independent)
>   */
> @@ -1374,7 +1498,6 @@ static acpi_status get_u32(u32 *value, u32 cap)
>              status = WMID_get_u32(value, cap);
>          break;
>      }
> -
>      return status;
>  }
>
> @@ -1422,6 +1545,34 @@ static acpi_status set_u32(u32 value, u32 cap)
>      return AE_BAD_PARAMETER;
>  }
>
> +static acpi_status set_u64(u64 value, u32 cap)
> +{
> +    if (gaming_interface->capability & cap) {
> +        switch (gaming_interface->type) {
> +        case ACER_WMID_GAMING:
> +            return WMID_gaming_set_u64(value, cap);
> +        default:
> +            return AE_BAD_PARAMETER;
> +        }
> +    }
> +    return AE_BAD_PARAMETER;
> +}
> +
> +
> +static acpi_status get_u64(u64 *value, u32 cap)
> +{
> +    acpi_status status = AE_ERROR;
> +
> +    if (gaming_interface->capability & cap) {
> +        switch (gaming_interface->type) {
> +        case ACER_WMID_GAMING:
> +            status = WMID_gaming_get_u64(value, cap);
> +            break;
> +        }
> +    }
> +    return status;
> +}
> +
>  static void __init acer_commandline_init(void)
>  {
>      /*
> @@ -1501,7 +1652,7 @@ static int acer_backlight_init(struct device *dev)
>      props.type = BACKLIGHT_PLATFORM;
>      props.max_brightness = max_brightness;
>      bd = backlight_device_register("acer-wmi", dev, NULL, &acer_bl_ops,
> -                       &props);
> +                       &props);
>      if (IS_ERR(bd)) {
>          pr_err("Could not register Acer backlight device\n");
>          acer_backlight_device = NULL;
> @@ -1575,6 +1726,67 @@ static int acer_gsensor_event(void)
>      return 0;
>  }
>
> +/*
> + *  Predator series turbo button
> + */
> +static int acer_toggle_turbo(void)
> +{
> +    /* Get current state from turbo button */
> +    u64 turbo_led_state, gpu_fan_config1, gpu_fan_config2;
> +    u8 i;
> +
> +    if (ACPI_FAILURE(get_u64(&turbo_led_state, ACER_CAP_TURBO_LED)))
> +        return -1;
> +
> +    if (turbo_led_state) {
> +        // turns off turbo led
> +        set_u64(0x1, ACER_CAP_TURBO_LED);
> +
> +        // set FAN mode to auto
> +        if (quirks->cpu_fans > 0)
> +            gpu_fan_config2 |= 1;
> +        for (i = 0; i < (quirks->cpu_fans + quirks->gpu_fans); ++i)
> +            gpu_fan_config2 |= 1 << (i + 1);
> +        for (i = 0; i < quirks->gpu_fans; ++i)
> +            gpu_fan_config2 |= 1 << (i + 3);
> +        if (quirks->cpu_fans > 0)
> +            gpu_fan_config1 |= 1;
> +        for (i = 0; i < (quirks->cpu_fans + quirks->gpu_fans); ++i)
> +            gpu_fan_config1 |= 1 << (2 * i + 2);
> +        for (i = 0; i < quirks->gpu_fans; ++i)
> +            gpu_fan_config1 |= 1 << (2 * i + 6);
> +        set_u64(gpu_fan_config2 | gpu_fan_config1 << 16, ACER_CAP_TURBO_FAN);
> +
> +        // set OC to normal
> +        set_u64(0x5, ACER_CAP_TURBO_OC);
> +        set_u64(0x7, ACER_CAP_TURBO_OC);
> +    } else {
> +        // turn on turbo led
> +        set_u64(0x10001, ACER_CAP_TURBO_LED);
> +
> +        // set FAN to turbo mode
> +        if (quirks->cpu_fans > 0)
> +            gpu_fan_config2 |= 1;
> +        for (i = 0; i < (quirks->cpu_fans + quirks->gpu_fans); ++i)
> +            gpu_fan_config2 |= 1 << (i + 1);
> +        for (i = 0; i < quirks->gpu_fans; ++i)
> +            gpu_fan_config2 |= 1 << (i + 3);
> +        if (quirks->cpu_fans > 0)
> +            gpu_fan_config1 |= 2;
> +        for (i = 0; i < (quirks->cpu_fans + quirks->gpu_fans); ++i)
> +            gpu_fan_config1 |= 2 << (2 * i + 2);
> +        for (i = 0; i < quirks->gpu_fans; ++i)
> +            gpu_fan_config1 |= 2 << (2 * i + 6);
> +        set_u64(gpu_fan_config2 | gpu_fan_config1 << 16, ACER_CAP_TURBO_FAN);
> +
> +        // set OC to turbo mode
> +        set_u64(0x205, ACER_CAP_TURBO_OC);
> +        set_u64(0x207, ACER_CAP_TURBO_OC);
> +    }
> +    return turbo_led_state;
> +}
> +
> +
>  /*
>   * Switch series keyboard dock status
>   */
> @@ -1605,7 +1817,7 @@ static void acer_kbd_dock_get_initial_state(void)
>      status = wmi_evaluate_method(WMID_GUID3, 0, 0x2, &input_buf, &output_buf);
>      if (ACPI_FAILURE(status)) {
>          pr_err("Error getting keyboard-dock initial status: %s\n",
> -               acpi_format_exception(status));
> +               acpi_format_exception(status));
>          return;
>      }
>
> @@ -1618,7 +1830,7 @@ static void acer_kbd_dock_get_initial_state(void)
>      output = obj->buffer.pointer;
>      if (output[0] != 0x00 || (output[3] != 0x05 && output[3] != 0x45)) {
>          pr_err("Unexpected output [0]=0x%02x [3]=0x%02x getting
> keyboard-dock initial status\n",
> -               output[0], output[3]);
> +               output[0], output[3]);
>          goto out_free_obj;
>      }
>
> @@ -1759,7 +1971,7 @@ static int acer_rfkill_init(struct device *dev)
>      rfkill_inited = true;
>
>      if ((ec_raw_mode || !wmi_has_guid(ACERWMID_EVENT_GUID)) &&
> -        has_cap(ACER_CAP_WIRELESS | ACER_CAP_BLUETOOTH | ACER_CAP_THREEG))
> +        has_cap(ACER_CAP_WIRELESS | ACER_CAP_BLUETOOTH | ACER_CAP_THREEG))
>          schedule_delayed_work(&acer_rfkill_work,
>              round_jiffies_relative(HZ));
>
> @@ -1782,7 +1994,7 @@ static int acer_rfkill_init(struct device *dev)
>  static void acer_rfkill_exit(void)
>  {
>      if ((ec_raw_mode || !wmi_has_guid(ACERWMID_EVENT_GUID)) &&
> -        has_cap(ACER_CAP_WIRELESS | ACER_CAP_BLUETOOTH | ACER_CAP_THREEG))
> +        has_cap(ACER_CAP_WIRELESS | ACER_CAP_BLUETOOTH | ACER_CAP_THREEG))
>          cancel_delayed_work_sync(&acer_rfkill_work);
>
>      if (has_cap(ACER_CAP_WIRELESS)) {
> @@ -1872,6 +2084,10 @@ static void acer_wmi_notify(u32 value, void *context)
>          acer_gsensor_event();
>          acer_kbd_dock_event(&return_value);
>          break;
> +    case WMID_GAMING_TURBO_KEY_EVENT:
> +        if (return_value.key_num == 0x4)
> +            acer_toggle_turbo();
> +        break;
>      default:
>          pr_warn("Unknown function number - %d - %d\n",
>              return_value.function, return_value.key_num);
> @@ -2251,8 +2467,8 @@ static int __init acer_wmi_init(void)
>       * in the past quirk list.
>       */
>      if (wmi_has_guid(AMW0_GUID1) &&
> -        !dmi_check_system(amw0_whitelist) &&
> -        quirks == &quirk_unknown) {
> +        !dmi_check_system(amw0_whitelist) &&
> +        quirks == &quirk_unknown) {
>          pr_debug("Unsupported machine has AMW0_GUID1, unable to load\n");
>          return -ENODEV;
>      }
> @@ -2266,8 +2482,11 @@ static int __init acer_wmi_init(void)
>      if (!wmi_has_guid(AMW0_GUID1) && wmi_has_guid(WMID_GUID1))
>          interface = &wmid_interface;
>
> -    if (wmi_has_guid(WMID_GUID3))
> +    if (wmi_has_guid(WMID_GUID3)) {
>          interface = &wmid_v2_interface;
> +        if (wmi_has_guid(WMID_GUID4))
> +            gaming_interface = &wmid_gaming_interface;
> +    }
>
>      if (interface)
>          dmi_walk(type_aa_dmi_decode, NULL);
> @@ -2316,7 +2535,7 @@ static int __init acer_wmi_init(void)
>          interface->capability = force_caps;
>
>      if (wmi_has_guid(WMID_GUID3) &&
> -        (interface->capability & ACER_CAP_SET_FUNCTION_MODE)) {
> +        (interface->capability & ACER_CAP_SET_FUNCTION_MODE)) {
>          if (ACPI_FAILURE(acer_wmi_enable_rf_button()))
>              pr_warn("Cannot enable RF Button Driver\n");
>
> --
> 2.27.0

  reply	other threads:[~2021-07-28  8:45 UTC|newest]

Thread overview: 3+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2021-07-11 22:25 [PATCH v2] platform/x86: acer-wmi: Add Turbo Mode support for Acer PH315-53 Jafar Akhondali
2021-07-28  8:45 ` Jafar Akhondali [this message]
2021-08-02 11:39 ` Hans de Goede

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=CAMW3L+03N2bFK2YFwQDgc_S9ajDpT2GbCL9H4+WWEchGq58Ogg@mail.gmail.com \
    --to=jafar.akhoondali@gmail.com \
    --cc=hdegoede@redhat.com \
    --cc=jlee@suse.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=mgross@linux.intel.com \
    --cc=platform-driver-x86@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).