2005-04-17 05:20:36 +07:00
/*******************************************************************************
*
* Module Name : hwregs - Read / write access functions for the various ACPI
* control and status registers .
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/*
* Copyright ( C ) 2000 - 2005 , R . Byron Moore
* All rights reserved .
*
* Redistribution and use in source and binary forms , with or without
* modification , are permitted provided that the following conditions
* are met :
* 1. Redistributions of source code must retain the above copyright
* notice , this list of conditions , and the following disclaimer ,
* without modification .
* 2. Redistributions in binary form must reproduce at minimum a disclaimer
* substantially similar to the " NO WARRANTY " disclaimer below
* ( " Disclaimer " ) and any redistribution must be conditioned upon
* including a substantially similar Disclaimer requirement for further
* binary redistribution .
* 3. Neither the names of the above - listed copyright holders nor the names
* of any contributors may be used to endorse or promote products derived
* from this software without specific prior written permission .
*
* Alternatively , this software may be distributed under the terms of the
* GNU General Public License ( " GPL " ) version 2 as published by the Free
* Software Foundation .
*
* NO WARRANTY
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* " AS IS " AND ANY EXPRESS OR IMPLIED WARRANTIES , INCLUDING , BUT NOT
* LIMITED TO , THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED . IN NO EVENT SHALL THE COPYRIGHT
* HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL , EXEMPLARY , OR CONSEQUENTIAL
* DAMAGES ( INCLUDING , BUT NOT LIMITED TO , PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES ; LOSS OF USE , DATA , OR PROFITS ; OR BUSINESS INTERRUPTION )
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY , WHETHER IN CONTRACT ,
* STRICT LIABILITY , OR TORT ( INCLUDING NEGLIGENCE OR OTHERWISE ) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE , EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGES .
*/
# include <linux/module.h>
# include <acpi/acpi.h>
# include <acpi/acnamesp.h>
# include <acpi/acevents.h>
# define _COMPONENT ACPI_HARDWARE
2005-08-05 11:44:28 +07:00
ACPI_MODULE_NAME ( " hwregs " )
2005-04-17 05:20:36 +07:00
/*******************************************************************************
*
* FUNCTION : acpi_hw_clear_acpi_status
*
* PARAMETERS : Flags - Lock the hardware or not
*
* RETURN : none
*
* DESCRIPTION : Clears all fixed and general purpose status bits
* THIS FUNCTION MUST BE CALLED WITH INTERRUPTS DISABLED
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2005-08-05 11:44:28 +07:00
acpi_status acpi_hw_clear_acpi_status ( u32 flags )
2005-04-17 05:20:36 +07:00
{
2005-08-05 11:44:28 +07:00
acpi_status status ;
2005-04-17 05:20:36 +07:00
2005-08-05 11:44:28 +07:00
ACPI_FUNCTION_TRACE ( " hw_clear_acpi_status " ) ;
2005-04-17 05:20:36 +07:00
2005-08-05 11:44:28 +07:00
ACPI_DEBUG_PRINT ( ( ACPI_DB_IO , " About to write %04X to %04X \n " ,
ACPI_BITMASK_ALL_FIXED_STATUS ,
( u16 ) acpi_gbl_FADT - > xpm1a_evt_blk . address ) ) ;
2005-04-17 05:20:36 +07:00
if ( flags & ACPI_MTX_LOCK ) {
2005-08-05 11:44:28 +07:00
status = acpi_ut_acquire_mutex ( ACPI_MTX_HARDWARE ) ;
if ( ACPI_FAILURE ( status ) ) {
return_ACPI_STATUS ( status ) ;
2005-04-17 05:20:36 +07:00
}
}
2005-08-05 11:44:28 +07:00
status = acpi_hw_register_write ( ACPI_MTX_DO_NOT_LOCK ,
ACPI_REGISTER_PM1_STATUS ,
ACPI_BITMASK_ALL_FIXED_STATUS ) ;
if ( ACPI_FAILURE ( status ) ) {
2005-04-17 05:20:36 +07:00
goto unlock_and_exit ;
}
/* Clear the fixed events */
if ( acpi_gbl_FADT - > xpm1b_evt_blk . address ) {
2005-08-05 11:44:28 +07:00
status =
acpi_hw_low_level_write ( 16 , ACPI_BITMASK_ALL_FIXED_STATUS ,
& acpi_gbl_FADT - > xpm1b_evt_blk ) ;
if ( ACPI_FAILURE ( status ) ) {
2005-04-17 05:20:36 +07:00
goto unlock_and_exit ;
}
}
/* Clear the GPE Bits in all GPE registers in all GPE blocks */
2005-08-05 11:44:28 +07:00
status = acpi_ev_walk_gpe_list ( acpi_hw_clear_gpe_block ) ;
2005-04-17 05:20:36 +07:00
2005-08-05 11:44:28 +07:00
unlock_and_exit :
2005-04-17 05:20:36 +07:00
if ( flags & ACPI_MTX_LOCK ) {
2005-08-05 11:44:28 +07:00
( void ) acpi_ut_release_mutex ( ACPI_MTX_HARDWARE ) ;
2005-04-17 05:20:36 +07:00
}
2005-08-05 11:44:28 +07:00
return_ACPI_STATUS ( status ) ;
2005-04-17 05:20:36 +07:00
}
/*******************************************************************************
*
* FUNCTION : acpi_get_sleep_type_data
*
* PARAMETERS : sleep_state - Numeric sleep state
* * sleep_type_a - Where SLP_TYPa is returned
* * sleep_type_b - Where SLP_TYPb is returned
*
* RETURN : Status - ACPI status
*
* DESCRIPTION : Obtain the SLP_TYPa and SLP_TYPb values for the requested sleep
* state .
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
acpi_status
2005-08-05 11:44:28 +07:00
acpi_get_sleep_type_data ( u8 sleep_state , u8 * sleep_type_a , u8 * sleep_type_b )
2005-04-17 05:20:36 +07:00
{
2005-08-05 11:44:28 +07:00
acpi_status status = AE_OK ;
struct acpi_parameter_info info ;
char * sleep_state_name ;
2005-04-17 05:20:36 +07:00
2005-08-05 11:44:28 +07:00
ACPI_FUNCTION_TRACE ( " acpi_get_sleep_type_data " ) ;
2005-04-17 05:20:36 +07:00
2005-04-19 09:49:35 +07:00
/* Validate parameters */
2005-08-05 11:44:28 +07:00
if ( ( sleep_state > ACPI_S_STATES_MAX ) | | ! sleep_type_a | | ! sleep_type_b ) {
return_ACPI_STATUS ( AE_BAD_PARAMETER ) ;
2005-04-17 05:20:36 +07:00
}
2005-04-19 09:49:35 +07:00
/* Evaluate the namespace object containing the values for this state */
2005-04-17 05:20:36 +07:00
info . parameters = NULL ;
2005-04-19 09:49:35 +07:00
info . return_object = NULL ;
2005-08-05 11:44:28 +07:00
sleep_state_name = ( char * ) acpi_gbl_sleep_state_names [ sleep_state ] ;
2005-04-19 09:49:35 +07:00
2005-08-05 11:44:28 +07:00
status = acpi_ns_evaluate_by_name ( sleep_state_name , & info ) ;
if ( ACPI_FAILURE ( status ) ) {
ACPI_DEBUG_PRINT ( ( ACPI_DB_EXEC ,
" %s while evaluating sleep_state [%s] \n " ,
acpi_format_exception ( status ) ,
sleep_state_name ) ) ;
2005-04-17 05:20:36 +07:00
2005-08-05 11:44:28 +07:00
return_ACPI_STATUS ( status ) ;
2005-04-17 05:20:36 +07:00
}
/* Must have a return object */
if ( ! info . return_object ) {
2005-08-05 11:44:28 +07:00
ACPI_REPORT_ERROR ( ( " No Sleep State object returned from [%s] \n " ,
sleep_state_name ) ) ;
2005-04-17 05:20:36 +07:00
status = AE_NOT_EXIST ;
}
/* It must be of type Package */
2005-08-05 11:44:28 +07:00
else if ( ACPI_GET_OBJECT_TYPE ( info . return_object ) ! = ACPI_TYPE_PACKAGE ) {
ACPI_REPORT_ERROR ( ( " Sleep State return object is not a Package \n " ) ) ;
2005-04-17 05:20:36 +07:00
status = AE_AML_OPERAND_TYPE ;
}
2005-04-19 09:49:35 +07:00
/*
* The package must have at least two elements . NOTE ( March 2005 ) : This
* goes against the current ACPI spec which defines this object as a
* package with one encoded DWORD element . However , existing practice
* by BIOS vendors seems to be to have 2 or more elements , at least
* one per sleep type ( A / B ) .
*/
2005-04-17 05:20:36 +07:00
else if ( info . return_object - > package . count < 2 ) {
2005-08-05 11:44:28 +07:00
ACPI_REPORT_ERROR ( ( " Sleep State return package does not have at least two elements \n " ) ) ;
2005-04-17 05:20:36 +07:00
status = AE_AML_NO_OPERAND ;
}
/* The first two elements must both be of type Integer */
2005-08-05 11:44:28 +07:00
else if ( ( ACPI_GET_OBJECT_TYPE ( info . return_object - > package . elements [ 0 ] )
! = ACPI_TYPE_INTEGER ) | |
( ACPI_GET_OBJECT_TYPE ( info . return_object - > package . elements [ 1 ] )
! = ACPI_TYPE_INTEGER ) ) {
ACPI_REPORT_ERROR ( ( " Sleep State return package elements are not both Integers (%s, %s) \n " , acpi_ut_get_object_type_name ( info . return_object - > package . elements [ 0 ] ) , acpi_ut_get_object_type_name ( info . return_object - > package . elements [ 1 ] ) ) ) ;
2005-04-17 05:20:36 +07:00
status = AE_AML_OPERAND_TYPE ;
2005-08-05 11:44:28 +07:00
} else {
2005-04-19 09:49:35 +07:00
/* Valid _Sx_ package size, type, and value */
* sleep_type_a = ( u8 )
2005-08-05 11:44:28 +07:00
( info . return_object - > package . elements [ 0 ] ) - > integer . value ;
2005-04-19 09:49:35 +07:00
* sleep_type_b = ( u8 )
2005-08-05 11:44:28 +07:00
( info . return_object - > package . elements [ 1 ] ) - > integer . value ;
2005-04-17 05:20:36 +07:00
}
2005-08-05 11:44:28 +07:00
if ( ACPI_FAILURE ( status ) ) {
ACPI_DEBUG_PRINT ( ( ACPI_DB_ERROR ,
" %s While evaluating sleep_state [%s], bad Sleep object %p type %s \n " ,
acpi_format_exception ( status ) ,
sleep_state_name , info . return_object ,
acpi_ut_get_object_type_name ( info .
return_object ) ) ) ;
2005-04-17 05:20:36 +07:00
}
2005-08-05 11:44:28 +07:00
acpi_ut_remove_reference ( info . return_object ) ;
return_ACPI_STATUS ( status ) ;
2005-04-17 05:20:36 +07:00
}
2005-08-05 11:44:28 +07:00
EXPORT_SYMBOL ( acpi_get_sleep_type_data ) ;
2005-04-17 05:20:36 +07:00
/*******************************************************************************
*
* FUNCTION : acpi_hw_get_register_bit_mask
*
* PARAMETERS : register_id - Index of ACPI Register to access
*
2005-04-19 09:49:35 +07:00
* RETURN : The bitmask to be used when accessing the register
2005-04-17 05:20:36 +07:00
*
2005-04-19 09:49:35 +07:00
* DESCRIPTION : Map register_id into a register bitmask .
2005-04-17 05:20:36 +07:00
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2005-08-05 11:44:28 +07:00
struct acpi_bit_register_info * acpi_hw_get_bit_register_info ( u32 register_id )
2005-04-17 05:20:36 +07:00
{
2005-08-05 11:44:28 +07:00
ACPI_FUNCTION_NAME ( " hw_get_bit_register_info " ) ;
2005-04-17 05:20:36 +07:00
if ( register_id > ACPI_BITREG_MAX ) {
2005-08-05 11:44:28 +07:00
ACPI_DEBUG_PRINT ( ( ACPI_DB_ERROR ,
" Invalid bit_register ID: %X \n " ,
register_id ) ) ;
2005-04-17 05:20:36 +07:00
return ( NULL ) ;
}
return ( & acpi_gbl_bit_register_info [ register_id ] ) ;
}
/*******************************************************************************
*
* FUNCTION : acpi_get_register
*
* PARAMETERS : register_id - ID of ACPI bit_register to access
* return_value - Value that was read from the register
* Flags - Lock the hardware or not
*
* RETURN : Status and the value read from specified Register . Value
* returned is normalized to bit0 ( is shifted all the way right )
*
* DESCRIPTION : ACPI bit_register read function .
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2005-08-05 11:44:28 +07:00
acpi_status acpi_get_register ( u32 register_id , u32 * return_value , u32 flags )
2005-04-17 05:20:36 +07:00
{
2005-08-05 11:44:28 +07:00
u32 register_value = 0 ;
struct acpi_bit_register_info * bit_reg_info ;
acpi_status status ;
2005-04-17 05:20:36 +07:00
2005-08-05 11:44:28 +07:00
ACPI_FUNCTION_TRACE ( " acpi_get_register " ) ;
2005-04-17 05:20:36 +07:00
/* Get the info structure corresponding to the requested ACPI Register */
2005-08-05 11:44:28 +07:00
bit_reg_info = acpi_hw_get_bit_register_info ( register_id ) ;
2005-04-17 05:20:36 +07:00
if ( ! bit_reg_info ) {
2005-08-05 11:44:28 +07:00
return_ACPI_STATUS ( AE_BAD_PARAMETER ) ;
2005-04-17 05:20:36 +07:00
}
if ( flags & ACPI_MTX_LOCK ) {
2005-08-05 11:44:28 +07:00
status = acpi_ut_acquire_mutex ( ACPI_MTX_HARDWARE ) ;
if ( ACPI_FAILURE ( status ) ) {
return_ACPI_STATUS ( status ) ;
2005-04-17 05:20:36 +07:00
}
}
/* Read from the register */
2005-08-05 11:44:28 +07:00
status = acpi_hw_register_read ( ACPI_MTX_DO_NOT_LOCK ,
bit_reg_info - > parent_register ,
& register_value ) ;
2005-04-17 05:20:36 +07:00
if ( flags & ACPI_MTX_LOCK ) {
2005-08-05 11:44:28 +07:00
( void ) acpi_ut_release_mutex ( ACPI_MTX_HARDWARE ) ;
2005-04-17 05:20:36 +07:00
}
2005-08-05 11:44:28 +07:00
if ( ACPI_SUCCESS ( status ) ) {
2005-04-17 05:20:36 +07:00
/* Normalize the value that was read */
2005-08-05 11:44:28 +07:00
register_value =
( ( register_value & bit_reg_info - > access_bit_mask )
> > bit_reg_info - > bit_position ) ;
2005-04-17 05:20:36 +07:00
* return_value = register_value ;
2005-08-05 11:44:28 +07:00
ACPI_DEBUG_PRINT ( ( ACPI_DB_IO , " Read value %8.8X register %X \n " ,
register_value ,
bit_reg_info - > parent_register ) ) ;
2005-04-17 05:20:36 +07:00
}
2005-08-05 11:44:28 +07:00
return_ACPI_STATUS ( status ) ;
2005-04-17 05:20:36 +07:00
}
2005-08-05 11:44:28 +07:00
EXPORT_SYMBOL ( acpi_get_register ) ;
2005-04-17 05:20:36 +07:00
/*******************************************************************************
*
* FUNCTION : acpi_set_register
*
* PARAMETERS : register_id - ID of ACPI bit_register to access
* Value - ( only used on write ) value to write to the
* Register , NOT pre - normalized to the bit pos
* Flags - Lock the hardware or not
*
* RETURN : Status
*
* DESCRIPTION : ACPI Bit Register write function .
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2005-08-05 11:44:28 +07:00
acpi_status acpi_set_register ( u32 register_id , u32 value , u32 flags )
2005-04-17 05:20:36 +07:00
{
2005-08-05 11:44:28 +07:00
u32 register_value = 0 ;
struct acpi_bit_register_info * bit_reg_info ;
acpi_status status ;
2005-04-17 05:20:36 +07:00
2005-08-05 11:44:28 +07:00
ACPI_FUNCTION_TRACE_U32 ( " acpi_set_register " , register_id ) ;
2005-04-17 05:20:36 +07:00
/* Get the info structure corresponding to the requested ACPI Register */
2005-08-05 11:44:28 +07:00
bit_reg_info = acpi_hw_get_bit_register_info ( register_id ) ;
2005-04-17 05:20:36 +07:00
if ( ! bit_reg_info ) {
2005-08-05 11:44:28 +07:00
ACPI_REPORT_ERROR ( ( " Bad ACPI HW register_id: %X \n " ,
register_id ) ) ;
return_ACPI_STATUS ( AE_BAD_PARAMETER ) ;
2005-04-17 05:20:36 +07:00
}
if ( flags & ACPI_MTX_LOCK ) {
2005-08-05 11:44:28 +07:00
status = acpi_ut_acquire_mutex ( ACPI_MTX_HARDWARE ) ;
if ( ACPI_FAILURE ( status ) ) {
return_ACPI_STATUS ( status ) ;
2005-04-17 05:20:36 +07:00
}
}
/* Always do a register read first so we can insert the new bits */
2005-08-05 11:44:28 +07:00
status = acpi_hw_register_read ( ACPI_MTX_DO_NOT_LOCK ,
bit_reg_info - > parent_register ,
& register_value ) ;
if ( ACPI_FAILURE ( status ) ) {
2005-04-17 05:20:36 +07:00
goto unlock_and_exit ;
}
/*
* Decode the Register ID
* Register ID = [ Register block ID ] | [ bit ID ]
*
* Check bit ID to fine locate Register offset .
* Check Mask to determine Register offset , and then read - write .
*/
switch ( bit_reg_info - > parent_register ) {
case ACPI_REGISTER_PM1_STATUS :
/*
* Status Registers are different from the rest . Clear by
* writing 1 , and writing 0 has no effect . So , the only relevant
* information is the single bit we ' re interested in , all others should
* be written as 0 so they will be left unchanged .
*/
2005-08-05 11:44:28 +07:00
value = ACPI_REGISTER_PREPARE_BITS ( value ,
bit_reg_info - > bit_position ,
bit_reg_info - >
access_bit_mask ) ;
2005-04-17 05:20:36 +07:00
if ( value ) {
2005-08-05 11:44:28 +07:00
status = acpi_hw_register_write ( ACPI_MTX_DO_NOT_LOCK ,
ACPI_REGISTER_PM1_STATUS ,
( u16 ) value ) ;
2005-04-17 05:20:36 +07:00
register_value = 0 ;
}
break ;
case ACPI_REGISTER_PM1_ENABLE :
2005-08-05 11:44:28 +07:00
ACPI_REGISTER_INSERT_VALUE ( register_value ,
bit_reg_info - > bit_position ,
bit_reg_info - > access_bit_mask ,
value ) ;
2005-04-17 05:20:36 +07:00
2005-08-05 11:44:28 +07:00
status = acpi_hw_register_write ( ACPI_MTX_DO_NOT_LOCK ,
ACPI_REGISTER_PM1_ENABLE ,
( u16 ) register_value ) ;
2005-04-17 05:20:36 +07:00
break ;
case ACPI_REGISTER_PM1_CONTROL :
/*
* Write the PM1 Control register .
* Note that at this level , the fact that there are actually TWO
* registers ( A and B - and B may not exist ) is abstracted .
*/
2005-08-05 11:44:28 +07:00
ACPI_DEBUG_PRINT ( ( ACPI_DB_IO , " PM1 control: Read %X \n " ,
register_value ) ) ;
2005-04-17 05:20:36 +07:00
2005-08-05 11:44:28 +07:00
ACPI_REGISTER_INSERT_VALUE ( register_value ,
bit_reg_info - > bit_position ,
bit_reg_info - > access_bit_mask ,
value ) ;
2005-04-17 05:20:36 +07:00
2005-08-05 11:44:28 +07:00
status = acpi_hw_register_write ( ACPI_MTX_DO_NOT_LOCK ,
ACPI_REGISTER_PM1_CONTROL ,
( u16 ) register_value ) ;
2005-04-17 05:20:36 +07:00
break ;
case ACPI_REGISTER_PM2_CONTROL :
2005-08-05 11:44:28 +07:00
status = acpi_hw_register_read ( ACPI_MTX_DO_NOT_LOCK ,
ACPI_REGISTER_PM2_CONTROL ,
& register_value ) ;
if ( ACPI_FAILURE ( status ) ) {
2005-04-17 05:20:36 +07:00
goto unlock_and_exit ;
}
2005-08-05 11:44:28 +07:00
ACPI_DEBUG_PRINT ( ( ACPI_DB_IO ,
" PM2 control: Read %X from %8.8X%8.8X \n " ,
register_value ,
ACPI_FORMAT_UINT64 ( acpi_gbl_FADT - >
xpm2_cnt_blk . address ) ) ) ;
ACPI_REGISTER_INSERT_VALUE ( register_value ,
bit_reg_info - > bit_position ,
bit_reg_info - > access_bit_mask ,
value ) ;
ACPI_DEBUG_PRINT ( ( ACPI_DB_IO ,
" About to write %4.4X to %8.8X%8.8X \n " ,
register_value ,
ACPI_FORMAT_UINT64 ( acpi_gbl_FADT - >
xpm2_cnt_blk . address ) ) ) ;
status = acpi_hw_register_write ( ACPI_MTX_DO_NOT_LOCK ,
ACPI_REGISTER_PM2_CONTROL ,
( u8 ) ( register_value ) ) ;
2005-04-17 05:20:36 +07:00
break ;
default :
break ;
}
2005-08-05 11:44:28 +07:00
unlock_and_exit :
2005-04-17 05:20:36 +07:00
if ( flags & ACPI_MTX_LOCK ) {
2005-08-05 11:44:28 +07:00
( void ) acpi_ut_release_mutex ( ACPI_MTX_HARDWARE ) ;
2005-04-17 05:20:36 +07:00
}
/* Normalize the value that was read */
2005-08-05 11:44:28 +07:00
ACPI_DEBUG_EXEC ( register_value =
( ( register_value & bit_reg_info - > access_bit_mask ) > >
bit_reg_info - > bit_position ) ) ;
2005-04-17 05:20:36 +07:00
2005-08-05 11:44:28 +07:00
ACPI_DEBUG_PRINT ( ( ACPI_DB_IO ,
" Set bits: %8.8X actual %8.8X register %X \n " , value ,
register_value , bit_reg_info - > parent_register ) ) ;
return_ACPI_STATUS ( status ) ;
2005-04-17 05:20:36 +07:00
}
2005-08-05 11:44:28 +07:00
EXPORT_SYMBOL ( acpi_set_register ) ;
2005-04-17 05:20:36 +07:00
/******************************************************************************
*
* FUNCTION : acpi_hw_register_read
*
* PARAMETERS : use_lock - Mutex hw access
* register_id - register_iD + Offset
2005-04-19 09:49:35 +07:00
* return_value - Where the register value is returned
2005-04-17 05:20:36 +07:00
*
* RETURN : Status and the value read .
*
* DESCRIPTION : Acpi register read function . Registers are read at the
* given offset .
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
acpi_status
2005-08-05 11:44:28 +07:00
acpi_hw_register_read ( u8 use_lock , u32 register_id , u32 * return_value )
2005-04-17 05:20:36 +07:00
{
2005-08-05 11:44:28 +07:00
u32 value1 = 0 ;
u32 value2 = 0 ;
acpi_status status ;
2005-04-17 05:20:36 +07:00
2005-08-05 11:44:28 +07:00
ACPI_FUNCTION_TRACE ( " hw_register_read " ) ;
2005-04-17 05:20:36 +07:00
if ( ACPI_MTX_LOCK = = use_lock ) {
2005-08-05 11:44:28 +07:00
status = acpi_ut_acquire_mutex ( ACPI_MTX_HARDWARE ) ;
if ( ACPI_FAILURE ( status ) ) {
return_ACPI_STATUS ( status ) ;
2005-04-17 05:20:36 +07:00
}
}
switch ( register_id ) {
2005-08-05 11:44:28 +07:00
case ACPI_REGISTER_PM1_STATUS : /* 16-bit access */
2005-04-17 05:20:36 +07:00
2005-08-05 11:44:28 +07:00
status =
acpi_hw_low_level_read ( 16 , & value1 ,
& acpi_gbl_FADT - > xpm1a_evt_blk ) ;
if ( ACPI_FAILURE ( status ) ) {
2005-04-17 05:20:36 +07:00
goto unlock_and_exit ;
}
/* PM1B is optional */
2005-08-05 11:44:28 +07:00
status =
acpi_hw_low_level_read ( 16 , & value2 ,
& acpi_gbl_FADT - > xpm1b_evt_blk ) ;
2005-04-17 05:20:36 +07:00
value1 | = value2 ;
break ;
2005-08-05 11:44:28 +07:00
case ACPI_REGISTER_PM1_ENABLE : /* 16-bit access */
2005-04-17 05:20:36 +07:00
2005-08-05 11:44:28 +07:00
status =
acpi_hw_low_level_read ( 16 , & value1 , & acpi_gbl_xpm1a_enable ) ;
if ( ACPI_FAILURE ( status ) ) {
2005-04-17 05:20:36 +07:00
goto unlock_and_exit ;
}
/* PM1B is optional */
2005-08-05 11:44:28 +07:00
status =
acpi_hw_low_level_read ( 16 , & value2 , & acpi_gbl_xpm1b_enable ) ;
2005-04-17 05:20:36 +07:00
value1 | = value2 ;
break ;
2005-08-05 11:44:28 +07:00
case ACPI_REGISTER_PM1_CONTROL : /* 16-bit access */
2005-04-17 05:20:36 +07:00
2005-08-05 11:44:28 +07:00
status =
acpi_hw_low_level_read ( 16 , & value1 ,
& acpi_gbl_FADT - > xpm1a_cnt_blk ) ;
if ( ACPI_FAILURE ( status ) ) {
2005-04-17 05:20:36 +07:00
goto unlock_and_exit ;
}
2005-08-05 11:44:28 +07:00
status =
acpi_hw_low_level_read ( 16 , & value2 ,
& acpi_gbl_FADT - > xpm1b_cnt_blk ) ;
2005-04-17 05:20:36 +07:00
value1 | = value2 ;
break ;
2005-08-05 11:44:28 +07:00
case ACPI_REGISTER_PM2_CONTROL : /* 8-bit access */
2005-04-17 05:20:36 +07:00
2005-08-05 11:44:28 +07:00
status =
acpi_hw_low_level_read ( 8 , & value1 ,
& acpi_gbl_FADT - > xpm2_cnt_blk ) ;
2005-04-17 05:20:36 +07:00
break ;
2005-08-05 11:44:28 +07:00
case ACPI_REGISTER_PM_TIMER : /* 32-bit access */
2005-04-17 05:20:36 +07:00
2005-08-05 11:44:28 +07:00
status =
acpi_hw_low_level_read ( 32 , & value1 ,
& acpi_gbl_FADT - > xpm_tmr_blk ) ;
2005-04-17 05:20:36 +07:00
break ;
2005-08-05 11:44:28 +07:00
case ACPI_REGISTER_SMI_COMMAND_BLOCK : /* 8-bit access */
2005-04-17 05:20:36 +07:00
2005-08-05 11:44:28 +07:00
status = acpi_os_read_port ( acpi_gbl_FADT - > smi_cmd , & value1 , 8 ) ;
2005-04-17 05:20:36 +07:00
break ;
default :
2005-08-05 11:44:28 +07:00
ACPI_DEBUG_PRINT ( ( ACPI_DB_ERROR , " Unknown Register ID: %X \n " ,
register_id ) ) ;
2005-04-17 05:20:36 +07:00
status = AE_BAD_PARAMETER ;
break ;
}
2005-08-05 11:44:28 +07:00
unlock_and_exit :
2005-04-17 05:20:36 +07:00
if ( ACPI_MTX_LOCK = = use_lock ) {
2005-08-05 11:44:28 +07:00
( void ) acpi_ut_release_mutex ( ACPI_MTX_HARDWARE ) ;
2005-04-17 05:20:36 +07:00
}
2005-08-05 11:44:28 +07:00
if ( ACPI_SUCCESS ( status ) ) {
2005-04-17 05:20:36 +07:00
* return_value = value1 ;
}
2005-08-05 11:44:28 +07:00
return_ACPI_STATUS ( status ) ;
2005-04-17 05:20:36 +07:00
}
/******************************************************************************
*
* FUNCTION : acpi_hw_register_write
*
* PARAMETERS : use_lock - Mutex hw access
* register_id - register_iD + Offset
* Value - The value to write
*
* RETURN : Status
*
* DESCRIPTION : Acpi register Write function . Registers are written at the
* given offset .
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2005-08-05 11:44:28 +07:00
acpi_status acpi_hw_register_write ( u8 use_lock , u32 register_id , u32 value )
2005-04-17 05:20:36 +07:00
{
2005-08-05 11:44:28 +07:00
acpi_status status ;
2005-04-17 05:20:36 +07:00
2005-08-05 11:44:28 +07:00
ACPI_FUNCTION_TRACE ( " hw_register_write " ) ;
2005-04-17 05:20:36 +07:00
if ( ACPI_MTX_LOCK = = use_lock ) {
2005-08-05 11:44:28 +07:00
status = acpi_ut_acquire_mutex ( ACPI_MTX_HARDWARE ) ;
if ( ACPI_FAILURE ( status ) ) {
return_ACPI_STATUS ( status ) ;
2005-04-17 05:20:36 +07:00
}
}
switch ( register_id ) {
2005-08-05 11:44:28 +07:00
case ACPI_REGISTER_PM1_STATUS : /* 16-bit access */
2005-04-17 05:20:36 +07:00
2005-08-05 11:44:28 +07:00
status =
acpi_hw_low_level_write ( 16 , value ,
& acpi_gbl_FADT - > xpm1a_evt_blk ) ;
if ( ACPI_FAILURE ( status ) ) {
2005-04-17 05:20:36 +07:00
goto unlock_and_exit ;
}
/* PM1B is optional */
2005-08-05 11:44:28 +07:00
status =
acpi_hw_low_level_write ( 16 , value ,
& acpi_gbl_FADT - > xpm1b_evt_blk ) ;
2005-04-17 05:20:36 +07:00
break ;
2005-08-05 11:44:28 +07:00
case ACPI_REGISTER_PM1_ENABLE : /* 16-bit access */
2005-04-17 05:20:36 +07:00
2005-08-05 11:44:28 +07:00
status =
acpi_hw_low_level_write ( 16 , value , & acpi_gbl_xpm1a_enable ) ;
if ( ACPI_FAILURE ( status ) ) {
2005-04-17 05:20:36 +07:00
goto unlock_and_exit ;
}
/* PM1B is optional */
2005-08-05 11:44:28 +07:00
status =
acpi_hw_low_level_write ( 16 , value , & acpi_gbl_xpm1b_enable ) ;
2005-04-17 05:20:36 +07:00
break ;
2005-08-05 11:44:28 +07:00
case ACPI_REGISTER_PM1_CONTROL : /* 16-bit access */
2005-04-17 05:20:36 +07:00
2005-08-05 11:44:28 +07:00
status =
acpi_hw_low_level_write ( 16 , value ,
& acpi_gbl_FADT - > xpm1a_cnt_blk ) ;
if ( ACPI_FAILURE ( status ) ) {
2005-04-17 05:20:36 +07:00
goto unlock_and_exit ;
}
2005-08-05 11:44:28 +07:00
status =
acpi_hw_low_level_write ( 16 , value ,
& acpi_gbl_FADT - > xpm1b_cnt_blk ) ;
2005-04-17 05:20:36 +07:00
break ;
2005-08-05 11:44:28 +07:00
case ACPI_REGISTER_PM1A_CONTROL : /* 16-bit access */
2005-04-17 05:20:36 +07:00
2005-08-05 11:44:28 +07:00
status =
acpi_hw_low_level_write ( 16 , value ,
& acpi_gbl_FADT - > xpm1a_cnt_blk ) ;
2005-04-17 05:20:36 +07:00
break ;
2005-08-05 11:44:28 +07:00
case ACPI_REGISTER_PM1B_CONTROL : /* 16-bit access */
2005-04-17 05:20:36 +07:00
2005-08-05 11:44:28 +07:00
status =
acpi_hw_low_level_write ( 16 , value ,
& acpi_gbl_FADT - > xpm1b_cnt_blk ) ;
2005-04-17 05:20:36 +07:00
break ;
2005-08-05 11:44:28 +07:00
case ACPI_REGISTER_PM2_CONTROL : /* 8-bit access */
2005-04-17 05:20:36 +07:00
2005-08-05 11:44:28 +07:00
status =
acpi_hw_low_level_write ( 8 , value ,
& acpi_gbl_FADT - > xpm2_cnt_blk ) ;
2005-04-17 05:20:36 +07:00
break ;
2005-08-05 11:44:28 +07:00
case ACPI_REGISTER_PM_TIMER : /* 32-bit access */
2005-04-17 05:20:36 +07:00
2005-08-05 11:44:28 +07:00
status =
acpi_hw_low_level_write ( 32 , value ,
& acpi_gbl_FADT - > xpm_tmr_blk ) ;
2005-04-17 05:20:36 +07:00
break ;
2005-08-05 11:44:28 +07:00
case ACPI_REGISTER_SMI_COMMAND_BLOCK : /* 8-bit access */
2005-04-17 05:20:36 +07:00
/* SMI_CMD is currently always in IO space */
2005-08-05 11:44:28 +07:00
status = acpi_os_write_port ( acpi_gbl_FADT - > smi_cmd , value , 8 ) ;
2005-04-17 05:20:36 +07:00
break ;
default :
status = AE_BAD_PARAMETER ;
break ;
}
2005-08-05 11:44:28 +07:00
unlock_and_exit :
2005-04-17 05:20:36 +07:00
if ( ACPI_MTX_LOCK = = use_lock ) {
2005-08-05 11:44:28 +07:00
( void ) acpi_ut_release_mutex ( ACPI_MTX_HARDWARE ) ;
2005-04-17 05:20:36 +07:00
}
2005-08-05 11:44:28 +07:00
return_ACPI_STATUS ( status ) ;
2005-04-17 05:20:36 +07:00
}
/******************************************************************************
*
* FUNCTION : acpi_hw_low_level_read
*
* PARAMETERS : Width - 8 , 16 , or 32
* Value - Where the value is returned
* Reg - GAS register structure
*
* RETURN : Status
*
* DESCRIPTION : Read from either memory or IO space .
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
acpi_status
2005-08-05 11:44:28 +07:00
acpi_hw_low_level_read ( u32 width , u32 * value , struct acpi_generic_address * reg )
2005-04-17 05:20:36 +07:00
{
2005-08-05 11:44:28 +07:00
u64 address ;
acpi_status status ;
2005-04-17 05:20:36 +07:00
2005-08-05 11:44:28 +07:00
ACPI_FUNCTION_NAME ( " hw_low_level_read " ) ;
2005-04-17 05:20:36 +07:00
/*
* Must have a valid pointer to a GAS structure , and
* a non - zero address within . However , don ' t return an error
* because the PM1A / B code must not fail if B isn ' t present .
*/
if ( ! reg ) {
return ( AE_OK ) ;
}
/* Get a local copy of the address. Handles possible alignment issues */
2005-08-05 11:44:28 +07:00
ACPI_MOVE_64_TO_64 ( & address , & reg - > address ) ;
2005-04-17 05:20:36 +07:00
if ( ! address ) {
return ( AE_OK ) ;
}
* value = 0 ;
/*
* Two address spaces supported : Memory or IO .
* PCI_Config is not supported here because the GAS struct is insufficient
*/
switch ( reg - > address_space_id ) {
case ACPI_ADR_SPACE_SYSTEM_MEMORY :
2005-08-05 11:44:28 +07:00
status = acpi_os_read_memory ( ( acpi_physical_address ) address ,
value , width ) ;
2005-04-17 05:20:36 +07:00
break ;
case ACPI_ADR_SPACE_SYSTEM_IO :
2005-08-05 11:44:28 +07:00
status = acpi_os_read_port ( ( acpi_io_address ) address ,
value , width ) ;
2005-04-17 05:20:36 +07:00
break ;
default :
2005-08-05 11:44:28 +07:00
ACPI_DEBUG_PRINT ( ( ACPI_DB_ERROR ,
" Unsupported address space: %X \n " ,
reg - > address_space_id ) ) ;
2005-04-17 05:20:36 +07:00
return ( AE_BAD_PARAMETER ) ;
}
2005-08-05 11:44:28 +07:00
ACPI_DEBUG_PRINT ( ( ACPI_DB_IO ,
" Read: %8.8X width %2d from %8.8X%8.8X (%s) \n " ,
* value , width ,
ACPI_FORMAT_UINT64 ( address ) ,
acpi_ut_get_region_name ( reg - > address_space_id ) ) ) ;
2005-04-17 05:20:36 +07:00
return ( status ) ;
}
/******************************************************************************
*
* FUNCTION : acpi_hw_low_level_write
*
* PARAMETERS : Width - 8 , 16 , or 32
* Value - To be written
* Reg - GAS register structure
*
* RETURN : Status
*
* DESCRIPTION : Write to either memory or IO space .
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
acpi_status
2005-08-05 11:44:28 +07:00
acpi_hw_low_level_write ( u32 width , u32 value , struct acpi_generic_address * reg )
2005-04-17 05:20:36 +07:00
{
2005-08-05 11:44:28 +07:00
u64 address ;
acpi_status status ;
2005-04-17 05:20:36 +07:00
2005-08-05 11:44:28 +07:00
ACPI_FUNCTION_NAME ( " hw_low_level_write " ) ;
2005-04-17 05:20:36 +07:00
/*
* Must have a valid pointer to a GAS structure , and
* a non - zero address within . However , don ' t return an error
* because the PM1A / B code must not fail if B isn ' t present .
*/
if ( ! reg ) {
return ( AE_OK ) ;
}
/* Get a local copy of the address. Handles possible alignment issues */
2005-08-05 11:44:28 +07:00
ACPI_MOVE_64_TO_64 ( & address , & reg - > address ) ;
2005-04-17 05:20:36 +07:00
if ( ! address ) {
return ( AE_OK ) ;
}
/*
* Two address spaces supported : Memory or IO .
* PCI_Config is not supported here because the GAS struct is insufficient
*/
switch ( reg - > address_space_id ) {
case ACPI_ADR_SPACE_SYSTEM_MEMORY :
2005-08-05 11:44:28 +07:00
status = acpi_os_write_memory ( ( acpi_physical_address ) address ,
value , width ) ;
2005-04-17 05:20:36 +07:00
break ;
case ACPI_ADR_SPACE_SYSTEM_IO :
2005-08-05 11:44:28 +07:00
status = acpi_os_write_port ( ( acpi_io_address ) address ,
value , width ) ;
2005-04-17 05:20:36 +07:00
break ;
default :
2005-08-05 11:44:28 +07:00
ACPI_DEBUG_PRINT ( ( ACPI_DB_ERROR ,
" Unsupported address space: %X \n " ,
reg - > address_space_id ) ) ;
2005-04-17 05:20:36 +07:00
return ( AE_BAD_PARAMETER ) ;
}
2005-08-05 11:44:28 +07:00
ACPI_DEBUG_PRINT ( ( ACPI_DB_IO ,
" Wrote: %8.8X width %2d to %8.8X%8.8X (%s) \n " ,
value , width ,
ACPI_FORMAT_UINT64 ( address ) ,
acpi_ut_get_region_name ( reg - > address_space_id ) ) ) ;
2005-04-17 05:20:36 +07:00
return ( status ) ;
}