intel_opregion.c revision 235783
1235783Skib/* 2235783Skib * Copyright 2008 Intel Corporation <hong.liu@intel.com> 3235783Skib * Copyright 2008 Red Hat <mjg@redhat.com> 4235783Skib * 5235783Skib * Permission is hereby granted, free of charge, to any person obtaining 6235783Skib * a copy of this software and associated documentation files (the 7235783Skib * "Software"), to deal in the Software without restriction, including 8235783Skib * without limitation the rights to use, copy, modify, merge, publish, 9235783Skib * distribute, sub license, and/or sell copies of the Software, and to 10235783Skib * permit persons to whom the Software is furnished to do so, subject to 11235783Skib * the following conditions: 12235783Skib * 13235783Skib * The above copyright notice and this permission notice (including the 14235783Skib * next paragraph) shall be included in all copies or substantial 15235783Skib * portions of the Software. 16235783Skib * 17235783Skib * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 18235783Skib * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 19235783Skib * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 20235783Skib * NON-INFRINGEMENT. IN NO EVENT SHALL INTEL AND/OR ITS SUPPLIERS BE 21235783Skib * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 22235783Skib * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 23235783Skib * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 24235783Skib * SOFTWARE. 25235783Skib * 26235783Skib */ 27235783Skib 28235783Skib#include <sys/cdefs.h> 29235783Skib__FBSDID("$FreeBSD: head/sys/dev/drm2/i915/intel_opregion.c 235783 2012-05-22 11:07:44Z kib $"); 30235783Skib 31235783Skib#include <dev/drm2/drmP.h> 32235783Skib#include <dev/drm2/i915/i915_drm.h> 33235783Skib#include <dev/drm2/i915/i915_drv.h> 34235783Skib#include <dev/drm2/i915/intel_drv.h> 35235783Skib 36235783Skib#define PCI_ASLE 0xe4 37235783Skib#define PCI_ASLS 0xfc 38235783Skib 39235783Skib#define OPREGION_HEADER_OFFSET 0 40235783Skib#define OPREGION_ACPI_OFFSET 0x100 41235783Skib#define ACPI_CLID 0x01ac /* current lid state indicator */ 42235783Skib#define ACPI_CDCK 0x01b0 /* current docking state indicator */ 43235783Skib#define OPREGION_SWSCI_OFFSET 0x200 44235783Skib#define OPREGION_ASLE_OFFSET 0x300 45235783Skib#define OPREGION_VBT_OFFSET 0x400 46235783Skib 47235783Skib#define OPREGION_SIGNATURE "IntelGraphicsMem" 48235783Skib#define MBOX_ACPI (1<<0) 49235783Skib#define MBOX_SWSCI (1<<1) 50235783Skib#define MBOX_ASLE (1<<2) 51235783Skib 52235783Skibstruct opregion_header { 53235783Skib u8 signature[16]; 54235783Skib u32 size; 55235783Skib u32 opregion_ver; 56235783Skib u8 bios_ver[32]; 57235783Skib u8 vbios_ver[16]; 58235783Skib u8 driver_ver[16]; 59235783Skib u32 mboxes; 60235783Skib u8 reserved[164]; 61235783Skib} __attribute__((packed)); 62235783Skib 63235783Skib/* OpRegion mailbox #1: public ACPI methods */ 64235783Skibstruct opregion_acpi { 65235783Skib u32 drdy; /* driver readiness */ 66235783Skib u32 csts; /* notification status */ 67235783Skib u32 cevt; /* current event */ 68235783Skib u8 rsvd1[20]; 69235783Skib u32 didl[8]; /* supported display devices ID list */ 70235783Skib u32 cpdl[8]; /* currently presented display list */ 71235783Skib u32 cadl[8]; /* currently active display list */ 72235783Skib u32 nadl[8]; /* next active devices list */ 73235783Skib u32 aslp; /* ASL sleep time-out */ 74235783Skib u32 tidx; /* toggle table index */ 75235783Skib u32 chpd; /* current hotplug enable indicator */ 76235783Skib u32 clid; /* current lid state*/ 77235783Skib u32 cdck; /* current docking state */ 78235783Skib u32 sxsw; /* Sx state resume */ 79235783Skib u32 evts; /* ASL supported events */ 80235783Skib u32 cnot; /* current OS notification */ 81235783Skib u32 nrdy; /* driver status */ 82235783Skib u8 rsvd2[60]; 83235783Skib} __attribute__((packed)); 84235783Skib 85235783Skib/* OpRegion mailbox #2: SWSCI */ 86235783Skibstruct opregion_swsci { 87235783Skib u32 scic; /* SWSCI command|status|data */ 88235783Skib u32 parm; /* command parameters */ 89235783Skib u32 dslp; /* driver sleep time-out */ 90235783Skib u8 rsvd[244]; 91235783Skib} __attribute__((packed)); 92235783Skib 93235783Skib/* OpRegion mailbox #3: ASLE */ 94235783Skibstruct opregion_asle { 95235783Skib u32 ardy; /* driver readiness */ 96235783Skib u32 aslc; /* ASLE interrupt command */ 97235783Skib u32 tche; /* technology enabled indicator */ 98235783Skib u32 alsi; /* current ALS illuminance reading */ 99235783Skib u32 bclp; /* backlight brightness to set */ 100235783Skib u32 pfit; /* panel fitting state */ 101235783Skib u32 cblv; /* current brightness level */ 102235783Skib u16 bclm[20]; /* backlight level duty cycle mapping table */ 103235783Skib u32 cpfm; /* current panel fitting mode */ 104235783Skib u32 epfm; /* enabled panel fitting modes */ 105235783Skib u8 plut[74]; /* panel LUT and identifier */ 106235783Skib u32 pfmb; /* PWM freq and min brightness */ 107235783Skib u8 rsvd[102]; 108235783Skib} __attribute__((packed)); 109235783Skib 110235783Skib/* ASLE irq request bits */ 111235783Skib#define ASLE_SET_ALS_ILLUM (1 << 0) 112235783Skib#define ASLE_SET_BACKLIGHT (1 << 1) 113235783Skib#define ASLE_SET_PFIT (1 << 2) 114235783Skib#define ASLE_SET_PWM_FREQ (1 << 3) 115235783Skib#define ASLE_REQ_MSK 0xf 116235783Skib 117235783Skib/* response bits of ASLE irq request */ 118235783Skib#define ASLE_ALS_ILLUM_FAILED (1<<10) 119235783Skib#define ASLE_BACKLIGHT_FAILED (1<<12) 120235783Skib#define ASLE_PFIT_FAILED (1<<14) 121235783Skib#define ASLE_PWM_FREQ_FAILED (1<<16) 122235783Skib 123235783Skib/* ASLE backlight brightness to set */ 124235783Skib#define ASLE_BCLP_VALID (1<<31) 125235783Skib#define ASLE_BCLP_MSK (~(1<<31)) 126235783Skib 127235783Skib/* ASLE panel fitting request */ 128235783Skib#define ASLE_PFIT_VALID (1<<31) 129235783Skib#define ASLE_PFIT_CENTER (1<<0) 130235783Skib#define ASLE_PFIT_STRETCH_TEXT (1<<1) 131235783Skib#define ASLE_PFIT_STRETCH_GFX (1<<2) 132235783Skib 133235783Skib/* PWM frequency and minimum brightness */ 134235783Skib#define ASLE_PFMB_BRIGHTNESS_MASK (0xff) 135235783Skib#define ASLE_PFMB_BRIGHTNESS_VALID (1<<8) 136235783Skib#define ASLE_PFMB_PWM_MASK (0x7ffffe00) 137235783Skib#define ASLE_PFMB_PWM_VALID (1<<31) 138235783Skib 139235783Skib#define ASLE_CBLV_VALID (1<<31) 140235783Skib 141235783Skib#define ACPI_OTHER_OUTPUT (0<<8) 142235783Skib#define ACPI_VGA_OUTPUT (1<<8) 143235783Skib#define ACPI_TV_OUTPUT (2<<8) 144235783Skib#define ACPI_DIGITAL_OUTPUT (3<<8) 145235783Skib#define ACPI_LVDS_OUTPUT (4<<8) 146235783Skib 147235783Skib#ifdef CONFIG_ACPI 148235783Skibstatic u32 asle_set_backlight(struct drm_device *dev, u32 bclp) 149235783Skib{ 150235783Skib struct drm_i915_private *dev_priv = dev->dev_private; 151235783Skib struct opregion_asle *asle = dev_priv->opregion.asle; 152235783Skib u32 max; 153235783Skib 154235783Skib if (!(bclp & ASLE_BCLP_VALID)) 155235783Skib return ASLE_BACKLIGHT_FAILED; 156235783Skib 157235783Skib bclp &= ASLE_BCLP_MSK; 158235783Skib if (bclp > 255) 159235783Skib return ASLE_BACKLIGHT_FAILED; 160235783Skib 161235783Skib max = intel_panel_get_max_backlight(dev); 162235783Skib intel_panel_set_backlight(dev, bclp * max / 255); 163235783Skib asle->cblv = (bclp*0x64)/0xff | ASLE_CBLV_VALID; 164235783Skib 165235783Skib return 0; 166235783Skib} 167235783Skib 168235783Skibstatic u32 asle_set_als_illum(struct drm_device *dev, u32 alsi) 169235783Skib{ 170235783Skib /* alsi is the current ALS reading in lux. 0 indicates below sensor 171235783Skib range, 0xffff indicates above sensor range. 1-0xfffe are valid */ 172235783Skib return 0; 173235783Skib} 174235783Skib 175235783Skibstatic u32 asle_set_pwm_freq(struct drm_device *dev, u32 pfmb) 176235783Skib{ 177235783Skib struct drm_i915_private *dev_priv = dev->dev_private; 178235783Skib if (pfmb & ASLE_PFMB_PWM_VALID) { 179235783Skib u32 blc_pwm_ctl = I915_READ(BLC_PWM_CTL); 180235783Skib u32 pwm = pfmb & ASLE_PFMB_PWM_MASK; 181235783Skib blc_pwm_ctl &= BACKLIGHT_DUTY_CYCLE_MASK; 182235783Skib pwm = pwm >> 9; 183235783Skib /* FIXME - what do we do with the PWM? */ 184235783Skib } 185235783Skib return 0; 186235783Skib} 187235783Skib 188235783Skibstatic u32 asle_set_pfit(struct drm_device *dev, u32 pfit) 189235783Skib{ 190235783Skib /* Panel fitting is currently controlled by the X code, so this is a 191235783Skib noop until modesetting support works fully */ 192235783Skib if (!(pfit & ASLE_PFIT_VALID)) 193235783Skib return ASLE_PFIT_FAILED; 194235783Skib return 0; 195235783Skib} 196235783Skib 197235783Skibvoid intel_opregion_asle_intr(struct drm_device *dev) 198235783Skib{ 199235783Skib struct drm_i915_private *dev_priv = dev->dev_private; 200235783Skib struct opregion_asle *asle = dev_priv->opregion.asle; 201235783Skib u32 asle_stat = 0; 202235783Skib u32 asle_req; 203235783Skib 204235783Skib if (!asle) 205235783Skib return; 206235783Skib 207235783Skib asle_req = asle->aslc & ASLE_REQ_MSK; 208235783Skib 209235783Skib if (!asle_req) { 210235783Skib DRM_DEBUG("non asle set request??\n"); 211235783Skib return; 212235783Skib } 213235783Skib 214235783Skib if (asle_req & ASLE_SET_ALS_ILLUM) 215235783Skib asle_stat |= asle_set_als_illum(dev, asle->alsi); 216235783Skib 217235783Skib if (asle_req & ASLE_SET_BACKLIGHT) 218235783Skib asle_stat |= asle_set_backlight(dev, asle->bclp); 219235783Skib 220235783Skib if (asle_req & ASLE_SET_PFIT) 221235783Skib asle_stat |= asle_set_pfit(dev, asle->pfit); 222235783Skib 223235783Skib if (asle_req & ASLE_SET_PWM_FREQ) 224235783Skib asle_stat |= asle_set_pwm_freq(dev, asle->pfmb); 225235783Skib 226235783Skib asle->aslc = asle_stat; 227235783Skib} 228235783Skib 229235783Skibvoid intel_opregion_gse_intr(struct drm_device *dev) 230235783Skib{ 231235783Skib struct drm_i915_private *dev_priv = dev->dev_private; 232235783Skib struct opregion_asle *asle = dev_priv->opregion.asle; 233235783Skib u32 asle_stat = 0; 234235783Skib u32 asle_req; 235235783Skib 236235783Skib if (!asle) 237235783Skib return; 238235783Skib 239235783Skib asle_req = asle->aslc & ASLE_REQ_MSK; 240235783Skib 241235783Skib if (!asle_req) { 242235783Skib DRM_DEBUG("non asle set request??\n"); 243235783Skib return; 244235783Skib } 245235783Skib 246235783Skib if (asle_req & ASLE_SET_ALS_ILLUM) { 247235783Skib DRM_DEBUG("Illum is not supported\n"); 248235783Skib asle_stat |= ASLE_ALS_ILLUM_FAILED; 249235783Skib } 250235783Skib 251235783Skib if (asle_req & ASLE_SET_BACKLIGHT) 252235783Skib asle_stat |= asle_set_backlight(dev, asle->bclp); 253235783Skib 254235783Skib if (asle_req & ASLE_SET_PFIT) { 255235783Skib DRM_DEBUG("Pfit is not supported\n"); 256235783Skib asle_stat |= ASLE_PFIT_FAILED; 257235783Skib } 258235783Skib 259235783Skib if (asle_req & ASLE_SET_PWM_FREQ) { 260235783Skib DRM_DEBUG("PWM freq is not supported\n"); 261235783Skib asle_stat |= ASLE_PWM_FREQ_FAILED; 262235783Skib } 263235783Skib 264235783Skib asle->aslc = asle_stat; 265235783Skib} 266235783Skib#define ASLE_ALS_EN (1<<0) 267235783Skib#define ASLE_BLC_EN (1<<1) 268235783Skib#define ASLE_PFIT_EN (1<<2) 269235783Skib#define ASLE_PFMB_EN (1<<3) 270235783Skib 271235783Skibvoid intel_opregion_enable_asle(struct drm_device *dev) 272235783Skib{ 273235783Skib struct drm_i915_private *dev_priv = dev->dev_private; 274235783Skib struct opregion_asle *asle = dev_priv->opregion.asle; 275235783Skib 276235783Skib if (asle) { 277235783Skib if (IS_MOBILE(dev)) 278235783Skib intel_enable_asle(dev); 279235783Skib 280235783Skib asle->tche = ASLE_ALS_EN | ASLE_BLC_EN | ASLE_PFIT_EN | 281235783Skib ASLE_PFMB_EN; 282235783Skib asle->ardy = 1; 283235783Skib } 284235783Skib} 285235783Skib 286235783Skib#define ACPI_EV_DISPLAY_SWITCH (1<<0) 287235783Skib#define ACPI_EV_LID (1<<1) 288235783Skib#define ACPI_EV_DOCK (1<<2) 289235783Skib 290235783Skibstatic struct intel_opregion *system_opregion; 291235783Skib 292235783Skibstatic int intel_opregion_video_event(struct notifier_block *nb, 293235783Skib unsigned long val, void *data) 294235783Skib{ 295235783Skib /* The only video events relevant to opregion are 0x80. These indicate 296235783Skib either a docking event, lid switch or display switch request. In 297235783Skib Linux, these are handled by the dock, button and video drivers. 298235783Skib */ 299235783Skib struct opregion_acpi *acpi; 300235783Skib struct acpi_bus_event *event = data; 301235783Skib int ret = NOTIFY_OK; 302235783Skib 303235783Skib if (strcmp(event->device_class, ACPI_VIDEO_CLASS) != 0) 304235783Skib return NOTIFY_DONE; 305235783Skib 306235783Skib if (!system_opregion) 307235783Skib return NOTIFY_DONE; 308235783Skib 309235783Skib acpi = system_opregion->acpi; 310235783Skib 311235783Skib if (event->type == 0x80 && !(acpi->cevt & 0x1)) 312235783Skib ret = NOTIFY_BAD; 313235783Skib 314235783Skib acpi->csts = 0; 315235783Skib 316235783Skib return ret; 317235783Skib} 318235783Skib 319235783Skibstatic struct notifier_block intel_opregion_notifier = { 320235783Skib .notifier_call = intel_opregion_video_event, 321235783Skib}; 322235783Skib 323235783Skib/* 324235783Skib * Initialise the DIDL field in opregion. This passes a list of devices to 325235783Skib * the firmware. Values are defined by section B.4.2 of the ACPI specification 326235783Skib * (version 3) 327235783Skib */ 328235783Skib 329235783Skibstatic void intel_didl_outputs(struct drm_device *dev) 330235783Skib{ 331235783Skib struct drm_i915_private *dev_priv = dev->dev_private; 332235783Skib struct intel_opregion *opregion = &dev_priv->opregion; 333235783Skib struct drm_connector *connector; 334235783Skib acpi_handle handle; 335235783Skib struct acpi_device *acpi_dev, *acpi_cdev, *acpi_video_bus = NULL; 336235783Skib unsigned long long device_id; 337235783Skib acpi_status status; 338235783Skib int i = 0; 339235783Skib 340235783Skib handle = DEVICE_ACPI_HANDLE(&dev->pdev->dev); 341235783Skib if (!handle || ACPI_FAILURE(acpi_bus_get_device(handle, &acpi_dev))) 342235783Skib return; 343235783Skib 344235783Skib if (acpi_is_video_device(acpi_dev)) 345235783Skib acpi_video_bus = acpi_dev; 346235783Skib else { 347235783Skib list_for_each_entry(acpi_cdev, &acpi_dev->children, node) { 348235783Skib if (acpi_is_video_device(acpi_cdev)) { 349235783Skib acpi_video_bus = acpi_cdev; 350235783Skib break; 351235783Skib } 352235783Skib } 353235783Skib } 354235783Skib 355235783Skib if (!acpi_video_bus) { 356235783Skib printk(KERN_WARNING "No ACPI video bus found\n"); 357235783Skib return; 358235783Skib } 359235783Skib 360235783Skib list_for_each_entry(acpi_cdev, &acpi_video_bus->children, node) { 361235783Skib if (i >= 8) { 362235783Skib dev_printk(KERN_ERR, &dev->pdev->dev, 363235783Skib "More than 8 outputs detected\n"); 364235783Skib return; 365235783Skib } 366235783Skib status = 367235783Skib acpi_evaluate_integer(acpi_cdev->handle, "_ADR", 368235783Skib NULL, &device_id); 369235783Skib if (ACPI_SUCCESS(status)) { 370235783Skib if (!device_id) 371235783Skib goto blind_set; 372235783Skib opregion->acpi->didl[i] = (u32)(device_id & 0x0f0f); 373235783Skib i++; 374235783Skib } 375235783Skib } 376235783Skib 377235783Skibend: 378235783Skib /* If fewer than 8 outputs, the list must be null terminated */ 379235783Skib if (i < 8) 380235783Skib opregion->acpi->didl[i] = 0; 381235783Skib return; 382235783Skib 383235783Skibblind_set: 384235783Skib i = 0; 385235783Skib list_for_each_entry(connector, &dev->mode_config.connector_list, head) { 386235783Skib int output_type = ACPI_OTHER_OUTPUT; 387235783Skib if (i >= 8) { 388235783Skib device_printf(dev->device, 389235783Skib "More than 8 outputs detected\n"); 390235783Skib return; 391235783Skib } 392235783Skib switch (connector->connector_type) { 393235783Skib case DRM_MODE_CONNECTOR_VGA: 394235783Skib case DRM_MODE_CONNECTOR_DVIA: 395235783Skib output_type = ACPI_VGA_OUTPUT; 396235783Skib break; 397235783Skib case DRM_MODE_CONNECTOR_Composite: 398235783Skib case DRM_MODE_CONNECTOR_SVIDEO: 399235783Skib case DRM_MODE_CONNECTOR_Component: 400235783Skib case DRM_MODE_CONNECTOR_9PinDIN: 401235783Skib output_type = ACPI_TV_OUTPUT; 402235783Skib break; 403235783Skib case DRM_MODE_CONNECTOR_DVII: 404235783Skib case DRM_MODE_CONNECTOR_DVID: 405235783Skib case DRM_MODE_CONNECTOR_DisplayPort: 406235783Skib case DRM_MODE_CONNECTOR_HDMIA: 407235783Skib case DRM_MODE_CONNECTOR_HDMIB: 408235783Skib output_type = ACPI_DIGITAL_OUTPUT; 409235783Skib break; 410235783Skib case DRM_MODE_CONNECTOR_LVDS: 411235783Skib output_type = ACPI_LVDS_OUTPUT; 412235783Skib break; 413235783Skib } 414235783Skib opregion->acpi->didl[i] |= (1<<31) | output_type | i; 415235783Skib i++; 416235783Skib } 417235783Skib goto end; 418235783Skib} 419235783Skib 420235783Skibvoid intel_opregion_init(struct drm_device *dev) 421235783Skib{ 422235783Skib struct drm_i915_private *dev_priv = dev->dev_private; 423235783Skib struct intel_opregion *opregion = &dev_priv->opregion; 424235783Skib 425235783Skib if (!opregion->header) 426235783Skib return; 427235783Skib 428235783Skib if (opregion->acpi) { 429235783Skib if (drm_core_check_feature(dev, DRIVER_MODESET)) 430235783Skib intel_didl_outputs(dev); 431235783Skib 432235783Skib /* Notify BIOS we are ready to handle ACPI video ext notifs. 433235783Skib * Right now, all the events are handled by the ACPI video module. 434235783Skib * We don't actually need to do anything with them. */ 435235783Skib opregion->acpi->csts = 0; 436235783Skib opregion->acpi->drdy = 1; 437235783Skib 438235783Skib system_opregion = opregion; 439235783Skib register_acpi_notifier(&intel_opregion_notifier); 440235783Skib } 441235783Skib 442235783Skib if (opregion->asle) 443235783Skib intel_opregion_enable_asle(dev); 444235783Skib} 445235783Skib 446235783Skibvoid intel_opregion_fini(struct drm_device *dev) 447235783Skib{ 448235783Skib struct drm_i915_private *dev_priv = dev->dev_private; 449235783Skib struct intel_opregion *opregion = &dev_priv->opregion; 450235783Skib 451235783Skib if (!opregion->header) 452235783Skib return; 453235783Skib 454235783Skib if (opregion->acpi) { 455235783Skib opregion->acpi->drdy = 0; 456235783Skib 457235783Skib system_opregion = NULL; 458235783Skib unregister_acpi_notifier(&intel_opregion_notifier); 459235783Skib } 460235783Skib 461235783Skib /* just clear all opregion memory pointers now */ 462235783Skib iounmap(opregion->header); 463235783Skib opregion->header = NULL; 464235783Skib opregion->acpi = NULL; 465235783Skib opregion->swsci = NULL; 466235783Skib opregion->asle = NULL; 467235783Skib opregion->vbt = NULL; 468235783Skib} 469235783Skib#else 470235783Skibint 471235783Skibintel_opregion_init(struct drm_device *dev) 472235783Skib{ 473235783Skib 474235783Skib return (0); 475235783Skib} 476235783Skib 477235783Skibvoid 478235783Skibintel_opregion_fini(struct drm_device *dev) 479235783Skib{ 480235783Skib struct drm_i915_private *dev_priv; 481235783Skib struct intel_opregion *opregion; 482235783Skib 483235783Skib dev_priv = dev->dev_private; 484235783Skib opregion = &dev_priv->opregion; 485235783Skib 486235783Skib if (opregion->header == NULL) 487235783Skib return; 488235783Skib 489235783Skib pmap_unmapdev((vm_offset_t)opregion->header, OPREGION_SIZE); 490235783Skib opregion->header = NULL; 491235783Skib opregion->acpi = NULL; 492235783Skib opregion->swsci = NULL; 493235783Skib opregion->asle = NULL; 494235783Skib opregion->vbt = NULL; 495235783Skib} 496235783Skib#endif 497235783Skib 498235783Skibint intel_opregion_setup(struct drm_device *dev) 499235783Skib{ 500235783Skib struct drm_i915_private *dev_priv = dev->dev_private; 501235783Skib struct intel_opregion *opregion = &dev_priv->opregion; 502235783Skib char *base; 503235783Skib u32 asls, mboxes; 504235783Skib int err = 0; 505235783Skib 506235783Skib asls = pci_read_config(dev->device, PCI_ASLS, 4); 507235783Skib DRM_DEBUG("graphic opregion physical addr: 0x%x\n", asls); 508235783Skib if (asls == 0) { 509235783Skib DRM_DEBUG("ACPI OpRegion not supported!\n"); 510235783Skib return -ENOTSUP; 511235783Skib } 512235783Skib 513235783Skib base = (void *)pmap_mapbios(asls, OPREGION_SIZE); 514235783Skib if (!base) 515235783Skib return -ENOMEM; 516235783Skib 517235783Skib if (memcmp(base, OPREGION_SIGNATURE, 16)) { 518235783Skib DRM_DEBUG("opregion signature mismatch\n"); 519235783Skib err = -EINVAL; 520235783Skib goto err_out; 521235783Skib } 522235783Skib opregion->header = (struct opregion_header *)base; 523235783Skib opregion->vbt = base + OPREGION_VBT_OFFSET; 524235783Skib 525235783Skib opregion->lid_state = (u32 *)(base + ACPI_CLID); 526235783Skib 527235783Skib mboxes = opregion->header->mboxes; 528235783Skib if (mboxes & MBOX_ACPI) { 529235783Skib DRM_DEBUG("Public ACPI methods supported\n"); 530235783Skib opregion->acpi = (struct opregion_acpi *)(base + 531235783Skib OPREGION_ACPI_OFFSET); 532235783Skib } 533235783Skib 534235783Skib if (mboxes & MBOX_SWSCI) { 535235783Skib DRM_DEBUG("SWSCI supported\n"); 536235783Skib opregion->swsci = (struct opregion_swsci *)(base + 537235783Skib OPREGION_SWSCI_OFFSET); 538235783Skib } 539235783Skib if (mboxes & MBOX_ASLE) { 540235783Skib DRM_DEBUG("ASLE supported\n"); 541235783Skib opregion->asle = (struct opregion_asle *)(base + 542235783Skib OPREGION_ASLE_OFFSET); 543235783Skib } 544235783Skib 545235783Skib return 0; 546235783Skib 547235783Skiberr_out: 548235783Skib pmap_unmapdev((vm_offset_t)base, OPREGION_SIZE); 549235783Skib return err; 550235783Skib} 551