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