2008-08-05 19:37:25 +01:00
/*
* Copyright 2008 Intel Corporation < hong . liu @ intel . com >
* Copyright 2008 Red Hat < mjg @ redhat . com >
*
* Permission is hereby granted , free of charge , to any person obtaining
* a copy of this software and associated documentation files ( the
* " Software " ) , to deal in the Software without restriction , including
* without limitation the rights to use , copy , modify , merge , publish ,
* distribute , sub license , and / or sell copies of the Software , and to
* permit persons to whom the Software is furnished to do so , subject to
* the following conditions :
*
* The above copyright notice and this permission notice ( including the
* next paragraph ) shall be included in all copies or substantial
* portions of the Software .
*
* THE SOFTWARE IS PROVIDED " AS IS " , WITHOUT WARRANTY OF ANY KIND ,
* EXPRESS OR IMPLIED , INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY , FITNESS FOR A PARTICULAR PURPOSE AND
* NON - INFRINGEMENT . IN NO EVENT SHALL INTEL AND / OR ITS SUPPLIERS BE
* LIABLE FOR ANY CLAIM , DAMAGES OR OTHER LIABILITY , WHETHER IN AN
* ACTION OF CONTRACT , TORT OR OTHERWISE , ARISING FROM , OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE .
*
*/
2012-03-18 13:00:11 -07:00
# define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
2008-08-05 19:37:25 +01:00
# include <linux/acpi.h>
2011-01-23 18:17:17 +00:00
# include <linux/acpi_io.h>
2009-03-19 21:35:39 +00:00
# include <acpi/video.h>
2008-08-05 19:37:25 +01:00
2012-10-02 18:01:07 +01:00
# include <drm/drmP.h>
# include <drm/i915_drm.h>
2008-08-05 19:37:25 +01:00
# include "i915_drv.h"
2010-08-22 13:18:16 +01:00
# include "intel_drv.h"
2008-08-05 19:37:25 +01:00
# define PCI_ASLE 0xe4
# define PCI_ASLS 0xfc
# define OPREGION_HEADER_OFFSET 0
# define OPREGION_ACPI_OFFSET 0x100
2011-02-24 18:13:42 +00:00
# define ACPI_CLID 0x01ac /* current lid state indicator */
# define ACPI_CDCK 0x01b0 /* current docking state indicator */
2008-08-05 19:37:25 +01:00
# define OPREGION_SWSCI_OFFSET 0x200
# define OPREGION_ASLE_OFFSET 0x300
2010-08-19 16:09:23 +01:00
# define OPREGION_VBT_OFFSET 0x400
2008-08-05 19:37:25 +01:00
# define OPREGION_SIGNATURE "IntelGraphicsMem"
# define MBOX_ACPI (1<<0)
# define MBOX_SWSCI (1<<1)
# define MBOX_ASLE (1<<2)
struct opregion_header {
2011-08-16 15:34:10 -04:00
u8 signature [ 16 ] ;
u32 size ;
u32 opregion_ver ;
u8 bios_ver [ 32 ] ;
u8 vbios_ver [ 16 ] ;
u8 driver_ver [ 16 ] ;
u32 mboxes ;
u8 reserved [ 164 ] ;
2008-08-05 19:37:25 +01:00
} __attribute__ ( ( packed ) ) ;
/* OpRegion mailbox #1: public ACPI methods */
struct opregion_acpi {
2011-08-16 15:34:10 -04:00
u32 drdy ; /* driver readiness */
u32 csts ; /* notification status */
u32 cevt ; /* current event */
u8 rsvd1 [ 20 ] ;
u32 didl [ 8 ] ; /* supported display devices ID list */
u32 cpdl [ 8 ] ; /* currently presented display list */
u32 cadl [ 8 ] ; /* currently active display list */
u32 nadl [ 8 ] ; /* next active devices list */
u32 aslp ; /* ASL sleep time-out */
u32 tidx ; /* toggle table index */
u32 chpd ; /* current hotplug enable indicator */
u32 clid ; /* current lid state*/
u32 cdck ; /* current docking state */
u32 sxsw ; /* Sx state resume */
u32 evts ; /* ASL supported events */
u32 cnot ; /* current OS notification */
u32 nrdy ; /* driver status */
u8 rsvd2 [ 60 ] ;
2008-08-05 19:37:25 +01:00
} __attribute__ ( ( packed ) ) ;
/* OpRegion mailbox #2: SWSCI */
struct opregion_swsci {
2011-08-16 15:34:10 -04:00
u32 scic ; /* SWSCI command|status|data */
u32 parm ; /* command parameters */
u32 dslp ; /* driver sleep time-out */
u8 rsvd [ 244 ] ;
2008-08-05 19:37:25 +01:00
} __attribute__ ( ( packed ) ) ;
/* OpRegion mailbox #3: ASLE */
struct opregion_asle {
2011-08-16 15:34:10 -04:00
u32 ardy ; /* driver readiness */
u32 aslc ; /* ASLE interrupt command */
u32 tche ; /* technology enabled indicator */
u32 alsi ; /* current ALS illuminance reading */
u32 bclp ; /* backlight brightness to set */
u32 pfit ; /* panel fitting state */
u32 cblv ; /* current brightness level */
u16 bclm [ 20 ] ; /* backlight level duty cycle mapping table */
u32 cpfm ; /* current panel fitting mode */
u32 epfm ; /* enabled panel fitting modes */
u8 plut [ 74 ] ; /* panel LUT and identifier */
u32 pfmb ; /* PWM freq and min brightness */
u8 rsvd [ 102 ] ;
2008-08-05 19:37:25 +01:00
} __attribute__ ( ( packed ) ) ;
/* ASLE irq request bits */
# define ASLE_SET_ALS_ILLUM (1 << 0)
# define ASLE_SET_BACKLIGHT (1 << 1)
# define ASLE_SET_PFIT (1 << 2)
# define ASLE_SET_PWM_FREQ (1 << 3)
# define ASLE_REQ_MSK 0xf
/* response bits of ASLE irq request */
2009-10-28 05:10:00 +00:00
# define ASLE_ALS_ILLUM_FAILED (1<<10)
# define ASLE_BACKLIGHT_FAILED (1<<12)
# define ASLE_PFIT_FAILED (1<<14)
# define ASLE_PWM_FREQ_FAILED (1<<16)
2008-08-05 19:37:25 +01:00
/* ASLE backlight brightness to set */
# define ASLE_BCLP_VALID (1<<31)
# define ASLE_BCLP_MSK (~(1<<31))
/* ASLE panel fitting request */
# define ASLE_PFIT_VALID (1<<31)
# define ASLE_PFIT_CENTER (1<<0)
# define ASLE_PFIT_STRETCH_TEXT (1<<1)
# define ASLE_PFIT_STRETCH_GFX (1<<2)
/* PWM frequency and minimum brightness */
# define ASLE_PFMB_BRIGHTNESS_MASK (0xff)
# define ASLE_PFMB_BRIGHTNESS_VALID (1<<8)
# define ASLE_PFMB_PWM_MASK (0x7ffffe00)
# define ASLE_PFMB_PWM_VALID (1<<31)
# define ASLE_CBLV_VALID (1<<31)
2009-03-19 21:35:39 +00:00
# define ACPI_OTHER_OUTPUT (0<<8)
# define ACPI_VGA_OUTPUT (1<<8)
# define ACPI_TV_OUTPUT (2<<8)
# define ACPI_DIGITAL_OUTPUT (3<<8)
# define ACPI_LVDS_OUTPUT (4<<8)
2010-08-19 16:09:23 +01:00
# ifdef CONFIG_ACPI
2008-08-05 19:37:25 +01:00
static u32 asle_set_backlight ( struct drm_device * dev , u32 bclp )
{
struct drm_i915_private * dev_priv = dev - > dev_private ;
2012-04-16 14:07:42 -07:00
struct opregion_asle __iomem * asle = dev_priv - > opregion . asle ;
2010-08-22 13:18:16 +01:00
u32 max ;
2008-08-05 19:37:25 +01:00
2012-10-01 14:25:30 +03:00
DRM_DEBUG_DRIVER ( " bclp = 0x%08x \n " , bclp ) ;
2008-08-05 19:37:25 +01:00
if ( ! ( bclp & ASLE_BCLP_VALID ) )
2010-08-07 11:01:32 +01:00
return ASLE_BACKLIGHT_FAILED ;
2008-08-05 19:37:25 +01:00
bclp & = ASLE_BCLP_MSK ;
2010-08-22 13:18:16 +01:00
if ( bclp > 255 )
2010-08-07 11:01:32 +01:00
return ASLE_BACKLIGHT_FAILED ;
2008-08-05 19:37:25 +01:00
2010-08-22 13:18:16 +01:00
max = intel_panel_get_max_backlight ( dev ) ;
intel_panel_set_backlight ( dev , bclp * max / 255 ) ;
2012-04-16 14:07:42 -07:00
iowrite32 ( ( bclp * 0x64 ) / 0xff | ASLE_CBLV_VALID , & asle - > cblv ) ;
2008-08-05 19:37:25 +01:00
return 0 ;
}
static u32 asle_set_als_illum ( struct drm_device * dev , u32 alsi )
{
/* alsi is the current ALS reading in lux. 0 indicates below sensor
range , 0xffff indicates above sensor range . 1 - 0xfffe are valid */
return 0 ;
}
static u32 asle_set_pwm_freq ( struct drm_device * dev , u32 pfmb )
{
struct drm_i915_private * dev_priv = dev - > dev_private ;
if ( pfmb & ASLE_PFMB_PWM_VALID ) {
u32 blc_pwm_ctl = I915_READ ( BLC_PWM_CTL ) ;
u32 pwm = pfmb & ASLE_PFMB_PWM_MASK ;
blc_pwm_ctl & = BACKLIGHT_DUTY_CYCLE_MASK ;
pwm = pwm > > 9 ;
/* FIXME - what do we do with the PWM? */
}
return 0 ;
}
static u32 asle_set_pfit ( struct drm_device * dev , u32 pfit )
{
/* Panel fitting is currently controlled by the X code, so this is a
noop until modesetting support works fully */
if ( ! ( pfit & ASLE_PFIT_VALID ) )
2010-08-07 11:01:32 +01:00
return ASLE_PFIT_FAILED ;
2008-08-05 19:37:25 +01:00
return 0 ;
}
2010-08-24 09:02:58 +01:00
void intel_opregion_asle_intr ( struct drm_device * dev )
2008-08-05 19:37:25 +01:00
{
struct drm_i915_private * dev_priv = dev - > dev_private ;
2012-04-16 14:07:42 -07:00
struct opregion_asle __iomem * asle = dev_priv - > opregion . asle ;
2008-08-05 19:37:25 +01:00
u32 asle_stat = 0 ;
u32 asle_req ;
if ( ! asle )
return ;
2012-04-16 14:07:42 -07:00
asle_req = ioread32 ( & asle - > aslc ) & ASLE_REQ_MSK ;
2008-08-05 19:37:25 +01:00
if ( ! asle_req ) {
2009-10-09 11:39:40 +08:00
DRM_DEBUG_DRIVER ( " non asle set request?? \n " ) ;
2008-08-05 19:37:25 +01:00
return ;
}
if ( asle_req & ASLE_SET_ALS_ILLUM )
2012-04-16 14:07:42 -07:00
asle_stat | = asle_set_als_illum ( dev , ioread32 ( & asle - > alsi ) ) ;
2008-08-05 19:37:25 +01:00
if ( asle_req & ASLE_SET_BACKLIGHT )
2012-04-16 14:07:42 -07:00
asle_stat | = asle_set_backlight ( dev , ioread32 ( & asle - > bclp ) ) ;
2008-08-05 19:37:25 +01:00
if ( asle_req & ASLE_SET_PFIT )
2012-04-16 14:07:42 -07:00
asle_stat | = asle_set_pfit ( dev , ioread32 ( & asle - > pfit ) ) ;
2008-08-05 19:37:25 +01:00
if ( asle_req & ASLE_SET_PWM_FREQ )
2012-04-16 14:07:42 -07:00
asle_stat | = asle_set_pwm_freq ( dev , ioread32 ( & asle - > pfmb ) ) ;
2008-08-05 19:37:25 +01:00
2012-04-16 14:07:42 -07:00
iowrite32 ( asle_stat , & asle - > aslc ) ;
2008-08-05 19:37:25 +01:00
}
2010-08-24 09:02:58 +01:00
void intel_opregion_gse_intr ( struct drm_device * dev )
2009-10-28 05:10:00 +00:00
{
struct drm_i915_private * dev_priv = dev - > dev_private ;
2012-04-16 14:07:42 -07:00
struct opregion_asle __iomem * asle = dev_priv - > opregion . asle ;
2009-10-28 05:10:00 +00:00
u32 asle_stat = 0 ;
u32 asle_req ;
if ( ! asle )
return ;
2012-04-16 14:07:42 -07:00
asle_req = ioread32 ( & asle - > aslc ) & ASLE_REQ_MSK ;
2009-10-28 05:10:00 +00:00
if ( ! asle_req ) {
DRM_DEBUG_DRIVER ( " non asle set request?? \n " ) ;
return ;
}
if ( asle_req & ASLE_SET_ALS_ILLUM ) {
DRM_DEBUG_DRIVER ( " Illum is not supported \n " ) ;
asle_stat | = ASLE_ALS_ILLUM_FAILED ;
}
if ( asle_req & ASLE_SET_BACKLIGHT )
2012-04-16 14:07:42 -07:00
asle_stat | = asle_set_backlight ( dev , ioread32 ( & asle - > bclp ) ) ;
2009-10-28 05:10:00 +00:00
if ( asle_req & ASLE_SET_PFIT ) {
DRM_DEBUG_DRIVER ( " Pfit is not supported \n " ) ;
asle_stat | = ASLE_PFIT_FAILED ;
}
if ( asle_req & ASLE_SET_PWM_FREQ ) {
DRM_DEBUG_DRIVER ( " PWM freq is not supported \n " ) ;
asle_stat | = ASLE_PWM_FREQ_FAILED ;
}
2012-04-16 14:07:42 -07:00
iowrite32 ( asle_stat , & asle - > aslc ) ;
2009-10-28 05:10:00 +00:00
}
2008-08-05 19:37:25 +01:00
# define ASLE_ALS_EN (1<<0)
# define ASLE_BLC_EN (1<<1)
# define ASLE_PFIT_EN (1<<2)
# define ASLE_PFMB_EN (1<<3)
2010-08-24 09:02:58 +01:00
void intel_opregion_enable_asle ( struct drm_device * dev )
2008-08-05 19:37:25 +01:00
{
struct drm_i915_private * dev_priv = dev - > dev_private ;
2012-04-16 14:07:42 -07:00
struct opregion_asle __iomem * asle = dev_priv - > opregion . asle ;
2008-08-05 19:37:25 +01:00
if ( asle ) {
2010-12-04 11:30:53 +00:00
if ( IS_MOBILE ( dev ) )
2009-10-28 05:10:00 +00:00
intel_enable_asle ( dev ) ;
2008-08-05 19:37:25 +01:00
2012-04-16 14:07:42 -07:00
iowrite32 ( ASLE_ALS_EN | ASLE_BLC_EN | ASLE_PFIT_EN |
ASLE_PFMB_EN ,
& asle - > tche ) ;
iowrite32 ( 1 , & asle - > ardy ) ;
2008-08-05 19:37:25 +01:00
}
}
# define ACPI_EV_DISPLAY_SWITCH (1<<0)
# define ACPI_EV_LID (1<<1)
# define ACPI_EV_DOCK (1<<2)
static struct intel_opregion * system_opregion ;
2008-12-18 21:18:47 +01:00
static int intel_opregion_video_event ( struct notifier_block * nb ,
unsigned long val , void * data )
2008-08-05 19:37:25 +01:00
{
/* The only video events relevant to opregion are 0x80. These indicate
either a docking event , lid switch or display switch request . In
Linux , these are handled by the dock , button and video drivers .
2011-07-12 18:30:52 -04:00
*/
2008-08-05 19:37:25 +01:00
2012-04-16 14:07:42 -07:00
struct opregion_acpi __iomem * acpi ;
2011-07-12 18:30:52 -04:00
struct acpi_bus_event * event = data ;
int ret = NOTIFY_OK ;
if ( strcmp ( event - > device_class , ACPI_VIDEO_CLASS ) ! = 0 )
return NOTIFY_DONE ;
2008-08-05 19:37:25 +01:00
if ( ! system_opregion )
return NOTIFY_DONE ;
acpi = system_opregion - > acpi ;
2011-07-12 18:30:52 -04:00
2012-04-16 14:07:42 -07:00
if ( event - > type = = 0x80 & &
( ioread32 ( & acpi - > cevt ) & 1 ) = = 0 )
2011-07-12 18:30:52 -04:00
ret = NOTIFY_BAD ;
2012-04-16 14:07:42 -07:00
iowrite32 ( 0 , & acpi - > csts ) ;
2008-08-05 19:37:25 +01:00
2011-07-12 18:30:52 -04:00
return ret ;
2008-08-05 19:37:25 +01:00
}
static struct notifier_block intel_opregion_notifier = {
. notifier_call = intel_opregion_video_event ,
} ;
2009-03-19 21:35:39 +00:00
/*
* Initialise the DIDL field in opregion . This passes a list of devices to
* the firmware . Values are defined by section B .4 .2 of the ACPI specification
* ( version 3 )
*/
static void intel_didl_outputs ( struct drm_device * dev )
{
struct drm_i915_private * dev_priv = dev - > dev_private ;
struct intel_opregion * opregion = & dev_priv - > opregion ;
struct drm_connector * connector ;
2010-03-29 15:12:16 +08:00
acpi_handle handle ;
struct acpi_device * acpi_dev , * acpi_cdev , * acpi_video_bus = NULL ;
unsigned long long device_id ;
acpi_status status ;
2012-04-16 14:07:42 -07:00
u32 temp ;
2009-03-19 21:35:39 +00:00
int i = 0 ;
2010-03-29 15:12:16 +08:00
handle = DEVICE_ACPI_HANDLE ( & dev - > pdev - > dev ) ;
if ( ! handle | | ACPI_FAILURE ( acpi_bus_get_device ( handle , & acpi_dev ) ) )
return ;
if ( acpi_is_video_device ( acpi_dev ) )
acpi_video_bus = acpi_dev ;
else {
list_for_each_entry ( acpi_cdev , & acpi_dev - > children , node ) {
if ( acpi_is_video_device ( acpi_cdev ) ) {
acpi_video_bus = acpi_cdev ;
break ;
}
}
}
if ( ! acpi_video_bus ) {
2012-03-18 13:00:11 -07:00
pr_warn ( " No ACPI video bus found \n " ) ;
2010-03-29 15:12:16 +08:00
return ;
}
list_for_each_entry ( acpi_cdev , & acpi_video_bus - > children , node ) {
if ( i > = 8 ) {
2011-08-16 15:34:10 -04:00
dev_printk ( KERN_ERR , & dev - > pdev - > dev ,
2010-03-29 15:12:16 +08:00
" More than 8 outputs detected \n " ) ;
return ;
}
status =
acpi_evaluate_integer ( acpi_cdev - > handle , " _ADR " ,
NULL , & device_id ) ;
if ( ACPI_SUCCESS ( status ) ) {
if ( ! device_id )
goto blind_set ;
2012-04-16 14:07:42 -07:00
iowrite32 ( ( u32 ) ( device_id & 0x0f0f ) ,
& opregion - > acpi - > didl [ i ] ) ;
2010-03-29 15:12:16 +08:00
i + + ;
}
}
end :
/* If fewer than 8 outputs, the list must be null terminated */
if ( i < 8 )
2012-04-16 14:07:42 -07:00
iowrite32 ( 0 , & opregion - > acpi - > didl [ i ] ) ;
2010-03-29 15:12:16 +08:00
return ;
blind_set :
i = 0 ;
2009-03-19 21:35:39 +00:00
list_for_each_entry ( connector , & dev - > mode_config . connector_list , head ) {
int output_type = ACPI_OTHER_OUTPUT ;
if ( i > = 8 ) {
2011-08-16 15:34:10 -04:00
dev_printk ( KERN_ERR , & dev - > pdev - > dev ,
2009-03-19 21:35:39 +00:00
" More than 8 outputs detected \n " ) ;
return ;
}
switch ( connector - > connector_type ) {
case DRM_MODE_CONNECTOR_VGA :
case DRM_MODE_CONNECTOR_DVIA :
output_type = ACPI_VGA_OUTPUT ;
break ;
case DRM_MODE_CONNECTOR_Composite :
case DRM_MODE_CONNECTOR_SVIDEO :
case DRM_MODE_CONNECTOR_Component :
case DRM_MODE_CONNECTOR_9PinDIN :
output_type = ACPI_TV_OUTPUT ;
break ;
case DRM_MODE_CONNECTOR_DVII :
case DRM_MODE_CONNECTOR_DVID :
case DRM_MODE_CONNECTOR_DisplayPort :
case DRM_MODE_CONNECTOR_HDMIA :
case DRM_MODE_CONNECTOR_HDMIB :
output_type = ACPI_DIGITAL_OUTPUT ;
break ;
case DRM_MODE_CONNECTOR_LVDS :
output_type = ACPI_LVDS_OUTPUT ;
break ;
}
2012-04-16 14:07:42 -07:00
temp = ioread32 ( & opregion - > acpi - > didl [ i ] ) ;
iowrite32 ( temp | ( 1 < < 31 ) | output_type | i ,
& opregion - > acpi - > didl [ i ] ) ;
2009-03-19 21:35:39 +00:00
i + + ;
}
2010-03-29 15:12:16 +08:00
goto end ;
2009-03-19 21:35:39 +00:00
}
2012-06-26 00:36:24 +02:00
static void intel_setup_cadls ( struct drm_device * dev )
{
struct drm_i915_private * dev_priv = dev - > dev_private ;
struct intel_opregion * opregion = & dev_priv - > opregion ;
int i = 0 ;
u32 disp_id ;
/* Initialize the CADL field by duplicating the DIDL values.
* Technically , this is not always correct as display outputs may exist ,
* but not active . This initialization is necessary for some Clevo
* laptops that check this field before processing the brightness and
* display switching hotkeys . Just like DIDL , CADL is NULL - terminated if
* there are less than eight devices . */
do {
disp_id = ioread32 ( & opregion - > acpi - > didl [ i ] ) ;
iowrite32 ( disp_id , & opregion - > acpi - > cadl [ i ] ) ;
} while ( + + i < 8 & & disp_id ! = 0 ) ;
}
2010-08-19 16:09:23 +01:00
void intel_opregion_init ( struct drm_device * dev )
{
struct drm_i915_private * dev_priv = dev - > dev_private ;
struct intel_opregion * opregion = & dev_priv - > opregion ;
if ( ! opregion - > header )
return ;
if ( opregion - > acpi ) {
2012-06-26 00:36:24 +02:00
if ( drm_core_check_feature ( dev , DRIVER_MODESET ) ) {
2010-08-19 16:09:23 +01:00
intel_didl_outputs ( dev ) ;
2012-06-26 00:36:24 +02:00
intel_setup_cadls ( dev ) ;
}
2010-08-19 16:09:23 +01:00
/* Notify BIOS we are ready to handle ACPI video ext notifs.
* Right now , all the events are handled by the ACPI video module .
* We don ' t actually need to do anything with them . */
2012-04-16 14:07:42 -07:00
iowrite32 ( 0 , & opregion - > acpi - > csts ) ;
iowrite32 ( 1 , & opregion - > acpi - > drdy ) ;
2010-08-19 16:09:23 +01:00
system_opregion = opregion ;
register_acpi_notifier ( & intel_opregion_notifier ) ;
}
if ( opregion - > asle )
intel_opregion_enable_asle ( dev ) ;
}
void intel_opregion_fini ( struct drm_device * dev )
{
struct drm_i915_private * dev_priv = dev - > dev_private ;
struct intel_opregion * opregion = & dev_priv - > opregion ;
if ( ! opregion - > header )
return ;
if ( opregion - > acpi ) {
2012-04-16 14:07:42 -07:00
iowrite32 ( 0 , & opregion - > acpi - > drdy ) ;
2010-08-19 16:09:23 +01:00
system_opregion = NULL ;
unregister_acpi_notifier ( & intel_opregion_notifier ) ;
}
/* just clear all opregion memory pointers now */
iounmap ( opregion - > header ) ;
opregion - > header = NULL ;
opregion - > acpi = NULL ;
opregion - > swsci = NULL ;
opregion - > asle = NULL ;
opregion - > vbt = NULL ;
}
# endif
int intel_opregion_setup ( struct drm_device * dev )
2008-08-05 19:37:25 +01:00
{
struct drm_i915_private * dev_priv = dev - > dev_private ;
struct intel_opregion * opregion = & dev_priv - > opregion ;
2012-04-16 14:07:42 -07:00
void __iomem * base ;
2008-08-05 19:37:25 +01:00
u32 asls , mboxes ;
2012-04-16 14:07:42 -07:00
char buf [ sizeof ( OPREGION_SIGNATURE ) ] ;
2008-08-05 19:37:25 +01:00
int err = 0 ;
pci_read_config_dword ( dev - > pdev , PCI_ASLS , & asls ) ;
2009-10-09 11:39:40 +08:00
DRM_DEBUG_DRIVER ( " graphic opregion physical addr: 0x%x \n " , asls ) ;
2008-08-05 19:37:25 +01:00
if ( asls = = 0 ) {
2009-10-09 11:39:40 +08:00
DRM_DEBUG_DRIVER ( " ACPI OpRegion not supported! \n " ) ;
2008-08-05 19:37:25 +01:00
return - ENOTSUPP ;
}
2011-01-23 18:17:17 +00:00
base = acpi_os_ioremap ( asls , OPREGION_SIZE ) ;
2008-08-05 19:37:25 +01:00
if ( ! base )
return - ENOMEM ;
2012-04-16 14:07:42 -07:00
memcpy_fromio ( buf , base , sizeof ( buf ) ) ;
if ( memcmp ( buf , OPREGION_SIGNATURE , 16 ) ) {
2009-10-09 11:39:40 +08:00
DRM_DEBUG_DRIVER ( " opregion signature mismatch \n " ) ;
2008-08-05 19:37:25 +01:00
err = - EINVAL ;
goto err_out ;
}
2010-08-19 16:09:23 +01:00
opregion - > header = base ;
opregion - > vbt = base + OPREGION_VBT_OFFSET ;
2008-08-05 19:37:25 +01:00
2011-02-24 18:13:42 +00:00
opregion - > lid_state = base + ACPI_CLID ;
2011-01-16 19:37:30 +00:00
2012-04-16 14:07:42 -07:00
mboxes = ioread32 ( & opregion - > header - > mboxes ) ;
2008-08-05 19:37:25 +01:00
if ( mboxes & MBOX_ACPI ) {
2009-10-09 11:39:40 +08:00
DRM_DEBUG_DRIVER ( " Public ACPI methods supported \n " ) ;
2008-08-05 19:37:25 +01:00
opregion - > acpi = base + OPREGION_ACPI_OFFSET ;
}
if ( mboxes & MBOX_SWSCI ) {
2009-10-09 11:39:40 +08:00
DRM_DEBUG_DRIVER ( " SWSCI supported \n " ) ;
2008-08-05 19:37:25 +01:00
opregion - > swsci = base + OPREGION_SWSCI_OFFSET ;
}
if ( mboxes & MBOX_ASLE ) {
2009-10-09 11:39:40 +08:00
DRM_DEBUG_DRIVER ( " ASLE supported \n " ) ;
2008-08-05 19:37:25 +01:00
opregion - > asle = base + OPREGION_ASLE_OFFSET ;
}
return 0 ;
err_out :
2010-11-01 11:32:22 +01:00
iounmap ( base ) ;
2008-08-05 19:37:25 +01:00
return err ;
}