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$"); 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> 35279961Sjhb#include <contrib/dev/acpica/include/acpi.h> 36279961Sjhb#include <contrib/dev/acpica/include/accommon.h> 37279961Sjhb#include <dev/acpica/acpivar.h> 38235783Skib 39235783Skib#define PCI_ASLE 0xe4 40235783Skib#define PCI_ASLS 0xfc 41235783Skib 42235783Skib#define OPREGION_HEADER_OFFSET 0 43235783Skib#define OPREGION_ACPI_OFFSET 0x100 44235783Skib#define ACPI_CLID 0x01ac /* current lid state indicator */ 45235783Skib#define ACPI_CDCK 0x01b0 /* current docking state indicator */ 46235783Skib#define OPREGION_SWSCI_OFFSET 0x200 47235783Skib#define OPREGION_ASLE_OFFSET 0x300 48235783Skib#define OPREGION_VBT_OFFSET 0x400 49235783Skib 50235783Skib#define OPREGION_SIGNATURE "IntelGraphicsMem" 51235783Skib#define MBOX_ACPI (1<<0) 52235783Skib#define MBOX_SWSCI (1<<1) 53235783Skib#define MBOX_ASLE (1<<2) 54235783Skib 55235783Skibstruct opregion_header { 56235783Skib u8 signature[16]; 57235783Skib u32 size; 58235783Skib u32 opregion_ver; 59235783Skib u8 bios_ver[32]; 60235783Skib u8 vbios_ver[16]; 61235783Skib u8 driver_ver[16]; 62235783Skib u32 mboxes; 63235783Skib u8 reserved[164]; 64235783Skib} __attribute__((packed)); 65235783Skib 66235783Skib/* OpRegion mailbox #1: public ACPI methods */ 67235783Skibstruct opregion_acpi { 68235783Skib u32 drdy; /* driver readiness */ 69235783Skib u32 csts; /* notification status */ 70235783Skib u32 cevt; /* current event */ 71235783Skib u8 rsvd1[20]; 72235783Skib u32 didl[8]; /* supported display devices ID list */ 73235783Skib u32 cpdl[8]; /* currently presented display list */ 74235783Skib u32 cadl[8]; /* currently active display list */ 75235783Skib u32 nadl[8]; /* next active devices list */ 76235783Skib u32 aslp; /* ASL sleep time-out */ 77235783Skib u32 tidx; /* toggle table index */ 78235783Skib u32 chpd; /* current hotplug enable indicator */ 79235783Skib u32 clid; /* current lid state*/ 80235783Skib u32 cdck; /* current docking state */ 81235783Skib u32 sxsw; /* Sx state resume */ 82235783Skib u32 evts; /* ASL supported events */ 83235783Skib u32 cnot; /* current OS notification */ 84235783Skib u32 nrdy; /* driver status */ 85235783Skib u8 rsvd2[60]; 86235783Skib} __attribute__((packed)); 87235783Skib 88235783Skib/* OpRegion mailbox #2: SWSCI */ 89235783Skibstruct opregion_swsci { 90235783Skib u32 scic; /* SWSCI command|status|data */ 91235783Skib u32 parm; /* command parameters */ 92235783Skib u32 dslp; /* driver sleep time-out */ 93235783Skib u8 rsvd[244]; 94235783Skib} __attribute__((packed)); 95235783Skib 96235783Skib/* OpRegion mailbox #3: ASLE */ 97235783Skibstruct opregion_asle { 98235783Skib u32 ardy; /* driver readiness */ 99235783Skib u32 aslc; /* ASLE interrupt command */ 100235783Skib u32 tche; /* technology enabled indicator */ 101235783Skib u32 alsi; /* current ALS illuminance reading */ 102235783Skib u32 bclp; /* backlight brightness to set */ 103235783Skib u32 pfit; /* panel fitting state */ 104235783Skib u32 cblv; /* current brightness level */ 105235783Skib u16 bclm[20]; /* backlight level duty cycle mapping table */ 106235783Skib u32 cpfm; /* current panel fitting mode */ 107235783Skib u32 epfm; /* enabled panel fitting modes */ 108235783Skib u8 plut[74]; /* panel LUT and identifier */ 109235783Skib u32 pfmb; /* PWM freq and min brightness */ 110235783Skib u8 rsvd[102]; 111235783Skib} __attribute__((packed)); 112235783Skib 113235783Skib/* ASLE irq request bits */ 114235783Skib#define ASLE_SET_ALS_ILLUM (1 << 0) 115235783Skib#define ASLE_SET_BACKLIGHT (1 << 1) 116235783Skib#define ASLE_SET_PFIT (1 << 2) 117235783Skib#define ASLE_SET_PWM_FREQ (1 << 3) 118235783Skib#define ASLE_REQ_MSK 0xf 119235783Skib 120235783Skib/* response bits of ASLE irq request */ 121235783Skib#define ASLE_ALS_ILLUM_FAILED (1<<10) 122235783Skib#define ASLE_BACKLIGHT_FAILED (1<<12) 123235783Skib#define ASLE_PFIT_FAILED (1<<14) 124235783Skib#define ASLE_PWM_FREQ_FAILED (1<<16) 125235783Skib 126235783Skib/* ASLE backlight brightness to set */ 127235783Skib#define ASLE_BCLP_VALID (1<<31) 128235783Skib#define ASLE_BCLP_MSK (~(1<<31)) 129235783Skib 130235783Skib/* ASLE panel fitting request */ 131235783Skib#define ASLE_PFIT_VALID (1<<31) 132235783Skib#define ASLE_PFIT_CENTER (1<<0) 133235783Skib#define ASLE_PFIT_STRETCH_TEXT (1<<1) 134235783Skib#define ASLE_PFIT_STRETCH_GFX (1<<2) 135235783Skib 136235783Skib/* PWM frequency and minimum brightness */ 137235783Skib#define ASLE_PFMB_BRIGHTNESS_MASK (0xff) 138235783Skib#define ASLE_PFMB_BRIGHTNESS_VALID (1<<8) 139235783Skib#define ASLE_PFMB_PWM_MASK (0x7ffffe00) 140235783Skib#define ASLE_PFMB_PWM_VALID (1<<31) 141235783Skib 142235783Skib#define ASLE_CBLV_VALID (1<<31) 143235783Skib 144235783Skib#define ACPI_OTHER_OUTPUT (0<<8) 145235783Skib#define ACPI_VGA_OUTPUT (1<<8) 146235783Skib#define ACPI_TV_OUTPUT (2<<8) 147235783Skib#define ACPI_DIGITAL_OUTPUT (3<<8) 148235783Skib#define ACPI_LVDS_OUTPUT (4<<8) 149235783Skib 150282199Sdumbbell#if defined(CONFIG_ACPI) 151235783Skibstatic u32 asle_set_backlight(struct drm_device *dev, u32 bclp) 152235783Skib{ 153235783Skib struct drm_i915_private *dev_priv = dev->dev_private; 154235783Skib struct opregion_asle *asle = dev_priv->opregion.asle; 155235783Skib u32 max; 156235783Skib 157235783Skib if (!(bclp & ASLE_BCLP_VALID)) 158235783Skib return ASLE_BACKLIGHT_FAILED; 159235783Skib 160235783Skib bclp &= ASLE_BCLP_MSK; 161235783Skib if (bclp > 255) 162235783Skib return ASLE_BACKLIGHT_FAILED; 163235783Skib 164235783Skib max = intel_panel_get_max_backlight(dev); 165235783Skib intel_panel_set_backlight(dev, bclp * max / 255); 166235783Skib asle->cblv = (bclp*0x64)/0xff | ASLE_CBLV_VALID; 167235783Skib 168235783Skib return 0; 169235783Skib} 170235783Skib 171235783Skibstatic u32 asle_set_als_illum(struct drm_device *dev, u32 alsi) 172235783Skib{ 173235783Skib /* alsi is the current ALS reading in lux. 0 indicates below sensor 174235783Skib range, 0xffff indicates above sensor range. 1-0xfffe are valid */ 175235783Skib return 0; 176235783Skib} 177235783Skib 178235783Skibstatic u32 asle_set_pwm_freq(struct drm_device *dev, u32 pfmb) 179235783Skib{ 180235783Skib struct drm_i915_private *dev_priv = dev->dev_private; 181235783Skib if (pfmb & ASLE_PFMB_PWM_VALID) { 182235783Skib u32 blc_pwm_ctl = I915_READ(BLC_PWM_CTL); 183235783Skib u32 pwm = pfmb & ASLE_PFMB_PWM_MASK; 184235783Skib blc_pwm_ctl &= BACKLIGHT_DUTY_CYCLE_MASK; 185235783Skib pwm = pwm >> 9; 186235783Skib /* FIXME - what do we do with the PWM? */ 187235783Skib } 188235783Skib return 0; 189235783Skib} 190235783Skib 191235783Skibstatic u32 asle_set_pfit(struct drm_device *dev, u32 pfit) 192235783Skib{ 193235783Skib /* Panel fitting is currently controlled by the X code, so this is a 194235783Skib noop until modesetting support works fully */ 195235783Skib if (!(pfit & ASLE_PFIT_VALID)) 196235783Skib return ASLE_PFIT_FAILED; 197235783Skib return 0; 198235783Skib} 199235783Skib 200235783Skibvoid intel_opregion_asle_intr(struct drm_device *dev) 201235783Skib{ 202235783Skib struct drm_i915_private *dev_priv = dev->dev_private; 203235783Skib struct opregion_asle *asle = dev_priv->opregion.asle; 204235783Skib u32 asle_stat = 0; 205235783Skib u32 asle_req; 206235783Skib 207235783Skib if (!asle) 208235783Skib return; 209235783Skib 210235783Skib asle_req = asle->aslc & ASLE_REQ_MSK; 211235783Skib 212235783Skib if (!asle_req) { 213235783Skib DRM_DEBUG("non asle set request??\n"); 214235783Skib return; 215235783Skib } 216235783Skib 217235783Skib if (asle_req & ASLE_SET_ALS_ILLUM) 218235783Skib asle_stat |= asle_set_als_illum(dev, asle->alsi); 219235783Skib 220235783Skib if (asle_req & ASLE_SET_BACKLIGHT) 221235783Skib asle_stat |= asle_set_backlight(dev, asle->bclp); 222235783Skib 223235783Skib if (asle_req & ASLE_SET_PFIT) 224235783Skib asle_stat |= asle_set_pfit(dev, asle->pfit); 225235783Skib 226235783Skib if (asle_req & ASLE_SET_PWM_FREQ) 227235783Skib asle_stat |= asle_set_pwm_freq(dev, asle->pfmb); 228235783Skib 229235783Skib asle->aslc = asle_stat; 230235783Skib} 231235783Skib 232235783Skibvoid intel_opregion_gse_intr(struct drm_device *dev) 233235783Skib{ 234235783Skib struct drm_i915_private *dev_priv = dev->dev_private; 235235783Skib struct opregion_asle *asle = dev_priv->opregion.asle; 236235783Skib u32 asle_stat = 0; 237235783Skib u32 asle_req; 238235783Skib 239235783Skib if (!asle) 240235783Skib return; 241235783Skib 242235783Skib asle_req = asle->aslc & ASLE_REQ_MSK; 243235783Skib 244235783Skib if (!asle_req) { 245235783Skib DRM_DEBUG("non asle set request??\n"); 246235783Skib return; 247235783Skib } 248235783Skib 249235783Skib if (asle_req & ASLE_SET_ALS_ILLUM) { 250235783Skib DRM_DEBUG("Illum is not supported\n"); 251235783Skib asle_stat |= ASLE_ALS_ILLUM_FAILED; 252235783Skib } 253235783Skib 254235783Skib if (asle_req & ASLE_SET_BACKLIGHT) 255235783Skib asle_stat |= asle_set_backlight(dev, asle->bclp); 256235783Skib 257235783Skib if (asle_req & ASLE_SET_PFIT) { 258235783Skib DRM_DEBUG("Pfit is not supported\n"); 259235783Skib asle_stat |= ASLE_PFIT_FAILED; 260235783Skib } 261235783Skib 262235783Skib if (asle_req & ASLE_SET_PWM_FREQ) { 263235783Skib DRM_DEBUG("PWM freq is not supported\n"); 264235783Skib asle_stat |= ASLE_PWM_FREQ_FAILED; 265235783Skib } 266235783Skib 267235783Skib asle->aslc = asle_stat; 268235783Skib} 269235783Skib#define ASLE_ALS_EN (1<<0) 270235783Skib#define ASLE_BLC_EN (1<<1) 271235783Skib#define ASLE_PFIT_EN (1<<2) 272235783Skib#define ASLE_PFMB_EN (1<<3) 273235783Skib 274235783Skibvoid intel_opregion_enable_asle(struct drm_device *dev) 275235783Skib{ 276235783Skib struct drm_i915_private *dev_priv = dev->dev_private; 277235783Skib struct opregion_asle *asle = dev_priv->opregion.asle; 278235783Skib 279235783Skib if (asle) { 280235783Skib if (IS_MOBILE(dev)) 281235783Skib intel_enable_asle(dev); 282235783Skib 283235783Skib asle->tche = ASLE_ALS_EN | ASLE_BLC_EN | ASLE_PFIT_EN | 284235783Skib ASLE_PFMB_EN; 285235783Skib asle->ardy = 1; 286235783Skib } 287235783Skib} 288235783Skib 289235783Skib#define ACPI_EV_DISPLAY_SWITCH (1<<0) 290235783Skib#define ACPI_EV_LID (1<<1) 291235783Skib#define ACPI_EV_DOCK (1<<2) 292235783Skib 293235783Skibstatic struct intel_opregion *system_opregion; 294235783Skib 295279961Sjhb#if 0 296235783Skibstatic int intel_opregion_video_event(struct notifier_block *nb, 297235783Skib unsigned long val, void *data) 298235783Skib{ 299235783Skib /* The only video events relevant to opregion are 0x80. These indicate 300235783Skib either a docking event, lid switch or display switch request. In 301235783Skib Linux, these are handled by the dock, button and video drivers. 302235783Skib */ 303235783Skib struct opregion_acpi *acpi; 304235783Skib struct acpi_bus_event *event = data; 305235783Skib int ret = NOTIFY_OK; 306235783Skib 307235783Skib if (strcmp(event->device_class, ACPI_VIDEO_CLASS) != 0) 308235783Skib return NOTIFY_DONE; 309235783Skib 310235783Skib if (!system_opregion) 311235783Skib return NOTIFY_DONE; 312235783Skib 313235783Skib acpi = system_opregion->acpi; 314235783Skib 315235783Skib if (event->type == 0x80 && !(acpi->cevt & 0x1)) 316235783Skib ret = NOTIFY_BAD; 317235783Skib 318235783Skib acpi->csts = 0; 319235783Skib 320235783Skib return ret; 321235783Skib} 322235783Skib 323235783Skibstatic struct notifier_block intel_opregion_notifier = { 324235783Skib .notifier_call = intel_opregion_video_event, 325235783Skib}; 326279961Sjhb#endif 327235783Skib 328235783Skib/* 329235783Skib * Initialise the DIDL field in opregion. This passes a list of devices to 330235783Skib * the firmware. Values are defined by section B.4.2 of the ACPI specification 331235783Skib * (version 3) 332235783Skib */ 333235783Skib 334279961Sjhbstatic int acpi_is_video_device(ACPI_HANDLE devh) { 335279961Sjhb ACPI_HANDLE h; 336279961Sjhb if (ACPI_FAILURE(AcpiGetHandle(devh, "_DOD", &h)) || 337279961Sjhb ACPI_FAILURE(AcpiGetHandle(devh, "_DOS", &h))) { 338279961Sjhb return 0; 339279961Sjhb } 340279961Sjhb return 1; 341279961Sjhb} 342279961Sjhb 343235783Skibstatic void intel_didl_outputs(struct drm_device *dev) 344235783Skib{ 345235783Skib struct drm_i915_private *dev_priv = dev->dev_private; 346235783Skib struct intel_opregion *opregion = &dev_priv->opregion; 347235783Skib struct drm_connector *connector; 348279961Sjhb u32 device_id; 349279961Sjhb ACPI_HANDLE handle, acpi_video_bus, acpi_cdev; 350279961Sjhb ACPI_STATUS status; 351235783Skib int i = 0; 352235783Skib 353282199Sdumbbell handle = acpi_get_handle(dev->dev); 354279961Sjhb if (!handle) 355235783Skib return; 356235783Skib 357279961Sjhb if (acpi_is_video_device(handle)) 358279961Sjhb acpi_video_bus = handle; 359235783Skib else { 360279961Sjhb acpi_cdev = NULL; 361279961Sjhb acpi_video_bus = NULL; 362279961Sjhb while (AcpiGetNextObject(ACPI_TYPE_DEVICE, handle, acpi_cdev, 363279961Sjhb &acpi_cdev) != AE_NOT_FOUND) { 364279961Sjhb if (acpi_is_video_device(acpi_cdev)) { 365279961Sjhb acpi_video_bus = acpi_cdev; 366279961Sjhb break; 367279961Sjhb } 368279961Sjhb } 369279961Sjhb#if 0 370235783Skib list_for_each_entry(acpi_cdev, &acpi_dev->children, node) { 371235783Skib if (acpi_is_video_device(acpi_cdev)) { 372235783Skib acpi_video_bus = acpi_cdev; 373235783Skib break; 374235783Skib } 375235783Skib } 376279961Sjhb#endif 377235783Skib } 378235783Skib 379235783Skib if (!acpi_video_bus) { 380282199Sdumbbell device_printf(dev->dev, "No ACPI video bus found\n"); 381235783Skib return; 382235783Skib } 383235783Skib 384279961Sjhb acpi_cdev = NULL; 385279961Sjhb while (AcpiGetNextObject(ACPI_TYPE_DEVICE, acpi_video_bus, acpi_cdev, 386279961Sjhb &acpi_cdev) != AE_NOT_FOUND) { 387279961Sjhb if (i >= 8) { 388282199Sdumbbell device_printf(dev->dev, "More than 8 outputs detected\n"); 389279961Sjhb return; 390279961Sjhb } 391279961Sjhb status = acpi_GetInteger(acpi_cdev, "_ADR", &device_id); 392279961Sjhb if (ACPI_SUCCESS(status)) { 393279961Sjhb if (!device_id) 394279961Sjhb goto blind_set; 395279961Sjhb opregion->acpi->didl[i] = (u32)(device_id & 0x0f0f); 396279961Sjhb i++; 397279961Sjhb } 398279961Sjhb } 399279961Sjhb#if 0 400235783Skib list_for_each_entry(acpi_cdev, &acpi_video_bus->children, node) { 401235783Skib if (i >= 8) { 402235783Skib dev_printk(KERN_ERR, &dev->pdev->dev, 403235783Skib "More than 8 outputs detected\n"); 404235783Skib return; 405235783Skib } 406235783Skib status = 407235783Skib acpi_evaluate_integer(acpi_cdev->handle, "_ADR", 408235783Skib NULL, &device_id); 409235783Skib if (ACPI_SUCCESS(status)) { 410235783Skib if (!device_id) 411235783Skib goto blind_set; 412235783Skib opregion->acpi->didl[i] = (u32)(device_id & 0x0f0f); 413235783Skib i++; 414235783Skib } 415235783Skib } 416279961Sjhb#endif 417235783Skib 418235783Skibend: 419235783Skib /* If fewer than 8 outputs, the list must be null terminated */ 420235783Skib if (i < 8) 421235783Skib opregion->acpi->didl[i] = 0; 422235783Skib return; 423235783Skib 424235783Skibblind_set: 425235783Skib i = 0; 426235783Skib list_for_each_entry(connector, &dev->mode_config.connector_list, head) { 427235783Skib int output_type = ACPI_OTHER_OUTPUT; 428235783Skib if (i >= 8) { 429282199Sdumbbell device_printf(dev->dev, 430235783Skib "More than 8 outputs detected\n"); 431235783Skib return; 432235783Skib } 433235783Skib switch (connector->connector_type) { 434235783Skib case DRM_MODE_CONNECTOR_VGA: 435235783Skib case DRM_MODE_CONNECTOR_DVIA: 436235783Skib output_type = ACPI_VGA_OUTPUT; 437235783Skib break; 438235783Skib case DRM_MODE_CONNECTOR_Composite: 439235783Skib case DRM_MODE_CONNECTOR_SVIDEO: 440235783Skib case DRM_MODE_CONNECTOR_Component: 441235783Skib case DRM_MODE_CONNECTOR_9PinDIN: 442235783Skib output_type = ACPI_TV_OUTPUT; 443235783Skib break; 444235783Skib case DRM_MODE_CONNECTOR_DVII: 445235783Skib case DRM_MODE_CONNECTOR_DVID: 446235783Skib case DRM_MODE_CONNECTOR_DisplayPort: 447235783Skib case DRM_MODE_CONNECTOR_HDMIA: 448235783Skib case DRM_MODE_CONNECTOR_HDMIB: 449235783Skib output_type = ACPI_DIGITAL_OUTPUT; 450235783Skib break; 451235783Skib case DRM_MODE_CONNECTOR_LVDS: 452235783Skib output_type = ACPI_LVDS_OUTPUT; 453235783Skib break; 454235783Skib } 455235783Skib opregion->acpi->didl[i] |= (1<<31) | output_type | i; 456235783Skib i++; 457235783Skib } 458235783Skib goto end; 459235783Skib} 460235783Skib 461279961Sjhbstatic void intel_setup_cadls(struct drm_device *dev) 462279961Sjhb{ 463279961Sjhb struct drm_i915_private *dev_priv = dev->dev_private; 464279961Sjhb struct intel_opregion *opregion = &dev_priv->opregion; 465279961Sjhb int i = 0; 466279961Sjhb u32 disp_id; 467279961Sjhb 468279961Sjhb /* Initialize the CADL field by duplicating the DIDL values. 469279961Sjhb * Technically, this is not always correct as display outputs may exist, 470279961Sjhb * but not active. This initialization is necessary for some Clevo 471279961Sjhb * laptops that check this field before processing the brightness and 472279961Sjhb * display switching hotkeys. Just like DIDL, CADL is NULL-terminated if 473279961Sjhb * there are less than eight devices. */ 474279961Sjhb do { 475279961Sjhb disp_id = opregion->acpi->didl[i]; 476279961Sjhb opregion->acpi->cadl[i] = disp_id; 477279961Sjhb } while (++i < 8 && disp_id != 0); 478279961Sjhb} 479279961Sjhb 480235783Skibvoid intel_opregion_init(struct drm_device *dev) 481235783Skib{ 482235783Skib struct drm_i915_private *dev_priv = dev->dev_private; 483235783Skib struct intel_opregion *opregion = &dev_priv->opregion; 484235783Skib 485235783Skib if (!opregion->header) 486235783Skib return; 487235783Skib 488235783Skib if (opregion->acpi) { 489279961Sjhb if (drm_core_check_feature(dev, DRIVER_MODESET)) { 490235783Skib intel_didl_outputs(dev); 491279961Sjhb intel_setup_cadls(dev); 492279961Sjhb } 493235783Skib 494235783Skib /* Notify BIOS we are ready to handle ACPI video ext notifs. 495235783Skib * Right now, all the events are handled by the ACPI video module. 496235783Skib * We don't actually need to do anything with them. */ 497235783Skib opregion->acpi->csts = 0; 498235783Skib opregion->acpi->drdy = 1; 499235783Skib 500235783Skib system_opregion = opregion; 501279961Sjhb#if 0 502235783Skib register_acpi_notifier(&intel_opregion_notifier); 503279961Sjhb#endif 504235783Skib } 505235783Skib 506235783Skib if (opregion->asle) 507235783Skib intel_opregion_enable_asle(dev); 508235783Skib} 509235783Skib 510235783Skibvoid intel_opregion_fini(struct drm_device *dev) 511235783Skib{ 512235783Skib struct drm_i915_private *dev_priv = dev->dev_private; 513235783Skib struct intel_opregion *opregion = &dev_priv->opregion; 514235783Skib 515235783Skib if (!opregion->header) 516235783Skib return; 517235783Skib 518235783Skib if (opregion->acpi) { 519235783Skib opregion->acpi->drdy = 0; 520235783Skib 521235783Skib system_opregion = NULL; 522279961Sjhb#if 0 523235783Skib unregister_acpi_notifier(&intel_opregion_notifier); 524279961Sjhb#endif 525235783Skib } 526235783Skib 527235783Skib /* just clear all opregion memory pointers now */ 528279961Sjhb pmap_unmapdev((vm_offset_t)opregion->header, OPREGION_SIZE); 529235783Skib opregion->header = NULL; 530235783Skib opregion->acpi = NULL; 531235783Skib opregion->swsci = NULL; 532235783Skib opregion->asle = NULL; 533235783Skib opregion->vbt = NULL; 534235783Skib} 535235783Skib#else 536295623Sdumbbellvoid 537235783Skibintel_opregion_init(struct drm_device *dev) 538235783Skib{ 539235783Skib} 540235783Skib 541235783Skibvoid 542235783Skibintel_opregion_fini(struct drm_device *dev) 543235783Skib{ 544235783Skib struct drm_i915_private *dev_priv; 545235783Skib struct intel_opregion *opregion; 546235783Skib 547235783Skib dev_priv = dev->dev_private; 548235783Skib opregion = &dev_priv->opregion; 549235783Skib 550235783Skib if (opregion->header == NULL) 551235783Skib return; 552235783Skib 553235783Skib pmap_unmapdev((vm_offset_t)opregion->header, OPREGION_SIZE); 554235783Skib opregion->header = NULL; 555235783Skib opregion->acpi = NULL; 556235783Skib opregion->swsci = NULL; 557235783Skib opregion->asle = NULL; 558235783Skib opregion->vbt = NULL; 559235783Skib} 560235783Skib#endif 561235783Skib 562235783Skibint intel_opregion_setup(struct drm_device *dev) 563235783Skib{ 564235783Skib struct drm_i915_private *dev_priv = dev->dev_private; 565235783Skib struct intel_opregion *opregion = &dev_priv->opregion; 566235783Skib char *base; 567235783Skib u32 asls, mboxes; 568235783Skib int err = 0; 569235783Skib 570282199Sdumbbell asls = pci_read_config(dev->dev, PCI_ASLS, 4); 571235783Skib DRM_DEBUG("graphic opregion physical addr: 0x%x\n", asls); 572235783Skib if (asls == 0) { 573235783Skib DRM_DEBUG("ACPI OpRegion not supported!\n"); 574235783Skib return -ENOTSUP; 575235783Skib } 576235783Skib 577235783Skib base = (void *)pmap_mapbios(asls, OPREGION_SIZE); 578235783Skib if (!base) 579235783Skib return -ENOMEM; 580235783Skib 581235783Skib if (memcmp(base, OPREGION_SIGNATURE, 16)) { 582235783Skib DRM_DEBUG("opregion signature mismatch\n"); 583235783Skib err = -EINVAL; 584235783Skib goto err_out; 585235783Skib } 586235783Skib opregion->header = (struct opregion_header *)base; 587235783Skib opregion->vbt = base + OPREGION_VBT_OFFSET; 588235783Skib 589235783Skib opregion->lid_state = (u32 *)(base + ACPI_CLID); 590235783Skib 591235783Skib mboxes = opregion->header->mboxes; 592235783Skib if (mboxes & MBOX_ACPI) { 593235783Skib DRM_DEBUG("Public ACPI methods supported\n"); 594235783Skib opregion->acpi = (struct opregion_acpi *)(base + 595235783Skib OPREGION_ACPI_OFFSET); 596235783Skib } 597235783Skib 598235783Skib if (mboxes & MBOX_SWSCI) { 599235783Skib DRM_DEBUG("SWSCI supported\n"); 600235783Skib opregion->swsci = (struct opregion_swsci *)(base + 601235783Skib OPREGION_SWSCI_OFFSET); 602235783Skib } 603235783Skib if (mboxes & MBOX_ASLE) { 604235783Skib DRM_DEBUG("ASLE supported\n"); 605235783Skib opregion->asle = (struct opregion_asle *)(base + 606235783Skib OPREGION_ASLE_OFFSET); 607235783Skib } 608235783Skib 609235783Skib return 0; 610235783Skib 611235783Skiberr_out: 612235783Skib pmap_unmapdev((vm_offset_t)base, OPREGION_SIZE); 613235783Skib return err; 614235783Skib} 615