195b482a8SLen Brown 295b482a8SLen Brown /******************************************************************************* 395b482a8SLen Brown * 495b482a8SLen Brown * Module Name: hwregs - Read/write access functions for the various ACPI 595b482a8SLen Brown * control and status registers. 695b482a8SLen Brown * 795b482a8SLen Brown ******************************************************************************/ 895b482a8SLen Brown 995b482a8SLen Brown /* 1095b482a8SLen Brown * Copyright (C) 2000 - 2008, Intel Corp. 1195b482a8SLen Brown * All rights reserved. 1295b482a8SLen Brown * 1395b482a8SLen Brown * Redistribution and use in source and binary forms, with or without 1495b482a8SLen Brown * modification, are permitted provided that the following conditions 1595b482a8SLen Brown * are met: 1695b482a8SLen Brown * 1. Redistributions of source code must retain the above copyright 1795b482a8SLen Brown * notice, this list of conditions, and the following disclaimer, 1895b482a8SLen Brown * without modification. 1995b482a8SLen Brown * 2. Redistributions in binary form must reproduce at minimum a disclaimer 2095b482a8SLen Brown * substantially similar to the "NO WARRANTY" disclaimer below 2195b482a8SLen Brown * ("Disclaimer") and any redistribution must be conditioned upon 2295b482a8SLen Brown * including a substantially similar Disclaimer requirement for further 2395b482a8SLen Brown * binary redistribution. 2495b482a8SLen Brown * 3. Neither the names of the above-listed copyright holders nor the names 2595b482a8SLen Brown * of any contributors may be used to endorse or promote products derived 2695b482a8SLen Brown * from this software without specific prior written permission. 2795b482a8SLen Brown * 2895b482a8SLen Brown * Alternatively, this software may be distributed under the terms of the 2995b482a8SLen Brown * GNU General Public License ("GPL") version 2 as published by the Free 3095b482a8SLen Brown * Software Foundation. 3195b482a8SLen Brown * 3295b482a8SLen Brown * NO WARRANTY 3395b482a8SLen Brown * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 3495b482a8SLen Brown * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 3595b482a8SLen Brown * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR 3695b482a8SLen Brown * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 3795b482a8SLen Brown * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 3895b482a8SLen Brown * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 3995b482a8SLen Brown * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 4095b482a8SLen Brown * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 4195b482a8SLen Brown * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 4295b482a8SLen Brown * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 4395b482a8SLen Brown * POSSIBILITY OF SUCH DAMAGES. 4495b482a8SLen Brown */ 4595b482a8SLen Brown 4695b482a8SLen Brown #include <acpi/acpi.h> 47e2f7a777SLen Brown #include "accommon.h" 48e2f7a777SLen Brown #include "acnamesp.h" 49e2f7a777SLen Brown #include "acevents.h" 5095b482a8SLen Brown 5195b482a8SLen Brown #define _COMPONENT ACPI_HARDWARE 5295b482a8SLen Brown ACPI_MODULE_NAME("hwregs") 5395b482a8SLen Brown 54c520abadSBob Moore /* Local Prototypes */ 55c520abadSBob Moore static acpi_status 56c520abadSBob Moore acpi_hw_read_multiple(u32 *value, 57c520abadSBob Moore struct acpi_generic_address *register_a, 58c520abadSBob Moore struct acpi_generic_address *register_b); 59c520abadSBob Moore 60c520abadSBob Moore static acpi_status 61c520abadSBob Moore acpi_hw_write_multiple(u32 value, 62c520abadSBob Moore struct acpi_generic_address *register_a, 63c520abadSBob Moore struct acpi_generic_address *register_b); 64c520abadSBob Moore 6595b482a8SLen Brown /******************************************************************************* 6695b482a8SLen Brown * 6795b482a8SLen Brown * FUNCTION: acpi_hw_clear_acpi_status 6895b482a8SLen Brown * 6995b482a8SLen Brown * PARAMETERS: None 7095b482a8SLen Brown * 7195b482a8SLen Brown * RETURN: Status 7295b482a8SLen Brown * 7395b482a8SLen Brown * DESCRIPTION: Clears all fixed and general purpose status bits 7495b482a8SLen Brown * 7595b482a8SLen Brown ******************************************************************************/ 76c520abadSBob Moore 7795b482a8SLen Brown acpi_status acpi_hw_clear_acpi_status(void) 7895b482a8SLen Brown { 7995b482a8SLen Brown acpi_status status; 8095b482a8SLen Brown acpi_cpu_flags lock_flags = 0; 8195b482a8SLen Brown 8295b482a8SLen Brown ACPI_FUNCTION_TRACE(hw_clear_acpi_status); 8395b482a8SLen Brown 84227243a0SBob Moore ACPI_DEBUG_PRINT((ACPI_DB_IO, "About to write %04X to %0llX\n", 8595b482a8SLen Brown ACPI_BITMASK_ALL_FIXED_STATUS, 86227243a0SBob Moore acpi_gbl_xpm1a_status.address)); 8795b482a8SLen Brown 8895b482a8SLen Brown lock_flags = acpi_os_acquire_lock(acpi_gbl_hardware_lock); 8995b482a8SLen Brown 90227243a0SBob Moore /* Clear the fixed events in PM1 A/B */ 91531c633dSBob Moore 9295b482a8SLen Brown status = acpi_hw_register_write(ACPI_REGISTER_PM1_STATUS, 9395b482a8SLen Brown ACPI_BITMASK_ALL_FIXED_STATUS); 9495b482a8SLen Brown if (ACPI_FAILURE(status)) { 9595b482a8SLen Brown goto unlock_and_exit; 9695b482a8SLen Brown } 9795b482a8SLen Brown 9895b482a8SLen Brown /* Clear the GPE Bits in all GPE registers in all GPE blocks */ 9995b482a8SLen Brown 10095b482a8SLen Brown status = acpi_ev_walk_gpe_list(acpi_hw_clear_gpe_block, NULL); 10195b482a8SLen Brown 10295b482a8SLen Brown unlock_and_exit: 10395b482a8SLen Brown acpi_os_release_lock(acpi_gbl_hardware_lock, lock_flags); 10495b482a8SLen Brown return_ACPI_STATUS(status); 10595b482a8SLen Brown } 10695b482a8SLen Brown 10795b482a8SLen Brown /******************************************************************************* 10895b482a8SLen Brown * 10995b482a8SLen Brown * FUNCTION: acpi_hw_get_register_bit_mask 11095b482a8SLen Brown * 11195b482a8SLen Brown * PARAMETERS: register_id - Index of ACPI Register to access 11295b482a8SLen Brown * 11395b482a8SLen Brown * RETURN: The bitmask to be used when accessing the register 11495b482a8SLen Brown * 11595b482a8SLen Brown * DESCRIPTION: Map register_id into a register bitmask. 11695b482a8SLen Brown * 11795b482a8SLen Brown ******************************************************************************/ 11895b482a8SLen Brown 11995b482a8SLen Brown struct acpi_bit_register_info *acpi_hw_get_bit_register_info(u32 register_id) 12095b482a8SLen Brown { 12195b482a8SLen Brown ACPI_FUNCTION_ENTRY(); 12295b482a8SLen Brown 12395b482a8SLen Brown if (register_id > ACPI_BITREG_MAX) { 12495b482a8SLen Brown ACPI_ERROR((AE_INFO, "Invalid BitRegister ID: %X", 12595b482a8SLen Brown register_id)); 12695b482a8SLen Brown return (NULL); 12795b482a8SLen Brown } 12895b482a8SLen Brown 12995b482a8SLen Brown return (&acpi_gbl_bit_register_info[register_id]); 13095b482a8SLen Brown } 13195b482a8SLen Brown 13295b482a8SLen Brown /****************************************************************************** 13395b482a8SLen Brown * 13432c9ef99SBob Moore * FUNCTION: acpi_hw_write_pm1_control 13532c9ef99SBob Moore * 13632c9ef99SBob Moore * PARAMETERS: pm1a_control - Value to be written to PM1A control 13732c9ef99SBob Moore * pm1b_control - Value to be written to PM1B control 13832c9ef99SBob Moore * 13932c9ef99SBob Moore * RETURN: Status 14032c9ef99SBob Moore * 14132c9ef99SBob Moore * DESCRIPTION: Write the PM1 A/B control registers. These registers are 14232c9ef99SBob Moore * different than than the PM1 A/B status and enable registers 14332c9ef99SBob Moore * in that different values can be written to the A/B registers. 14432c9ef99SBob Moore * Most notably, the SLP_TYP bits can be different, as per the 14532c9ef99SBob Moore * values returned from the _Sx predefined methods. 14632c9ef99SBob Moore * 14732c9ef99SBob Moore ******************************************************************************/ 14832c9ef99SBob Moore 14932c9ef99SBob Moore acpi_status acpi_hw_write_pm1_control(u32 pm1a_control, u32 pm1b_control) 15032c9ef99SBob Moore { 15132c9ef99SBob Moore acpi_status status; 15232c9ef99SBob Moore 15332c9ef99SBob Moore ACPI_FUNCTION_TRACE(hw_write_pm1_control); 15432c9ef99SBob Moore 15532c9ef99SBob Moore status = acpi_write(pm1a_control, &acpi_gbl_FADT.xpm1a_control_block); 15632c9ef99SBob Moore if (ACPI_FAILURE(status)) { 15732c9ef99SBob Moore return_ACPI_STATUS(status); 15832c9ef99SBob Moore } 15932c9ef99SBob Moore 16032c9ef99SBob Moore if (acpi_gbl_FADT.xpm1b_control_block.address) { 16132c9ef99SBob Moore status = 16232c9ef99SBob Moore acpi_write(pm1b_control, 16332c9ef99SBob Moore &acpi_gbl_FADT.xpm1b_control_block); 16432c9ef99SBob Moore } 16532c9ef99SBob Moore return_ACPI_STATUS(status); 16632c9ef99SBob Moore } 16732c9ef99SBob Moore 16832c9ef99SBob Moore /****************************************************************************** 16932c9ef99SBob Moore * 17095b482a8SLen Brown * FUNCTION: acpi_hw_register_read 17195b482a8SLen Brown * 17295b482a8SLen Brown * PARAMETERS: register_id - ACPI Register ID 17395b482a8SLen Brown * return_value - Where the register value is returned 17495b482a8SLen Brown * 17595b482a8SLen Brown * RETURN: Status and the value read. 17695b482a8SLen Brown * 17795b482a8SLen Brown * DESCRIPTION: Read from the specified ACPI register 17895b482a8SLen Brown * 17995b482a8SLen Brown ******************************************************************************/ 18095b482a8SLen Brown acpi_status 18195b482a8SLen Brown acpi_hw_register_read(u32 register_id, u32 * return_value) 18295b482a8SLen Brown { 183c520abadSBob Moore u32 value = 0; 18495b482a8SLen Brown acpi_status status; 18595b482a8SLen Brown 18695b482a8SLen Brown ACPI_FUNCTION_TRACE(hw_register_read); 18795b482a8SLen Brown 18895b482a8SLen Brown switch (register_id) { 189c520abadSBob Moore case ACPI_REGISTER_PM1_STATUS: /* PM1 A/B: 16-bit access each */ 19095b482a8SLen Brown 191c520abadSBob Moore status = acpi_hw_read_multiple(&value, 192c520abadSBob Moore &acpi_gbl_xpm1a_status, 193c520abadSBob Moore &acpi_gbl_xpm1b_status); 19495b482a8SLen Brown break; 19595b482a8SLen Brown 196c520abadSBob Moore case ACPI_REGISTER_PM1_ENABLE: /* PM1 A/B: 16-bit access each */ 19795b482a8SLen Brown 198c520abadSBob Moore status = acpi_hw_read_multiple(&value, 199c520abadSBob Moore &acpi_gbl_xpm1a_enable, 200c520abadSBob Moore &acpi_gbl_xpm1b_enable); 20195b482a8SLen Brown break; 20295b482a8SLen Brown 203c520abadSBob Moore case ACPI_REGISTER_PM1_CONTROL: /* PM1 A/B: 16-bit access each */ 20495b482a8SLen Brown 205c520abadSBob Moore status = acpi_hw_read_multiple(&value, 206c520abadSBob Moore &acpi_gbl_FADT. 207c520abadSBob Moore xpm1a_control_block, 208c520abadSBob Moore &acpi_gbl_FADT. 209c520abadSBob Moore xpm1b_control_block); 21095b482a8SLen Brown break; 21195b482a8SLen Brown 21295b482a8SLen Brown case ACPI_REGISTER_PM2_CONTROL: /* 8-bit access */ 21395b482a8SLen Brown 214c520abadSBob Moore status = acpi_read(&value, &acpi_gbl_FADT.xpm2_control_block); 21595b482a8SLen Brown break; 21695b482a8SLen Brown 21795b482a8SLen Brown case ACPI_REGISTER_PM_TIMER: /* 32-bit access */ 21895b482a8SLen Brown 219c520abadSBob Moore status = acpi_read(&value, &acpi_gbl_FADT.xpm_timer_block); 22095b482a8SLen Brown break; 22195b482a8SLen Brown 22295b482a8SLen Brown case ACPI_REGISTER_SMI_COMMAND_BLOCK: /* 8-bit access */ 22395b482a8SLen Brown 22495b482a8SLen Brown status = 2257f071903SBob Moore acpi_hw_read_port(acpi_gbl_FADT.smi_command, &value, 8); 22695b482a8SLen Brown break; 22795b482a8SLen Brown 22895b482a8SLen Brown default: 22995b482a8SLen Brown ACPI_ERROR((AE_INFO, "Unknown Register ID: %X", register_id)); 23095b482a8SLen Brown status = AE_BAD_PARAMETER; 23195b482a8SLen Brown break; 23295b482a8SLen Brown } 23395b482a8SLen Brown 23495b482a8SLen Brown if (ACPI_SUCCESS(status)) { 235c520abadSBob Moore *return_value = value; 23695b482a8SLen Brown } 23795b482a8SLen Brown 23895b482a8SLen Brown return_ACPI_STATUS(status); 23995b482a8SLen Brown } 24095b482a8SLen Brown 24195b482a8SLen Brown /****************************************************************************** 24295b482a8SLen Brown * 24395b482a8SLen Brown * FUNCTION: acpi_hw_register_write 24495b482a8SLen Brown * 24595b482a8SLen Brown * PARAMETERS: register_id - ACPI Register ID 24695b482a8SLen Brown * Value - The value to write 24795b482a8SLen Brown * 24895b482a8SLen Brown * RETURN: Status 24995b482a8SLen Brown * 25095b482a8SLen Brown * DESCRIPTION: Write to the specified ACPI register 25195b482a8SLen Brown * 25295b482a8SLen Brown * NOTE: In accordance with the ACPI specification, this function automatically 25395b482a8SLen Brown * preserves the value of the following bits, meaning that these bits cannot be 25495b482a8SLen Brown * changed via this interface: 25595b482a8SLen Brown * 25695b482a8SLen Brown * PM1_CONTROL[0] = SCI_EN 25795b482a8SLen Brown * PM1_CONTROL[9] 25895b482a8SLen Brown * PM1_STATUS[11] 25995b482a8SLen Brown * 26095b482a8SLen Brown * ACPI References: 26195b482a8SLen Brown * 1) Hardware Ignored Bits: When software writes to a register with ignored 26295b482a8SLen Brown * bit fields, it preserves the ignored bit fields 26395b482a8SLen Brown * 2) SCI_EN: OSPM always preserves this bit position 26495b482a8SLen Brown * 26595b482a8SLen Brown ******************************************************************************/ 26695b482a8SLen Brown 26795b482a8SLen Brown acpi_status acpi_hw_register_write(u32 register_id, u32 value) 26895b482a8SLen Brown { 26995b482a8SLen Brown acpi_status status; 27095b482a8SLen Brown u32 read_value; 27195b482a8SLen Brown 27295b482a8SLen Brown ACPI_FUNCTION_TRACE(hw_register_write); 27395b482a8SLen Brown 27495b482a8SLen Brown switch (register_id) { 275c520abadSBob Moore case ACPI_REGISTER_PM1_STATUS: /* PM1 A/B: 16-bit access each */ 2768636f8d2SBob Moore /* 2778636f8d2SBob Moore * Handle the "ignored" bit in PM1 Status. According to the ACPI 2788636f8d2SBob Moore * specification, ignored bits are to be preserved when writing. 2798636f8d2SBob Moore * Normally, this would mean a read/modify/write sequence. However, 2808636f8d2SBob Moore * preserving a bit in the status register is different. Writing a 2818636f8d2SBob Moore * one clears the status, and writing a zero preserves the status. 2828636f8d2SBob Moore * Therefore, we must always write zero to the ignored bit. 2838636f8d2SBob Moore * 2848636f8d2SBob Moore * This behavior is clarified in the ACPI 4.0 specification. 2858636f8d2SBob Moore */ 2868636f8d2SBob Moore value &= ~ACPI_PM1_STATUS_PRESERVED_BITS; 28795b482a8SLen Brown 288c520abadSBob Moore status = acpi_hw_write_multiple(value, 289c520abadSBob Moore &acpi_gbl_xpm1a_status, 290c520abadSBob Moore &acpi_gbl_xpm1b_status); 29195b482a8SLen Brown break; 29295b482a8SLen Brown 293c520abadSBob Moore case ACPI_REGISTER_PM1_ENABLE: /* PM1 A/B: 16-bit access */ 29495b482a8SLen Brown 295c520abadSBob Moore status = acpi_hw_write_multiple(value, 296c520abadSBob Moore &acpi_gbl_xpm1a_enable, 297c520abadSBob Moore &acpi_gbl_xpm1b_enable); 29895b482a8SLen Brown break; 29995b482a8SLen Brown 300c520abadSBob Moore case ACPI_REGISTER_PM1_CONTROL: /* PM1 A/B: 16-bit access each */ 30195b482a8SLen Brown 30295b482a8SLen Brown /* 30395b482a8SLen Brown * Perform a read first to preserve certain bits (per ACPI spec) 304c520abadSBob Moore * Note: This includes SCI_EN, we never want to change this bit 30595b482a8SLen Brown */ 306c520abadSBob Moore status = acpi_hw_read_multiple(&read_value, 307c520abadSBob Moore &acpi_gbl_FADT. 308c520abadSBob Moore xpm1a_control_block, 309c520abadSBob Moore &acpi_gbl_FADT. 310c520abadSBob Moore xpm1b_control_block); 31195b482a8SLen Brown if (ACPI_FAILURE(status)) { 31295b482a8SLen Brown goto exit; 31395b482a8SLen Brown } 31495b482a8SLen Brown 31595b482a8SLen Brown /* Insert the bits to be preserved */ 31695b482a8SLen Brown 31795b482a8SLen Brown ACPI_INSERT_BITS(value, ACPI_PM1_CONTROL_PRESERVED_BITS, 31895b482a8SLen Brown read_value); 31995b482a8SLen Brown 32095b482a8SLen Brown /* Now we can write the data */ 32195b482a8SLen Brown 322c520abadSBob Moore status = acpi_hw_write_multiple(value, 323c520abadSBob Moore &acpi_gbl_FADT. 324c520abadSBob Moore xpm1a_control_block, 325c520abadSBob Moore &acpi_gbl_FADT. 326c520abadSBob Moore xpm1b_control_block); 32795b482a8SLen Brown break; 32895b482a8SLen Brown 32995b482a8SLen Brown case ACPI_REGISTER_PM2_CONTROL: /* 8-bit access */ 33095b482a8SLen Brown 33120869dcfSBob Moore /* 33220869dcfSBob Moore * For control registers, all reserved bits must be preserved, 33320869dcfSBob Moore * as per the ACPI spec. 33420869dcfSBob Moore */ 33520869dcfSBob Moore status = 33620869dcfSBob Moore acpi_read(&read_value, &acpi_gbl_FADT.xpm2_control_block); 33720869dcfSBob Moore if (ACPI_FAILURE(status)) { 33820869dcfSBob Moore goto exit; 33920869dcfSBob Moore } 34020869dcfSBob Moore 34120869dcfSBob Moore /* Insert the bits to be preserved */ 34220869dcfSBob Moore 34320869dcfSBob Moore ACPI_INSERT_BITS(value, ACPI_PM2_CONTROL_PRESERVED_BITS, 34420869dcfSBob Moore read_value); 34520869dcfSBob Moore 34695b482a8SLen Brown status = acpi_write(value, &acpi_gbl_FADT.xpm2_control_block); 34795b482a8SLen Brown break; 34895b482a8SLen Brown 34995b482a8SLen Brown case ACPI_REGISTER_PM_TIMER: /* 32-bit access */ 35095b482a8SLen Brown 35195b482a8SLen Brown status = acpi_write(value, &acpi_gbl_FADT.xpm_timer_block); 35295b482a8SLen Brown break; 35395b482a8SLen Brown 35495b482a8SLen Brown case ACPI_REGISTER_SMI_COMMAND_BLOCK: /* 8-bit access */ 35595b482a8SLen Brown 35695b482a8SLen Brown /* SMI_CMD is currently always in IO space */ 35795b482a8SLen Brown 35895b482a8SLen Brown status = 3597f071903SBob Moore acpi_hw_write_port(acpi_gbl_FADT.smi_command, value, 8); 36095b482a8SLen Brown break; 36195b482a8SLen Brown 36295b482a8SLen Brown default: 363c520abadSBob Moore ACPI_ERROR((AE_INFO, "Unknown Register ID: %X", register_id)); 36495b482a8SLen Brown status = AE_BAD_PARAMETER; 36595b482a8SLen Brown break; 36695b482a8SLen Brown } 36795b482a8SLen Brown 36895b482a8SLen Brown exit: 36995b482a8SLen Brown return_ACPI_STATUS(status); 37095b482a8SLen Brown } 371c520abadSBob Moore 372c520abadSBob Moore /****************************************************************************** 373c520abadSBob Moore * 374c520abadSBob Moore * FUNCTION: acpi_hw_read_multiple 375c520abadSBob Moore * 376c520abadSBob Moore * PARAMETERS: Value - Where the register value is returned 377c520abadSBob Moore * register_a - First ACPI register (required) 378c520abadSBob Moore * register_b - Second ACPI register (optional) 379c520abadSBob Moore * 380c520abadSBob Moore * RETURN: Status 381c520abadSBob Moore * 382c520abadSBob Moore * DESCRIPTION: Read from the specified two-part ACPI register (such as PM1 A/B) 383c520abadSBob Moore * 384c520abadSBob Moore ******************************************************************************/ 385c520abadSBob Moore 386c520abadSBob Moore static acpi_status 387c520abadSBob Moore acpi_hw_read_multiple(u32 *value, 388c520abadSBob Moore struct acpi_generic_address *register_a, 389c520abadSBob Moore struct acpi_generic_address *register_b) 390c520abadSBob Moore { 391c520abadSBob Moore u32 value_a = 0; 392c520abadSBob Moore u32 value_b = 0; 393c520abadSBob Moore acpi_status status; 394c520abadSBob Moore 395c520abadSBob Moore /* The first register is always required */ 396c520abadSBob Moore 397c520abadSBob Moore status = acpi_read(&value_a, register_a); 398c520abadSBob Moore if (ACPI_FAILURE(status)) { 399c520abadSBob Moore return (status); 400c520abadSBob Moore } 401c520abadSBob Moore 402c520abadSBob Moore /* Second register is optional */ 403c520abadSBob Moore 404c520abadSBob Moore if (register_b->address) { 405c520abadSBob Moore status = acpi_read(&value_b, register_b); 406c520abadSBob Moore if (ACPI_FAILURE(status)) { 407c520abadSBob Moore return (status); 408c520abadSBob Moore } 409c520abadSBob Moore } 410c520abadSBob Moore 411aefc7f9aSBob Moore /* 412aefc7f9aSBob Moore * OR the two return values together. No shifting or masking is necessary, 413aefc7f9aSBob Moore * because of how the PM1 registers are defined in the ACPI specification: 414aefc7f9aSBob Moore * 415aefc7f9aSBob Moore * "Although the bits can be split between the two register blocks (each 416aefc7f9aSBob Moore * register block has a unique pointer within the FADT), the bit positions 417aefc7f9aSBob Moore * are maintained. The register block with unimplemented bits (that is, 418aefc7f9aSBob Moore * those implemented in the other register block) always returns zeros, 419aefc7f9aSBob Moore * and writes have no side effects" 420aefc7f9aSBob Moore */ 421aefc7f9aSBob Moore *value = (value_a | value_b); 422c520abadSBob Moore return (AE_OK); 423c520abadSBob Moore } 424c520abadSBob Moore 425c520abadSBob Moore /****************************************************************************** 426c520abadSBob Moore * 427c520abadSBob Moore * FUNCTION: acpi_hw_write_multiple 428c520abadSBob Moore * 429c520abadSBob Moore * PARAMETERS: Value - The value to write 430c520abadSBob Moore * register_a - First ACPI register (required) 431c520abadSBob Moore * register_b - Second ACPI register (optional) 432c520abadSBob Moore * 433c520abadSBob Moore * RETURN: Status 434c520abadSBob Moore * 435c520abadSBob Moore * DESCRIPTION: Write to the specified two-part ACPI register (such as PM1 A/B) 436c520abadSBob Moore * 437c520abadSBob Moore ******************************************************************************/ 438c520abadSBob Moore 439c520abadSBob Moore static acpi_status 440c520abadSBob Moore acpi_hw_write_multiple(u32 value, 441c520abadSBob Moore struct acpi_generic_address *register_a, 442c520abadSBob Moore struct acpi_generic_address *register_b) 443c520abadSBob Moore { 444c520abadSBob Moore acpi_status status; 445c520abadSBob Moore 446c520abadSBob Moore /* The first register is always required */ 447c520abadSBob Moore 448c520abadSBob Moore status = acpi_write(value, register_a); 449c520abadSBob Moore if (ACPI_FAILURE(status)) { 450c520abadSBob Moore return (status); 451c520abadSBob Moore } 452c520abadSBob Moore 453aefc7f9aSBob Moore /* 454aefc7f9aSBob Moore * Second register is optional 455aefc7f9aSBob Moore * 456aefc7f9aSBob Moore * No bit shifting or clearing is necessary, because of how the PM1 457aefc7f9aSBob Moore * registers are defined in the ACPI specification: 458aefc7f9aSBob Moore * 459aefc7f9aSBob Moore * "Although the bits can be split between the two register blocks (each 460aefc7f9aSBob Moore * register block has a unique pointer within the FADT), the bit positions 461aefc7f9aSBob Moore * are maintained. The register block with unimplemented bits (that is, 462aefc7f9aSBob Moore * those implemented in the other register block) always returns zeros, 463aefc7f9aSBob Moore * and writes have no side effects" 464aefc7f9aSBob Moore */ 465c520abadSBob Moore if (register_b->address) { 466aefc7f9aSBob Moore status = acpi_write(value, register_b); 467c520abadSBob Moore } 468c520abadSBob Moore 469c520abadSBob Moore return (status); 470c520abadSBob Moore } 471