linux/drivers/gpu/drm/radeon/radeon_atpx_handler.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 * Copyright (c) 2010 Red Hat Inc.
   4 * Author : Dave Airlie <airlied@redhat.com>
   5 *
   6 * ATPX support for both Intel/ATI
   7 */
   8#include <linux/vga_switcheroo.h>
   9#include <linux/slab.h>
  10#include <linux/acpi.h>
  11#include <linux/pci.h>
  12#include <linux/delay.h>
  13
  14#include "radeon_acpi.h"
  15
  16struct radeon_atpx_functions {
  17        bool px_params;
  18        bool power_cntl;
  19        bool disp_mux_cntl;
  20        bool i2c_mux_cntl;
  21        bool switch_start;
  22        bool switch_end;
  23        bool disp_connectors_mapping;
  24        bool disp_detetion_ports;
  25};
  26
  27struct radeon_atpx {
  28        acpi_handle handle;
  29        struct radeon_atpx_functions functions;
  30        bool is_hybrid;
  31        bool dgpu_req_power_for_displays;
  32};
  33
  34static struct radeon_atpx_priv {
  35        bool atpx_detected;
  36        bool bridge_pm_usable;
  37        /* handle for device - and atpx */
  38        acpi_handle dhandle;
  39        struct radeon_atpx atpx;
  40} radeon_atpx_priv;
  41
  42struct atpx_verify_interface {
  43        u16 size;               /* structure size in bytes (includes size field) */
  44        u16 version;            /* version */
  45        u32 function_bits;      /* supported functions bit vector */
  46} __packed;
  47
  48struct atpx_px_params {
  49        u16 size;               /* structure size in bytes (includes size field) */
  50        u32 valid_flags;        /* which flags are valid */
  51        u32 flags;              /* flags */
  52} __packed;
  53
  54struct atpx_power_control {
  55        u16 size;
  56        u8 dgpu_state;
  57} __packed;
  58
  59struct atpx_mux {
  60        u16 size;
  61        u16 mux;
  62} __packed;
  63
  64bool radeon_has_atpx(void) {
  65        return radeon_atpx_priv.atpx_detected;
  66}
  67
  68bool radeon_has_atpx_dgpu_power_cntl(void) {
  69        return radeon_atpx_priv.atpx.functions.power_cntl;
  70}
  71
  72bool radeon_is_atpx_hybrid(void) {
  73        return radeon_atpx_priv.atpx.is_hybrid;
  74}
  75
  76bool radeon_atpx_dgpu_req_power_for_displays(void) {
  77        return radeon_atpx_priv.atpx.dgpu_req_power_for_displays;
  78}
  79
  80/**
  81 * radeon_atpx_call - call an ATPX method
  82 *
  83 * @handle: acpi handle
  84 * @function: the ATPX function to execute
  85 * @params: ATPX function params
  86 *
  87 * Executes the requested ATPX function (all asics).
  88 * Returns a pointer to the acpi output buffer.
  89 */
  90static union acpi_object *radeon_atpx_call(acpi_handle handle, int function,
  91                                           struct acpi_buffer *params)
  92{
  93        acpi_status status;
  94        union acpi_object atpx_arg_elements[2];
  95        struct acpi_object_list atpx_arg;
  96        struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
  97
  98        atpx_arg.count = 2;
  99        atpx_arg.pointer = &atpx_arg_elements[0];
 100
 101        atpx_arg_elements[0].type = ACPI_TYPE_INTEGER;
 102        atpx_arg_elements[0].integer.value = function;
 103
 104        if (params) {
 105                atpx_arg_elements[1].type = ACPI_TYPE_BUFFER;
 106                atpx_arg_elements[1].buffer.length = params->length;
 107                atpx_arg_elements[1].buffer.pointer = params->pointer;
 108        } else {
 109                /* We need a second fake parameter */
 110                atpx_arg_elements[1].type = ACPI_TYPE_INTEGER;
 111                atpx_arg_elements[1].integer.value = 0;
 112        }
 113
 114        status = acpi_evaluate_object(handle, NULL, &atpx_arg, &buffer);
 115
 116        /* Fail only if calling the method fails and ATPX is supported */
 117        if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) {
 118                printk("failed to evaluate ATPX got %s\n",
 119                       acpi_format_exception(status));
 120                kfree(buffer.pointer);
 121                return NULL;
 122        }
 123
 124        return buffer.pointer;
 125}
 126
 127/**
 128 * radeon_atpx_parse_functions - parse supported functions
 129 *
 130 * @f: supported functions struct
 131 * @mask: supported functions mask from ATPX
 132 *
 133 * Use the supported functions mask from ATPX function
 134 * ATPX_FUNCTION_VERIFY_INTERFACE to determine what functions
 135 * are supported (all asics).
 136 */
 137static void radeon_atpx_parse_functions(struct radeon_atpx_functions *f, u32 mask)
 138{
 139        f->px_params = mask & ATPX_GET_PX_PARAMETERS_SUPPORTED;
 140        f->power_cntl = mask & ATPX_POWER_CONTROL_SUPPORTED;
 141        f->disp_mux_cntl = mask & ATPX_DISPLAY_MUX_CONTROL_SUPPORTED;
 142        f->i2c_mux_cntl = mask & ATPX_I2C_MUX_CONTROL_SUPPORTED;
 143        f->switch_start = mask & ATPX_GRAPHICS_DEVICE_SWITCH_START_NOTIFICATION_SUPPORTED;
 144        f->switch_end = mask & ATPX_GRAPHICS_DEVICE_SWITCH_END_NOTIFICATION_SUPPORTED;
 145        f->disp_connectors_mapping = mask & ATPX_GET_DISPLAY_CONNECTORS_MAPPING_SUPPORTED;
 146        f->disp_detetion_ports = mask & ATPX_GET_DISPLAY_DETECTION_PORTS_SUPPORTED;
 147}
 148
 149/**
 150 * radeon_atpx_validate_functions - validate ATPX functions
 151 *
 152 * @atpx: radeon atpx struct
 153 *
 154 * Validate that required functions are enabled (all asics).
 155 * returns 0 on success, error on failure.
 156 */
 157static int radeon_atpx_validate(struct radeon_atpx *atpx)
 158{
 159        u32 valid_bits = 0;
 160
 161        if (atpx->functions.px_params) {
 162                union acpi_object *info;
 163                struct atpx_px_params output;
 164                size_t size;
 165
 166                info = radeon_atpx_call(atpx->handle, ATPX_FUNCTION_GET_PX_PARAMETERS, NULL);
 167                if (!info)
 168                        return -EIO;
 169
 170                memset(&output, 0, sizeof(output));
 171
 172                size = *(u16 *) info->buffer.pointer;
 173                if (size < 10) {
 174                        printk("ATPX buffer is too small: %zu\n", size);
 175                        kfree(info);
 176                        return -EINVAL;
 177                }
 178                size = min(sizeof(output), size);
 179
 180                memcpy(&output, info->buffer.pointer, size);
 181
 182                valid_bits = output.flags & output.valid_flags;
 183
 184                kfree(info);
 185        }
 186
 187        /* if separate mux flag is set, mux controls are required */
 188        if (valid_bits & ATPX_SEPARATE_MUX_FOR_I2C) {
 189                atpx->functions.i2c_mux_cntl = true;
 190                atpx->functions.disp_mux_cntl = true;
 191        }
 192        /* if any outputs are muxed, mux controls are required */
 193        if (valid_bits & (ATPX_CRT1_RGB_SIGNAL_MUXED |
 194                          ATPX_TV_SIGNAL_MUXED |
 195                          ATPX_DFP_SIGNAL_MUXED))
 196                atpx->functions.disp_mux_cntl = true;
 197
 198        /* some bioses set these bits rather than flagging power_cntl as supported */
 199        if (valid_bits & (ATPX_DYNAMIC_PX_SUPPORTED |
 200                          ATPX_DYNAMIC_DGPU_POWER_OFF_SUPPORTED))
 201                atpx->functions.power_cntl = true;
 202
 203        atpx->is_hybrid = false;
 204        if (valid_bits & ATPX_MS_HYBRID_GFX_SUPPORTED) {
 205                printk("ATPX Hybrid Graphics\n");
 206                /*
 207                 * Disable legacy PM methods only when pcie port PM is usable,
 208                 * otherwise the device might fail to power off or power on.
 209                 */
 210                atpx->functions.power_cntl = !radeon_atpx_priv.bridge_pm_usable;
 211                atpx->is_hybrid = true;
 212        }
 213
 214        return 0;
 215}
 216
 217/**
 218 * radeon_atpx_verify_interface - verify ATPX
 219 *
 220 * @atpx: radeon atpx struct
 221 *
 222 * Execute the ATPX_FUNCTION_VERIFY_INTERFACE ATPX function
 223 * to initialize ATPX and determine what features are supported
 224 * (all asics).
 225 * returns 0 on success, error on failure.
 226 */
 227static int radeon_atpx_verify_interface(struct radeon_atpx *atpx)
 228{
 229        union acpi_object *info;
 230        struct atpx_verify_interface output;
 231        size_t size;
 232        int err = 0;
 233
 234        info = radeon_atpx_call(atpx->handle, ATPX_FUNCTION_VERIFY_INTERFACE, NULL);
 235        if (!info)
 236                return -EIO;
 237
 238        memset(&output, 0, sizeof(output));
 239
 240        size = *(u16 *) info->buffer.pointer;
 241        if (size < 8) {
 242                printk("ATPX buffer is too small: %zu\n", size);
 243                err = -EINVAL;
 244                goto out;
 245        }
 246        size = min(sizeof(output), size);
 247
 248        memcpy(&output, info->buffer.pointer, size);
 249
 250        /* TODO: check version? */
 251        printk("ATPX version %u, functions 0x%08x\n",
 252               output.version, output.function_bits);
 253
 254        radeon_atpx_parse_functions(&atpx->functions, output.function_bits);
 255
 256out:
 257        kfree(info);
 258        return err;
 259}
 260
 261/**
 262 * radeon_atpx_set_discrete_state - power up/down discrete GPU
 263 *
 264 * @atpx: atpx info struct
 265 * @state: discrete GPU state (0 = power down, 1 = power up)
 266 *
 267 * Execute the ATPX_FUNCTION_POWER_CONTROL ATPX function to
 268 * power down/up the discrete GPU (all asics).
 269 * Returns 0 on success, error on failure.
 270 */
 271static int radeon_atpx_set_discrete_state(struct radeon_atpx *atpx, u8 state)
 272{
 273        struct acpi_buffer params;
 274        union acpi_object *info;
 275        struct atpx_power_control input;
 276
 277        if (atpx->functions.power_cntl) {
 278                input.size = 3;
 279                input.dgpu_state = state;
 280                params.length = input.size;
 281                params.pointer = &input;
 282                info = radeon_atpx_call(atpx->handle,
 283                                        ATPX_FUNCTION_POWER_CONTROL,
 284                                        &params);
 285                if (!info)
 286                        return -EIO;
 287                kfree(info);
 288
 289                /* 200ms delay is required after off */
 290                if (state == 0)
 291                        msleep(200);
 292        }
 293        return 0;
 294}
 295
 296/**
 297 * radeon_atpx_switch_disp_mux - switch display mux
 298 *
 299 * @atpx: atpx info struct
 300 * @mux_id: mux state (0 = integrated GPU, 1 = discrete GPU)
 301 *
 302 * Execute the ATPX_FUNCTION_DISPLAY_MUX_CONTROL ATPX function to
 303 * switch the display mux between the discrete GPU and integrated GPU
 304 * (all asics).
 305 * Returns 0 on success, error on failure.
 306 */
 307static int radeon_atpx_switch_disp_mux(struct radeon_atpx *atpx, u16 mux_id)
 308{
 309        struct acpi_buffer params;
 310        union acpi_object *info;
 311        struct atpx_mux input;
 312
 313        if (atpx->functions.disp_mux_cntl) {
 314                input.size = 4;
 315                input.mux = mux_id;
 316                params.length = input.size;
 317                params.pointer = &input;
 318                info = radeon_atpx_call(atpx->handle,
 319                                        ATPX_FUNCTION_DISPLAY_MUX_CONTROL,
 320                                        &params);
 321                if (!info)
 322                        return -EIO;
 323                kfree(info);
 324        }
 325        return 0;
 326}
 327
 328/**
 329 * radeon_atpx_switch_i2c_mux - switch i2c/hpd mux
 330 *
 331 * @atpx: atpx info struct
 332 * @mux_id: mux state (0 = integrated GPU, 1 = discrete GPU)
 333 *
 334 * Execute the ATPX_FUNCTION_I2C_MUX_CONTROL ATPX function to
 335 * switch the i2c/hpd mux between the discrete GPU and integrated GPU
 336 * (all asics).
 337 * Returns 0 on success, error on failure.
 338 */
 339static int radeon_atpx_switch_i2c_mux(struct radeon_atpx *atpx, u16 mux_id)
 340{
 341        struct acpi_buffer params;
 342        union acpi_object *info;
 343        struct atpx_mux input;
 344
 345        if (atpx->functions.i2c_mux_cntl) {
 346                input.size = 4;
 347                input.mux = mux_id;
 348                params.length = input.size;
 349                params.pointer = &input;
 350                info = radeon_atpx_call(atpx->handle,
 351                                        ATPX_FUNCTION_I2C_MUX_CONTROL,
 352                                        &params);
 353                if (!info)
 354                        return -EIO;
 355                kfree(info);
 356        }
 357        return 0;
 358}
 359
 360/**
 361 * radeon_atpx_switch_start - notify the sbios of a GPU switch
 362 *
 363 * @atpx: atpx info struct
 364 * @mux_id: mux state (0 = integrated GPU, 1 = discrete GPU)
 365 *
 366 * Execute the ATPX_FUNCTION_GRAPHICS_DEVICE_SWITCH_START_NOTIFICATION ATPX
 367 * function to notify the sbios that a switch between the discrete GPU and
 368 * integrated GPU has begun (all asics).
 369 * Returns 0 on success, error on failure.
 370 */
 371static int radeon_atpx_switch_start(struct radeon_atpx *atpx, u16 mux_id)
 372{
 373        struct acpi_buffer params;
 374        union acpi_object *info;
 375        struct atpx_mux input;
 376
 377        if (atpx->functions.switch_start) {
 378                input.size = 4;
 379                input.mux = mux_id;
 380                params.length = input.size;
 381                params.pointer = &input;
 382                info = radeon_atpx_call(atpx->handle,
 383                                        ATPX_FUNCTION_GRAPHICS_DEVICE_SWITCH_START_NOTIFICATION,
 384                                        &params);
 385                if (!info)
 386                        return -EIO;
 387                kfree(info);
 388        }
 389        return 0;
 390}
 391
 392/**
 393 * radeon_atpx_switch_end - notify the sbios of a GPU switch
 394 *
 395 * @atpx: atpx info struct
 396 * @mux_id: mux state (0 = integrated GPU, 1 = discrete GPU)
 397 *
 398 * Execute the ATPX_FUNCTION_GRAPHICS_DEVICE_SWITCH_END_NOTIFICATION ATPX
 399 * function to notify the sbios that a switch between the discrete GPU and
 400 * integrated GPU has ended (all asics).
 401 * Returns 0 on success, error on failure.
 402 */
 403static int radeon_atpx_switch_end(struct radeon_atpx *atpx, u16 mux_id)
 404{
 405        struct acpi_buffer params;
 406        union acpi_object *info;
 407        struct atpx_mux input;
 408
 409        if (atpx->functions.switch_end) {
 410                input.size = 4;
 411                input.mux = mux_id;
 412                params.length = input.size;
 413                params.pointer = &input;
 414                info = radeon_atpx_call(atpx->handle,
 415                                        ATPX_FUNCTION_GRAPHICS_DEVICE_SWITCH_END_NOTIFICATION,
 416                                        &params);
 417                if (!info)
 418                        return -EIO;
 419                kfree(info);
 420        }
 421        return 0;
 422}
 423
 424/**
 425 * radeon_atpx_switchto - switch to the requested GPU
 426 *
 427 * @id: GPU to switch to
 428 *
 429 * Execute the necessary ATPX functions to switch between the discrete GPU and
 430 * integrated GPU (all asics).
 431 * Returns 0 on success, error on failure.
 432 */
 433static int radeon_atpx_switchto(enum vga_switcheroo_client_id id)
 434{
 435        u16 gpu_id;
 436
 437        if (id == VGA_SWITCHEROO_IGD)
 438                gpu_id = ATPX_INTEGRATED_GPU;
 439        else
 440                gpu_id = ATPX_DISCRETE_GPU;
 441
 442        radeon_atpx_switch_start(&radeon_atpx_priv.atpx, gpu_id);
 443        radeon_atpx_switch_disp_mux(&radeon_atpx_priv.atpx, gpu_id);
 444        radeon_atpx_switch_i2c_mux(&radeon_atpx_priv.atpx, gpu_id);
 445        radeon_atpx_switch_end(&radeon_atpx_priv.atpx, gpu_id);
 446
 447        return 0;
 448}
 449
 450/**
 451 * radeon_atpx_power_state - power down/up the requested GPU
 452 *
 453 * @id: GPU to power down/up
 454 * @state: requested power state (0 = off, 1 = on)
 455 *
 456 * Execute the necessary ATPX function to power down/up the discrete GPU
 457 * (all asics).
 458 * Returns 0 on success, error on failure.
 459 */
 460static int radeon_atpx_power_state(enum vga_switcheroo_client_id id,
 461                                   enum vga_switcheroo_state state)
 462{
 463        /* on w500 ACPI can't change intel gpu state */
 464        if (id == VGA_SWITCHEROO_IGD)
 465                return 0;
 466
 467        radeon_atpx_set_discrete_state(&radeon_atpx_priv.atpx, state);
 468        return 0;
 469}
 470
 471/**
 472 * radeon_atpx_pci_probe_handle - look up the ATPX handle
 473 *
 474 * @pdev: pci device
 475 *
 476 * Look up the ATPX handles (all asics).
 477 * Returns true if the handles are found, false if not.
 478 */
 479static bool radeon_atpx_pci_probe_handle(struct pci_dev *pdev)
 480{
 481        acpi_handle dhandle, atpx_handle;
 482        acpi_status status;
 483
 484        dhandle = ACPI_HANDLE(&pdev->dev);
 485        if (!dhandle)
 486                return false;
 487
 488        status = acpi_get_handle(dhandle, "ATPX", &atpx_handle);
 489        if (ACPI_FAILURE(status))
 490                return false;
 491
 492        radeon_atpx_priv.dhandle = dhandle;
 493        radeon_atpx_priv.atpx.handle = atpx_handle;
 494        return true;
 495}
 496
 497/**
 498 * radeon_atpx_init - verify the ATPX interface
 499 *
 500 * Verify the ATPX interface (all asics).
 501 * Returns 0 on success, error on failure.
 502 */
 503static int radeon_atpx_init(void)
 504{
 505        int r;
 506
 507        /* set up the ATPX handle */
 508        r = radeon_atpx_verify_interface(&radeon_atpx_priv.atpx);
 509        if (r)
 510                return r;
 511
 512        /* validate the atpx setup */
 513        r = radeon_atpx_validate(&radeon_atpx_priv.atpx);
 514        if (r)
 515                return r;
 516
 517        return 0;
 518}
 519
 520/**
 521 * radeon_atpx_get_client_id - get the client id
 522 *
 523 * @pdev: pci device
 524 *
 525 * look up whether we are the integrated or discrete GPU (all asics).
 526 * Returns the client id.
 527 */
 528static enum vga_switcheroo_client_id radeon_atpx_get_client_id(struct pci_dev *pdev)
 529{
 530        if (radeon_atpx_priv.dhandle == ACPI_HANDLE(&pdev->dev))
 531                return VGA_SWITCHEROO_IGD;
 532        else
 533                return VGA_SWITCHEROO_DIS;
 534}
 535
 536static const struct vga_switcheroo_handler radeon_atpx_handler = {
 537        .switchto = radeon_atpx_switchto,
 538        .power_state = radeon_atpx_power_state,
 539        .get_client_id = radeon_atpx_get_client_id,
 540};
 541
 542/**
 543 * radeon_atpx_detect - detect whether we have PX
 544 *
 545 * Check if we have a PX system (all asics).
 546 * Returns true if we have a PX system, false if not.
 547 */
 548static bool radeon_atpx_detect(void)
 549{
 550        char acpi_method_name[255] = { 0 };
 551        struct acpi_buffer buffer = {sizeof(acpi_method_name), acpi_method_name};
 552        struct pci_dev *pdev = NULL;
 553        bool has_atpx = false;
 554        int vga_count = 0;
 555        bool d3_supported = false;
 556        struct pci_dev *parent_pdev;
 557
 558        while ((pdev = pci_get_class(PCI_CLASS_DISPLAY_VGA << 8, pdev)) != NULL) {
 559                vga_count++;
 560
 561                has_atpx |= (radeon_atpx_pci_probe_handle(pdev) == true);
 562
 563                parent_pdev = pci_upstream_bridge(pdev);
 564                d3_supported |= parent_pdev && parent_pdev->bridge_d3;
 565        }
 566
 567        /* some newer PX laptops mark the dGPU as a non-VGA display device */
 568        while ((pdev = pci_get_class(PCI_CLASS_DISPLAY_OTHER << 8, pdev)) != NULL) {
 569                vga_count++;
 570
 571                has_atpx |= (radeon_atpx_pci_probe_handle(pdev) == true);
 572
 573                parent_pdev = pci_upstream_bridge(pdev);
 574                d3_supported |= parent_pdev && parent_pdev->bridge_d3;
 575        }
 576
 577        if (has_atpx && vga_count == 2) {
 578                acpi_get_name(radeon_atpx_priv.atpx.handle, ACPI_FULL_PATHNAME, &buffer);
 579                pr_info("vga_switcheroo: detected switching method %s handle\n",
 580                        acpi_method_name);
 581                radeon_atpx_priv.atpx_detected = true;
 582                radeon_atpx_priv.bridge_pm_usable = d3_supported;
 583                radeon_atpx_init();
 584                return true;
 585        }
 586        return false;
 587}
 588
 589/**
 590 * radeon_register_atpx_handler - register with vga_switcheroo
 591 *
 592 * Register the PX callbacks with vga_switcheroo (all asics).
 593 */
 594void radeon_register_atpx_handler(void)
 595{
 596        bool r;
 597        enum vga_switcheroo_handler_flags_t handler_flags = 0;
 598
 599        /* detect if we have any ATPX + 2 VGA in the system */
 600        r = radeon_atpx_detect();
 601        if (!r)
 602                return;
 603
 604        vga_switcheroo_register_handler(&radeon_atpx_handler, handler_flags);
 605}
 606
 607/**
 608 * radeon_unregister_atpx_handler - unregister with vga_switcheroo
 609 *
 610 * Unregister the PX callbacks with vga_switcheroo (all asics).
 611 */
 612void radeon_unregister_atpx_handler(void)
 613{
 614        vga_switcheroo_unregister_handler();
 615}
 616