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 /* 1077848130SBob Moore * Copyright (C) 2000 - 2012, 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 5433620c54SBob Moore #if (!ACPI_REDUCED_HARDWARE) 55c520abadSBob Moore /* Local Prototypes */ 56c520abadSBob Moore static acpi_status 57c520abadSBob Moore acpi_hw_read_multiple(u32 *value, 58c520abadSBob Moore struct acpi_generic_address *register_a, 59c520abadSBob Moore struct acpi_generic_address *register_b); 60c520abadSBob Moore 61c520abadSBob Moore static acpi_status 62c520abadSBob Moore acpi_hw_write_multiple(u32 value, 63c520abadSBob Moore struct acpi_generic_address *register_a, 64c520abadSBob Moore struct acpi_generic_address *register_b); 65c520abadSBob Moore 6633620c54SBob Moore #endif /* !ACPI_REDUCED_HARDWARE */ 6733620c54SBob Moore 68c6b5774cSBob Moore /****************************************************************************** 69c6b5774cSBob Moore * 70c6b5774cSBob Moore * FUNCTION: acpi_hw_validate_register 71c6b5774cSBob Moore * 72ba494beeSBob Moore * PARAMETERS: reg - GAS register structure 73c6b5774cSBob Moore * max_bit_width - Max bit_width supported (32 or 64) 74ba494beeSBob Moore * address - Pointer to where the gas->address 75c6b5774cSBob Moore * is returned 76c6b5774cSBob Moore * 77c6b5774cSBob Moore * RETURN: Status 78c6b5774cSBob Moore * 79c6b5774cSBob Moore * DESCRIPTION: Validate the contents of a GAS register. Checks the GAS 80c6b5774cSBob Moore * pointer, Address, space_id, bit_width, and bit_offset. 81c6b5774cSBob Moore * 82c6b5774cSBob Moore ******************************************************************************/ 83c6b5774cSBob Moore 84c6b5774cSBob Moore acpi_status 85c6b5774cSBob Moore acpi_hw_validate_register(struct acpi_generic_address *reg, 86c6b5774cSBob Moore u8 max_bit_width, u64 *address) 87c6b5774cSBob Moore { 88c6b5774cSBob Moore 89c6b5774cSBob Moore /* Must have a valid pointer to a GAS structure */ 90c6b5774cSBob Moore 91c6b5774cSBob Moore if (!reg) { 92c6b5774cSBob Moore return (AE_BAD_PARAMETER); 93c6b5774cSBob Moore } 94c6b5774cSBob Moore 95c6b5774cSBob Moore /* 96c6b5774cSBob Moore * Copy the target address. This handles possible alignment issues. 97c6b5774cSBob Moore * Address must not be null. A null address also indicates an optional 98c6b5774cSBob Moore * ACPI register that is not supported, so no error message. 99c6b5774cSBob Moore */ 100c6b5774cSBob Moore ACPI_MOVE_64_TO_64(address, ®->address); 101c6b5774cSBob Moore if (!(*address)) { 102c6b5774cSBob Moore return (AE_BAD_ADDRESS); 103c6b5774cSBob Moore } 104c6b5774cSBob Moore 105ba494beeSBob Moore /* Validate the space_ID */ 106c6b5774cSBob Moore 107c6b5774cSBob Moore if ((reg->space_id != ACPI_ADR_SPACE_SYSTEM_MEMORY) && 108c6b5774cSBob Moore (reg->space_id != ACPI_ADR_SPACE_SYSTEM_IO)) { 109c6b5774cSBob Moore ACPI_ERROR((AE_INFO, 110c6b5774cSBob Moore "Unsupported address space: 0x%X", reg->space_id)); 111c6b5774cSBob Moore return (AE_SUPPORT); 112c6b5774cSBob Moore } 113c6b5774cSBob Moore 114c6b5774cSBob Moore /* Validate the bit_width */ 115c6b5774cSBob Moore 116c6b5774cSBob Moore if ((reg->bit_width != 8) && 117c6b5774cSBob Moore (reg->bit_width != 16) && 118c6b5774cSBob Moore (reg->bit_width != 32) && (reg->bit_width != max_bit_width)) { 119c6b5774cSBob Moore ACPI_ERROR((AE_INFO, 120c6b5774cSBob Moore "Unsupported register bit width: 0x%X", 121c6b5774cSBob Moore reg->bit_width)); 122c6b5774cSBob Moore return (AE_SUPPORT); 123c6b5774cSBob Moore } 124c6b5774cSBob Moore 125c6b5774cSBob Moore /* Validate the bit_offset. Just a warning for now. */ 126c6b5774cSBob Moore 127c6b5774cSBob Moore if (reg->bit_offset != 0) { 128c6b5774cSBob Moore ACPI_WARNING((AE_INFO, 129c6b5774cSBob Moore "Unsupported register bit offset: 0x%X", 130c6b5774cSBob Moore reg->bit_offset)); 131c6b5774cSBob Moore } 132c6b5774cSBob Moore 133c6b5774cSBob Moore return (AE_OK); 134c6b5774cSBob Moore } 135c6b5774cSBob Moore 136c6b5774cSBob Moore /****************************************************************************** 137c6b5774cSBob Moore * 138c6b5774cSBob Moore * FUNCTION: acpi_hw_read 139c6b5774cSBob Moore * 140ba494beeSBob Moore * PARAMETERS: value - Where the value is returned 141ba494beeSBob Moore * reg - GAS register structure 142c6b5774cSBob Moore * 143c6b5774cSBob Moore * RETURN: Status 144c6b5774cSBob Moore * 145c6b5774cSBob Moore * DESCRIPTION: Read from either memory or IO space. This is a 32-bit max 146c6b5774cSBob Moore * version of acpi_read, used internally since the overhead of 147c6b5774cSBob Moore * 64-bit values is not needed. 148c6b5774cSBob Moore * 149c6b5774cSBob Moore * LIMITATIONS: <These limitations also apply to acpi_hw_write> 150c6b5774cSBob Moore * bit_width must be exactly 8, 16, or 32. 151ba494beeSBob Moore * space_ID must be system_memory or system_IO. 152c6b5774cSBob Moore * bit_offset and access_width are currently ignored, as there has 153c6b5774cSBob Moore * not been a need to implement these. 154c6b5774cSBob Moore * 155c6b5774cSBob Moore ******************************************************************************/ 156c6b5774cSBob Moore 157c6b5774cSBob Moore acpi_status acpi_hw_read(u32 *value, struct acpi_generic_address *reg) 158c6b5774cSBob Moore { 159c6b5774cSBob Moore u64 address; 160653f4b53SBob Moore u64 value64; 161c6b5774cSBob Moore acpi_status status; 162c6b5774cSBob Moore 163c6b5774cSBob Moore ACPI_FUNCTION_NAME(hw_read); 164c6b5774cSBob Moore 165c6b5774cSBob Moore /* Validate contents of the GAS register */ 166c6b5774cSBob Moore 167c6b5774cSBob Moore status = acpi_hw_validate_register(reg, 32, &address); 168c6b5774cSBob Moore if (ACPI_FAILURE(status)) { 169c6b5774cSBob Moore return (status); 170c6b5774cSBob Moore } 171c6b5774cSBob Moore 172c6b5774cSBob Moore /* Initialize entire 32-bit return value to zero */ 173c6b5774cSBob Moore 174c6b5774cSBob Moore *value = 0; 175c6b5774cSBob Moore 176c6b5774cSBob Moore /* 177c6b5774cSBob Moore * Two address spaces supported: Memory or IO. PCI_Config is 178c6b5774cSBob Moore * not supported here because the GAS structure is insufficient 179c6b5774cSBob Moore */ 180c6b5774cSBob Moore if (reg->space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY) { 181c6b5774cSBob Moore status = acpi_os_read_memory((acpi_physical_address) 182653f4b53SBob Moore address, &value64, reg->bit_width); 183653f4b53SBob Moore 184653f4b53SBob Moore *value = (u32)value64; 185c6b5774cSBob Moore } else { /* ACPI_ADR_SPACE_SYSTEM_IO, validated earlier */ 186c6b5774cSBob Moore 187c6b5774cSBob Moore status = acpi_hw_read_port((acpi_io_address) 188c6b5774cSBob Moore address, value, reg->bit_width); 189c6b5774cSBob Moore } 190c6b5774cSBob Moore 191c6b5774cSBob Moore ACPI_DEBUG_PRINT((ACPI_DB_IO, 192c6b5774cSBob Moore "Read: %8.8X width %2d from %8.8X%8.8X (%s)\n", 193c6b5774cSBob Moore *value, reg->bit_width, ACPI_FORMAT_UINT64(address), 194c6b5774cSBob Moore acpi_ut_get_region_name(reg->space_id))); 195c6b5774cSBob Moore 196c6b5774cSBob Moore return (status); 197c6b5774cSBob Moore } 198c6b5774cSBob Moore 199c6b5774cSBob Moore /****************************************************************************** 200c6b5774cSBob Moore * 201c6b5774cSBob Moore * FUNCTION: acpi_hw_write 202c6b5774cSBob Moore * 203ba494beeSBob Moore * PARAMETERS: value - Value to be written 204ba494beeSBob Moore * reg - GAS register structure 205c6b5774cSBob Moore * 206c6b5774cSBob Moore * RETURN: Status 207c6b5774cSBob Moore * 208c6b5774cSBob Moore * DESCRIPTION: Write to either memory or IO space. This is a 32-bit max 209c6b5774cSBob Moore * version of acpi_write, used internally since the overhead of 210c6b5774cSBob Moore * 64-bit values is not needed. 211c6b5774cSBob Moore * 212c6b5774cSBob Moore ******************************************************************************/ 213c6b5774cSBob Moore 214c6b5774cSBob Moore acpi_status acpi_hw_write(u32 value, struct acpi_generic_address *reg) 215c6b5774cSBob Moore { 216c6b5774cSBob Moore u64 address; 217c6b5774cSBob Moore acpi_status status; 218c6b5774cSBob Moore 219c6b5774cSBob Moore ACPI_FUNCTION_NAME(hw_write); 220c6b5774cSBob Moore 221c6b5774cSBob Moore /* Validate contents of the GAS register */ 222c6b5774cSBob Moore 223c6b5774cSBob Moore status = acpi_hw_validate_register(reg, 32, &address); 224c6b5774cSBob Moore if (ACPI_FAILURE(status)) { 225c6b5774cSBob Moore return (status); 226c6b5774cSBob Moore } 227c6b5774cSBob Moore 228c6b5774cSBob Moore /* 229c6b5774cSBob Moore * Two address spaces supported: Memory or IO. PCI_Config is 230c6b5774cSBob Moore * not supported here because the GAS structure is insufficient 231c6b5774cSBob Moore */ 232c6b5774cSBob Moore if (reg->space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY) { 233c6b5774cSBob Moore status = acpi_os_write_memory((acpi_physical_address) 234653f4b53SBob Moore address, (u64)value, 235653f4b53SBob Moore reg->bit_width); 236c6b5774cSBob Moore } else { /* ACPI_ADR_SPACE_SYSTEM_IO, validated earlier */ 237c6b5774cSBob Moore 238c6b5774cSBob Moore status = acpi_hw_write_port((acpi_io_address) 239c6b5774cSBob Moore address, value, reg->bit_width); 240c6b5774cSBob Moore } 241c6b5774cSBob Moore 242c6b5774cSBob Moore ACPI_DEBUG_PRINT((ACPI_DB_IO, 243c6b5774cSBob Moore "Wrote: %8.8X width %2d to %8.8X%8.8X (%s)\n", 244c6b5774cSBob Moore value, reg->bit_width, ACPI_FORMAT_UINT64(address), 245c6b5774cSBob Moore acpi_ut_get_region_name(reg->space_id))); 246c6b5774cSBob Moore 247c6b5774cSBob Moore return (status); 248c6b5774cSBob Moore } 249c6b5774cSBob Moore 25033620c54SBob Moore #if (!ACPI_REDUCED_HARDWARE) 25195b482a8SLen Brown /******************************************************************************* 25295b482a8SLen Brown * 25395b482a8SLen Brown * FUNCTION: acpi_hw_clear_acpi_status 25495b482a8SLen Brown * 25595b482a8SLen Brown * PARAMETERS: None 25695b482a8SLen Brown * 25795b482a8SLen Brown * RETURN: Status 25895b482a8SLen Brown * 25995b482a8SLen Brown * DESCRIPTION: Clears all fixed and general purpose status bits 26095b482a8SLen Brown * 26195b482a8SLen Brown ******************************************************************************/ 262c520abadSBob Moore 26395b482a8SLen Brown acpi_status acpi_hw_clear_acpi_status(void) 26495b482a8SLen Brown { 26595b482a8SLen Brown acpi_status status; 26695b482a8SLen Brown acpi_cpu_flags lock_flags = 0; 26795b482a8SLen Brown 26895b482a8SLen Brown ACPI_FUNCTION_TRACE(hw_clear_acpi_status); 26995b482a8SLen Brown 2708eb7b247SBob Moore ACPI_DEBUG_PRINT((ACPI_DB_IO, "About to write %04X to %8.8X%8.8X\n", 27195b482a8SLen Brown ACPI_BITMASK_ALL_FIXED_STATUS, 2728eb7b247SBob Moore ACPI_FORMAT_UINT64(acpi_gbl_xpm1a_status.address))); 27395b482a8SLen Brown 27495b482a8SLen Brown lock_flags = acpi_os_acquire_lock(acpi_gbl_hardware_lock); 27595b482a8SLen Brown 276227243a0SBob Moore /* Clear the fixed events in PM1 A/B */ 277531c633dSBob Moore 27895b482a8SLen Brown status = acpi_hw_register_write(ACPI_REGISTER_PM1_STATUS, 27995b482a8SLen Brown ACPI_BITMASK_ALL_FIXED_STATUS); 280f7f71cfbSRakib Mullick 281f7f71cfbSRakib Mullick acpi_os_release_lock(acpi_gbl_hardware_lock, lock_flags); 282f7f71cfbSRakib Mullick 283f7f71cfbSRakib Mullick if (ACPI_FAILURE(status)) 284f7f71cfbSRakib Mullick goto exit; 28595b482a8SLen Brown 28695b482a8SLen Brown /* Clear the GPE Bits in all GPE registers in all GPE blocks */ 28795b482a8SLen Brown 28895b482a8SLen Brown status = acpi_ev_walk_gpe_list(acpi_hw_clear_gpe_block, NULL); 28995b482a8SLen Brown 290f7f71cfbSRakib Mullick exit: 29195b482a8SLen Brown return_ACPI_STATUS(status); 29295b482a8SLen Brown } 29395b482a8SLen Brown 29495b482a8SLen Brown /******************************************************************************* 29595b482a8SLen Brown * 29633620c54SBob Moore * FUNCTION: acpi_hw_get_bit_register_info 29795b482a8SLen Brown * 29895b482a8SLen Brown * PARAMETERS: register_id - Index of ACPI Register to access 29995b482a8SLen Brown * 30095b482a8SLen Brown * RETURN: The bitmask to be used when accessing the register 30195b482a8SLen Brown * 30295b482a8SLen Brown * DESCRIPTION: Map register_id into a register bitmask. 30395b482a8SLen Brown * 30495b482a8SLen Brown ******************************************************************************/ 30595b482a8SLen Brown 30695b482a8SLen Brown struct acpi_bit_register_info *acpi_hw_get_bit_register_info(u32 register_id) 30795b482a8SLen Brown { 30895b482a8SLen Brown ACPI_FUNCTION_ENTRY(); 30995b482a8SLen Brown 31095b482a8SLen Brown if (register_id > ACPI_BITREG_MAX) { 311f6a22b0bSBob Moore ACPI_ERROR((AE_INFO, "Invalid BitRegister ID: 0x%X", 31295b482a8SLen Brown register_id)); 31395b482a8SLen Brown return (NULL); 31495b482a8SLen Brown } 31595b482a8SLen Brown 31695b482a8SLen Brown return (&acpi_gbl_bit_register_info[register_id]); 31795b482a8SLen Brown } 31895b482a8SLen Brown 31995b482a8SLen Brown /****************************************************************************** 32095b482a8SLen Brown * 32132c9ef99SBob Moore * FUNCTION: acpi_hw_write_pm1_control 32232c9ef99SBob Moore * 32332c9ef99SBob Moore * PARAMETERS: pm1a_control - Value to be written to PM1A control 32432c9ef99SBob Moore * pm1b_control - Value to be written to PM1B control 32532c9ef99SBob Moore * 32632c9ef99SBob Moore * RETURN: Status 32732c9ef99SBob Moore * 32832c9ef99SBob Moore * DESCRIPTION: Write the PM1 A/B control registers. These registers are 32932c9ef99SBob Moore * different than than the PM1 A/B status and enable registers 33032c9ef99SBob Moore * in that different values can be written to the A/B registers. 33132c9ef99SBob Moore * Most notably, the SLP_TYP bits can be different, as per the 33232c9ef99SBob Moore * values returned from the _Sx predefined methods. 33332c9ef99SBob Moore * 33432c9ef99SBob Moore ******************************************************************************/ 33532c9ef99SBob Moore 33632c9ef99SBob Moore acpi_status acpi_hw_write_pm1_control(u32 pm1a_control, u32 pm1b_control) 33732c9ef99SBob Moore { 33832c9ef99SBob Moore acpi_status status; 33932c9ef99SBob Moore 34032c9ef99SBob Moore ACPI_FUNCTION_TRACE(hw_write_pm1_control); 34132c9ef99SBob Moore 342c6b5774cSBob Moore status = 343c6b5774cSBob Moore acpi_hw_write(pm1a_control, &acpi_gbl_FADT.xpm1a_control_block); 34432c9ef99SBob Moore if (ACPI_FAILURE(status)) { 34532c9ef99SBob Moore return_ACPI_STATUS(status); 34632c9ef99SBob Moore } 34732c9ef99SBob Moore 34832c9ef99SBob Moore if (acpi_gbl_FADT.xpm1b_control_block.address) { 34932c9ef99SBob Moore status = 350c6b5774cSBob Moore acpi_hw_write(pm1b_control, 35132c9ef99SBob Moore &acpi_gbl_FADT.xpm1b_control_block); 35232c9ef99SBob Moore } 35332c9ef99SBob Moore return_ACPI_STATUS(status); 35432c9ef99SBob Moore } 35532c9ef99SBob Moore 35632c9ef99SBob Moore /****************************************************************************** 35732c9ef99SBob Moore * 35895b482a8SLen Brown * FUNCTION: acpi_hw_register_read 35995b482a8SLen Brown * 36095b482a8SLen Brown * PARAMETERS: register_id - ACPI Register ID 36195b482a8SLen Brown * return_value - Where the register value is returned 36295b482a8SLen Brown * 36395b482a8SLen Brown * RETURN: Status and the value read. 36495b482a8SLen Brown * 36595b482a8SLen Brown * DESCRIPTION: Read from the specified ACPI register 36695b482a8SLen Brown * 36795b482a8SLen Brown ******************************************************************************/ 36895b482a8SLen Brown acpi_status 36995b482a8SLen Brown acpi_hw_register_read(u32 register_id, u32 * return_value) 37095b482a8SLen Brown { 371c520abadSBob Moore u32 value = 0; 37295b482a8SLen Brown acpi_status status; 37395b482a8SLen Brown 37495b482a8SLen Brown ACPI_FUNCTION_TRACE(hw_register_read); 37595b482a8SLen Brown 37695b482a8SLen Brown switch (register_id) { 377c520abadSBob Moore case ACPI_REGISTER_PM1_STATUS: /* PM1 A/B: 16-bit access each */ 37895b482a8SLen Brown 379c520abadSBob Moore status = acpi_hw_read_multiple(&value, 380c520abadSBob Moore &acpi_gbl_xpm1a_status, 381c520abadSBob Moore &acpi_gbl_xpm1b_status); 38295b482a8SLen Brown break; 38395b482a8SLen Brown 384c520abadSBob Moore case ACPI_REGISTER_PM1_ENABLE: /* PM1 A/B: 16-bit access each */ 38595b482a8SLen Brown 386c520abadSBob Moore status = acpi_hw_read_multiple(&value, 387c520abadSBob Moore &acpi_gbl_xpm1a_enable, 388c520abadSBob Moore &acpi_gbl_xpm1b_enable); 38995b482a8SLen Brown break; 39095b482a8SLen Brown 391c520abadSBob Moore case ACPI_REGISTER_PM1_CONTROL: /* PM1 A/B: 16-bit access each */ 39295b482a8SLen Brown 393c520abadSBob Moore status = acpi_hw_read_multiple(&value, 394c520abadSBob Moore &acpi_gbl_FADT. 395c520abadSBob Moore xpm1a_control_block, 396c520abadSBob Moore &acpi_gbl_FADT. 397c520abadSBob Moore xpm1b_control_block); 398c3dd25f4SLin Ming 399c3dd25f4SLin Ming /* 400c3dd25f4SLin Ming * Zero the write-only bits. From the ACPI specification, "Hardware 401c3dd25f4SLin Ming * Write-Only Bits": "Upon reads to registers with write-only bits, 402c3dd25f4SLin Ming * software masks out all write-only bits." 403c3dd25f4SLin Ming */ 404c3dd25f4SLin Ming value &= ~ACPI_PM1_CONTROL_WRITEONLY_BITS; 40595b482a8SLen Brown break; 40695b482a8SLen Brown 40795b482a8SLen Brown case ACPI_REGISTER_PM2_CONTROL: /* 8-bit access */ 40895b482a8SLen Brown 409c6b5774cSBob Moore status = 410c6b5774cSBob Moore acpi_hw_read(&value, &acpi_gbl_FADT.xpm2_control_block); 41195b482a8SLen Brown break; 41295b482a8SLen Brown 41395b482a8SLen Brown case ACPI_REGISTER_PM_TIMER: /* 32-bit access */ 41495b482a8SLen Brown 415c6b5774cSBob Moore status = acpi_hw_read(&value, &acpi_gbl_FADT.xpm_timer_block); 41695b482a8SLen Brown break; 41795b482a8SLen Brown 41895b482a8SLen Brown case ACPI_REGISTER_SMI_COMMAND_BLOCK: /* 8-bit access */ 41995b482a8SLen Brown 42095b482a8SLen Brown status = 4217f071903SBob Moore acpi_hw_read_port(acpi_gbl_FADT.smi_command, &value, 8); 42295b482a8SLen Brown break; 42395b482a8SLen Brown 42495b482a8SLen Brown default: 425f6a22b0bSBob Moore ACPI_ERROR((AE_INFO, "Unknown Register ID: 0x%X", register_id)); 42695b482a8SLen Brown status = AE_BAD_PARAMETER; 42795b482a8SLen Brown break; 42895b482a8SLen Brown } 42995b482a8SLen Brown 43095b482a8SLen Brown if (ACPI_SUCCESS(status)) { 431c520abadSBob Moore *return_value = value; 43295b482a8SLen Brown } 43395b482a8SLen Brown 43495b482a8SLen Brown return_ACPI_STATUS(status); 43595b482a8SLen Brown } 43695b482a8SLen Brown 43795b482a8SLen Brown /****************************************************************************** 43895b482a8SLen Brown * 43995b482a8SLen Brown * FUNCTION: acpi_hw_register_write 44095b482a8SLen Brown * 44195b482a8SLen Brown * PARAMETERS: register_id - ACPI Register ID 442ba494beeSBob Moore * value - The value to write 44395b482a8SLen Brown * 44495b482a8SLen Brown * RETURN: Status 44595b482a8SLen Brown * 44695b482a8SLen Brown * DESCRIPTION: Write to the specified ACPI register 44795b482a8SLen Brown * 44895b482a8SLen Brown * NOTE: In accordance with the ACPI specification, this function automatically 44995b482a8SLen Brown * preserves the value of the following bits, meaning that these bits cannot be 45095b482a8SLen Brown * changed via this interface: 45195b482a8SLen Brown * 45295b482a8SLen Brown * PM1_CONTROL[0] = SCI_EN 45395b482a8SLen Brown * PM1_CONTROL[9] 45495b482a8SLen Brown * PM1_STATUS[11] 45595b482a8SLen Brown * 45695b482a8SLen Brown * ACPI References: 45795b482a8SLen Brown * 1) Hardware Ignored Bits: When software writes to a register with ignored 45895b482a8SLen Brown * bit fields, it preserves the ignored bit fields 45995b482a8SLen Brown * 2) SCI_EN: OSPM always preserves this bit position 46095b482a8SLen Brown * 46195b482a8SLen Brown ******************************************************************************/ 46295b482a8SLen Brown 46395b482a8SLen Brown acpi_status acpi_hw_register_write(u32 register_id, u32 value) 46495b482a8SLen Brown { 46595b482a8SLen Brown acpi_status status; 46695b482a8SLen Brown u32 read_value; 46795b482a8SLen Brown 46895b482a8SLen Brown ACPI_FUNCTION_TRACE(hw_register_write); 46995b482a8SLen Brown 47095b482a8SLen Brown switch (register_id) { 471c520abadSBob Moore case ACPI_REGISTER_PM1_STATUS: /* PM1 A/B: 16-bit access each */ 4728636f8d2SBob Moore /* 4738636f8d2SBob Moore * Handle the "ignored" bit in PM1 Status. According to the ACPI 4748636f8d2SBob Moore * specification, ignored bits are to be preserved when writing. 4758636f8d2SBob Moore * Normally, this would mean a read/modify/write sequence. However, 4768636f8d2SBob Moore * preserving a bit in the status register is different. Writing a 4778636f8d2SBob Moore * one clears the status, and writing a zero preserves the status. 4788636f8d2SBob Moore * Therefore, we must always write zero to the ignored bit. 4798636f8d2SBob Moore * 4808636f8d2SBob Moore * This behavior is clarified in the ACPI 4.0 specification. 4818636f8d2SBob Moore */ 4828636f8d2SBob Moore value &= ~ACPI_PM1_STATUS_PRESERVED_BITS; 48395b482a8SLen Brown 484c520abadSBob Moore status = acpi_hw_write_multiple(value, 485c520abadSBob Moore &acpi_gbl_xpm1a_status, 486c520abadSBob Moore &acpi_gbl_xpm1b_status); 48795b482a8SLen Brown break; 48895b482a8SLen Brown 489c520abadSBob Moore case ACPI_REGISTER_PM1_ENABLE: /* PM1 A/B: 16-bit access */ 49095b482a8SLen Brown 491c520abadSBob Moore status = acpi_hw_write_multiple(value, 492c520abadSBob Moore &acpi_gbl_xpm1a_enable, 493c520abadSBob Moore &acpi_gbl_xpm1b_enable); 49495b482a8SLen Brown break; 49595b482a8SLen Brown 496c520abadSBob Moore case ACPI_REGISTER_PM1_CONTROL: /* PM1 A/B: 16-bit access each */ 49795b482a8SLen Brown 49895b482a8SLen Brown /* 49995b482a8SLen Brown * Perform a read first to preserve certain bits (per ACPI spec) 500c520abadSBob Moore * Note: This includes SCI_EN, we never want to change this bit 50195b482a8SLen Brown */ 502c520abadSBob Moore status = acpi_hw_read_multiple(&read_value, 503c520abadSBob Moore &acpi_gbl_FADT. 504c520abadSBob Moore xpm1a_control_block, 505c520abadSBob Moore &acpi_gbl_FADT. 506c520abadSBob Moore xpm1b_control_block); 50795b482a8SLen Brown if (ACPI_FAILURE(status)) { 50895b482a8SLen Brown goto exit; 50995b482a8SLen Brown } 51095b482a8SLen Brown 51195b482a8SLen Brown /* Insert the bits to be preserved */ 51295b482a8SLen Brown 51395b482a8SLen Brown ACPI_INSERT_BITS(value, ACPI_PM1_CONTROL_PRESERVED_BITS, 51495b482a8SLen Brown read_value); 51595b482a8SLen Brown 51695b482a8SLen Brown /* Now we can write the data */ 51795b482a8SLen Brown 518c520abadSBob Moore status = acpi_hw_write_multiple(value, 519c520abadSBob Moore &acpi_gbl_FADT. 520c520abadSBob Moore xpm1a_control_block, 521c520abadSBob Moore &acpi_gbl_FADT. 522c520abadSBob Moore xpm1b_control_block); 52395b482a8SLen Brown break; 52495b482a8SLen Brown 52595b482a8SLen Brown case ACPI_REGISTER_PM2_CONTROL: /* 8-bit access */ 52695b482a8SLen Brown 52720869dcfSBob Moore /* 52820869dcfSBob Moore * For control registers, all reserved bits must be preserved, 52920869dcfSBob Moore * as per the ACPI spec. 53020869dcfSBob Moore */ 53120869dcfSBob Moore status = 532c6b5774cSBob Moore acpi_hw_read(&read_value, 533c6b5774cSBob Moore &acpi_gbl_FADT.xpm2_control_block); 53420869dcfSBob Moore if (ACPI_FAILURE(status)) { 53520869dcfSBob Moore goto exit; 53620869dcfSBob Moore } 53720869dcfSBob Moore 53820869dcfSBob Moore /* Insert the bits to be preserved */ 53920869dcfSBob Moore 54020869dcfSBob Moore ACPI_INSERT_BITS(value, ACPI_PM2_CONTROL_PRESERVED_BITS, 54120869dcfSBob Moore read_value); 54220869dcfSBob Moore 543c6b5774cSBob Moore status = 544c6b5774cSBob Moore acpi_hw_write(value, &acpi_gbl_FADT.xpm2_control_block); 54595b482a8SLen Brown break; 54695b482a8SLen Brown 54795b482a8SLen Brown case ACPI_REGISTER_PM_TIMER: /* 32-bit access */ 54895b482a8SLen Brown 549c6b5774cSBob Moore status = acpi_hw_write(value, &acpi_gbl_FADT.xpm_timer_block); 55095b482a8SLen Brown break; 55195b482a8SLen Brown 55295b482a8SLen Brown case ACPI_REGISTER_SMI_COMMAND_BLOCK: /* 8-bit access */ 55395b482a8SLen Brown 55495b482a8SLen Brown /* SMI_CMD is currently always in IO space */ 55595b482a8SLen Brown 55695b482a8SLen Brown status = 5577f071903SBob Moore acpi_hw_write_port(acpi_gbl_FADT.smi_command, value, 8); 55895b482a8SLen Brown break; 55995b482a8SLen Brown 56095b482a8SLen Brown default: 561f6a22b0bSBob Moore ACPI_ERROR((AE_INFO, "Unknown Register ID: 0x%X", register_id)); 56295b482a8SLen Brown status = AE_BAD_PARAMETER; 56395b482a8SLen Brown break; 56495b482a8SLen Brown } 56595b482a8SLen Brown 56695b482a8SLen Brown exit: 56795b482a8SLen Brown return_ACPI_STATUS(status); 56895b482a8SLen Brown } 569c520abadSBob Moore 570c520abadSBob Moore /****************************************************************************** 571c520abadSBob Moore * 572c520abadSBob Moore * FUNCTION: acpi_hw_read_multiple 573c520abadSBob Moore * 574ba494beeSBob Moore * PARAMETERS: value - Where the register value is returned 575c520abadSBob Moore * register_a - First ACPI register (required) 576c520abadSBob Moore * register_b - Second ACPI register (optional) 577c520abadSBob Moore * 578c520abadSBob Moore * RETURN: Status 579c520abadSBob Moore * 580c520abadSBob Moore * DESCRIPTION: Read from the specified two-part ACPI register (such as PM1 A/B) 581c520abadSBob Moore * 582c520abadSBob Moore ******************************************************************************/ 583c520abadSBob Moore 584c520abadSBob Moore static acpi_status 585c520abadSBob Moore acpi_hw_read_multiple(u32 *value, 586c520abadSBob Moore struct acpi_generic_address *register_a, 587c520abadSBob Moore struct acpi_generic_address *register_b) 588c520abadSBob Moore { 589c520abadSBob Moore u32 value_a = 0; 590c520abadSBob Moore u32 value_b = 0; 591c520abadSBob Moore acpi_status status; 592c520abadSBob Moore 593c520abadSBob Moore /* The first register is always required */ 594c520abadSBob Moore 595c6b5774cSBob Moore status = acpi_hw_read(&value_a, register_a); 596c520abadSBob Moore if (ACPI_FAILURE(status)) { 597c520abadSBob Moore return (status); 598c520abadSBob Moore } 599c520abadSBob Moore 600c520abadSBob Moore /* Second register is optional */ 601c520abadSBob Moore 602c520abadSBob Moore if (register_b->address) { 603c6b5774cSBob Moore status = acpi_hw_read(&value_b, register_b); 604c520abadSBob Moore if (ACPI_FAILURE(status)) { 605c520abadSBob Moore return (status); 606c520abadSBob Moore } 607c520abadSBob Moore } 608c520abadSBob Moore 609aefc7f9aSBob Moore /* 610aefc7f9aSBob Moore * OR the two return values together. No shifting or masking is necessary, 611aefc7f9aSBob Moore * because of how the PM1 registers are defined in the ACPI specification: 612aefc7f9aSBob Moore * 613aefc7f9aSBob Moore * "Although the bits can be split between the two register blocks (each 614aefc7f9aSBob Moore * register block has a unique pointer within the FADT), the bit positions 615aefc7f9aSBob Moore * are maintained. The register block with unimplemented bits (that is, 616aefc7f9aSBob Moore * those implemented in the other register block) always returns zeros, 617aefc7f9aSBob Moore * and writes have no side effects" 618aefc7f9aSBob Moore */ 619aefc7f9aSBob Moore *value = (value_a | value_b); 620c520abadSBob Moore return (AE_OK); 621c520abadSBob Moore } 622c520abadSBob Moore 623c520abadSBob Moore /****************************************************************************** 624c520abadSBob Moore * 625c520abadSBob Moore * FUNCTION: acpi_hw_write_multiple 626c520abadSBob Moore * 627ba494beeSBob Moore * PARAMETERS: value - The value to write 628c520abadSBob Moore * register_a - First ACPI register (required) 629c520abadSBob Moore * register_b - Second ACPI register (optional) 630c520abadSBob Moore * 631c520abadSBob Moore * RETURN: Status 632c520abadSBob Moore * 633c520abadSBob Moore * DESCRIPTION: Write to the specified two-part ACPI register (such as PM1 A/B) 634c520abadSBob Moore * 635c520abadSBob Moore ******************************************************************************/ 636c520abadSBob Moore 637c520abadSBob Moore static acpi_status 638c520abadSBob Moore acpi_hw_write_multiple(u32 value, 639c520abadSBob Moore struct acpi_generic_address *register_a, 640c520abadSBob Moore struct acpi_generic_address *register_b) 641c520abadSBob Moore { 642c520abadSBob Moore acpi_status status; 643c520abadSBob Moore 644c520abadSBob Moore /* The first register is always required */ 645c520abadSBob Moore 646c6b5774cSBob Moore status = acpi_hw_write(value, register_a); 647c520abadSBob Moore if (ACPI_FAILURE(status)) { 648c520abadSBob Moore return (status); 649c520abadSBob Moore } 650c520abadSBob Moore 651aefc7f9aSBob Moore /* 652aefc7f9aSBob Moore * Second register is optional 653aefc7f9aSBob Moore * 654aefc7f9aSBob Moore * No bit shifting or clearing is necessary, because of how the PM1 655aefc7f9aSBob Moore * registers are defined in the ACPI specification: 656aefc7f9aSBob Moore * 657aefc7f9aSBob Moore * "Although the bits can be split between the two register blocks (each 658aefc7f9aSBob Moore * register block has a unique pointer within the FADT), the bit positions 659aefc7f9aSBob Moore * are maintained. The register block with unimplemented bits (that is, 660aefc7f9aSBob Moore * those implemented in the other register block) always returns zeros, 661aefc7f9aSBob Moore * and writes have no side effects" 662aefc7f9aSBob Moore */ 663c520abadSBob Moore if (register_b->address) { 664c6b5774cSBob Moore status = acpi_hw_write(value, register_b); 665c520abadSBob Moore } 666c520abadSBob Moore 667c520abadSBob Moore return (status); 668c520abadSBob Moore } 66933620c54SBob Moore 67033620c54SBob Moore #endif /* !ACPI_REDUCED_HARDWARE */ 671