Path: blob/main/sys/contrib/dev/acpica/components/hardware/hwregs.c
48521 views
/*******************************************************************************1*2* Module Name: hwregs - Read/write access functions for the various ACPI3* control and status registers.4*5******************************************************************************/67/******************************************************************************8*9* 1. Copyright Notice10*11* Some or all of this work - Copyright (c) 1999 - 2025, Intel Corp.12* All rights reserved.13*14* 2. License15*16* 2.1. This is your license from Intel Corp. under its intellectual property17* rights. You may have additional license terms from the party that provided18* you this software, covering your right to use that party's intellectual19* property rights.20*21* 2.2. Intel grants, free of charge, to any person ("Licensee") obtaining a22* copy of the source code appearing in this file ("Covered Code") an23* irrevocable, perpetual, worldwide license under Intel's copyrights in the24* base code distributed originally by Intel ("Original Intel Code") to copy,25* make derivatives, distribute, use and display any portion of the Covered26* Code in any form, with the right to sublicense such rights; and27*28* 2.3. Intel grants Licensee a non-exclusive and non-transferable patent29* license (with the right to sublicense), under only those claims of Intel30* patents that are infringed by the Original Intel Code, to make, use, sell,31* offer to sell, and import the Covered Code and derivative works thereof32* solely to the minimum extent necessary to exercise the above copyright33* license, and in no event shall the patent license extend to any additions34* to or modifications of the Original Intel Code. No other license or right35* is granted directly or by implication, estoppel or otherwise;36*37* The above copyright and patent license is granted only if the following38* conditions are met:39*40* 3. Conditions41*42* 3.1. Redistribution of Source with Rights to Further Distribute Source.43* Redistribution of source code of any substantial portion of the Covered44* Code or modification with rights to further distribute source must include45* the above Copyright Notice, the above License, this list of Conditions,46* and the following Disclaimer and Export Compliance provision. In addition,47* Licensee must cause all Covered Code to which Licensee contributes to48* contain a file documenting the changes Licensee made to create that Covered49* Code and the date of any change. Licensee must include in that file the50* documentation of any changes made by any predecessor Licensee. Licensee51* must include a prominent statement that the modification is derived,52* directly or indirectly, from Original Intel Code.53*54* 3.2. Redistribution of Source with no Rights to Further Distribute Source.55* Redistribution of source code of any substantial portion of the Covered56* Code or modification without rights to further distribute source must57* include the following Disclaimer and Export Compliance provision in the58* documentation and/or other materials provided with distribution. In59* addition, Licensee may not authorize further sublicense of source of any60* portion of the Covered Code, and must include terms to the effect that the61* license from Licensee to its licensee is limited to the intellectual62* property embodied in the software Licensee provides to its licensee, and63* not to intellectual property embodied in modifications its licensee may64* make.65*66* 3.3. Redistribution of Executable. Redistribution in executable form of any67* substantial portion of the Covered Code or modification must reproduce the68* above Copyright Notice, and the following Disclaimer and Export Compliance69* provision in the documentation and/or other materials provided with the70* distribution.71*72* 3.4. Intel retains all right, title, and interest in and to the Original73* Intel Code.74*75* 3.5. Neither the name Intel nor any other trademark owned or controlled by76* Intel shall be used in advertising or otherwise to promote the sale, use or77* other dealings in products derived from or relating to the Covered Code78* without prior written authorization from Intel.79*80* 4. Disclaimer and Export Compliance81*82* 4.1. INTEL MAKES NO WARRANTY OF ANY KIND REGARDING ANY SOFTWARE PROVIDED83* HERE. ANY SOFTWARE ORIGINATING FROM INTEL OR DERIVED FROM INTEL SOFTWARE84* IS PROVIDED "AS IS," AND INTEL WILL NOT PROVIDE ANY SUPPORT, ASSISTANCE,85* INSTALLATION, TRAINING OR OTHER SERVICES. INTEL WILL NOT PROVIDE ANY86* UPDATES, ENHANCEMENTS OR EXTENSIONS. INTEL SPECIFICALLY DISCLAIMS ANY87* IMPLIED WARRANTIES OF MERCHANTABILITY, NONINFRINGEMENT AND FITNESS FOR A88* PARTICULAR PURPOSE.89*90* 4.2. IN NO EVENT SHALL INTEL HAVE ANY LIABILITY TO LICENSEE, ITS LICENSEES91* OR ANY OTHER THIRD PARTY, FOR ANY LOST PROFITS, LOST DATA, LOSS OF USE OR92* COSTS OF PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, OR FOR ANY INDIRECT,93* SPECIAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THIS AGREEMENT, UNDER ANY94* CAUSE OF ACTION OR THEORY OF LIABILITY, AND IRRESPECTIVE OF WHETHER INTEL95* HAS ADVANCE NOTICE OF THE POSSIBILITY OF SUCH DAMAGES. THESE LIMITATIONS96* SHALL APPLY NOTWITHSTANDING THE FAILURE OF THE ESSENTIAL PURPOSE OF ANY97* LIMITED REMEDY.98*99* 4.3. Licensee shall not export, either directly or indirectly, any of this100* software or system incorporating such software without first obtaining any101* required license or other approval from the U. S. Department of Commerce or102* any other agency or department of the United States Government. In the103* event Licensee exports any such software from the United States or104* re-exports any such software from a foreign destination, Licensee shall105* ensure that the distribution and export/re-export of the software is in106* compliance with all laws, regulations, orders, or other restrictions of the107* U.S. Export Administration Regulations. Licensee agrees that neither it nor108* any of its subsidiaries will export/re-export any technical data, process,109* software, or service, directly or indirectly, to any country for which the110* United States government or any agency thereof requires an export license,111* other governmental approval, or letter of assurance, without first obtaining112* such license, approval or letter.113*114*****************************************************************************115*116* Alternatively, you may choose to be licensed under the terms of the117* following license:118*119* Redistribution and use in source and binary forms, with or without120* modification, are permitted provided that the following conditions121* are met:122* 1. Redistributions of source code must retain the above copyright123* notice, this list of conditions, and the following disclaimer,124* without modification.125* 2. Redistributions in binary form must reproduce at minimum a disclaimer126* substantially similar to the "NO WARRANTY" disclaimer below127* ("Disclaimer") and any redistribution must be conditioned upon128* including a substantially similar Disclaimer requirement for further129* binary redistribution.130* 3. Neither the names of the above-listed copyright holders nor the names131* of any contributors may be used to endorse or promote products derived132* from this software without specific prior written permission.133*134* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS135* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT136* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR137* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT138* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,139* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT140* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,141* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY142* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT143* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE144* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.145*146* Alternatively, you may choose to be licensed under the terms of the147* GNU General Public License ("GPL") version 2 as published by the Free148* Software Foundation.149*150*****************************************************************************/151152#include <contrib/dev/acpica/include/acpi.h>153#include <contrib/dev/acpica/include/accommon.h>154#include <contrib/dev/acpica/include/acevents.h>155156#define _COMPONENT ACPI_HARDWARE157ACPI_MODULE_NAME ("hwregs")158159160#if (!ACPI_REDUCED_HARDWARE)161162/* Local Prototypes */163164static UINT8165AcpiHwGetAccessBitWidth (166UINT64 Address,167ACPI_GENERIC_ADDRESS *Reg,168UINT8 MaxBitWidth);169170static ACPI_STATUS171AcpiHwReadMultiple (172UINT32 *Value,173ACPI_GENERIC_ADDRESS *RegisterA,174ACPI_GENERIC_ADDRESS *RegisterB);175176static ACPI_STATUS177AcpiHwWriteMultiple (178UINT32 Value,179ACPI_GENERIC_ADDRESS *RegisterA,180ACPI_GENERIC_ADDRESS *RegisterB);181182#endif /* !ACPI_REDUCED_HARDWARE */183184185/******************************************************************************186*187* FUNCTION: AcpiHwGetAccessBitWidth188*189* PARAMETERS: Address - GAS register address190* Reg - GAS register structure191* MaxBitWidth - Max BitWidth supported (32 or 64)192*193* RETURN: Status194*195* DESCRIPTION: Obtain optimal access bit width196*197******************************************************************************/198199static UINT8200AcpiHwGetAccessBitWidth (201UINT64 Address,202ACPI_GENERIC_ADDRESS *Reg,203UINT8 MaxBitWidth)204{205UINT8 AccessBitWidth;206207208/*209* GAS format "register", used by FADT:210* 1. Detected if BitOffset is 0 and BitWidth is 8/16/32/64;211* 2. AccessSize field is ignored and BitWidth field is used for212* determining the boundary of the IO accesses.213* GAS format "region", used by APEI registers:214* 1. Detected if BitOffset is not 0 or BitWidth is not 8/16/32/64;215* 2. AccessSize field is used for determining the boundary of the216* IO accesses;217* 3. BitOffset/BitWidth fields are used to describe the "region".218*219* Note: This algorithm assumes that the "Address" fields should always220* contain aligned values.221*/222if (!Reg->BitOffset && Reg->BitWidth &&223ACPI_IS_POWER_OF_TWO (Reg->BitWidth) &&224ACPI_IS_ALIGNED (Reg->BitWidth, 8))225{226AccessBitWidth = Reg->BitWidth;227}228else if (Reg->AccessWidth)229{230AccessBitWidth = ACPI_ACCESS_BIT_WIDTH (Reg->AccessWidth);231}232else233{234AccessBitWidth = ACPI_ROUND_UP_POWER_OF_TWO_8 (235Reg->BitOffset + Reg->BitWidth);236if (AccessBitWidth <= 8)237{238AccessBitWidth = 8;239}240else241{242while (!ACPI_IS_ALIGNED (Address, AccessBitWidth >> 3))243{244AccessBitWidth >>= 1;245}246}247}248249/* Maximum IO port access bit width is 32 */250251if (Reg->SpaceId == ACPI_ADR_SPACE_SYSTEM_IO)252{253MaxBitWidth = 32;254}255256/*257* Return access width according to the requested maximum access bit width,258* as the caller should know the format of the register and may enforce259* a 32-bit accesses.260*/261if (AccessBitWidth < MaxBitWidth)262{263return (AccessBitWidth);264}265return (MaxBitWidth);266}267268269/******************************************************************************270*271* FUNCTION: AcpiHwValidateRegister272*273* PARAMETERS: Reg - GAS register structure274* MaxBitWidth - Max BitWidth supported (32 or 64)275* Address - Pointer to where the gas->address276* is returned277*278* RETURN: Status279*280* DESCRIPTION: Validate the contents of a GAS register. Checks the GAS281* pointer, Address, SpaceId, BitWidth, and BitOffset.282*283******************************************************************************/284285ACPI_STATUS286AcpiHwValidateRegister (287ACPI_GENERIC_ADDRESS *Reg,288UINT8 MaxBitWidth,289UINT64 *Address)290{291UINT8 BitWidth;292UINT8 AccessWidth;293294295/* Must have a valid pointer to a GAS structure */296297if (!Reg)298{299return (AE_BAD_PARAMETER);300}301302/*303* Copy the target address. This handles possible alignment issues.304* Address must not be null. A null address also indicates an optional305* ACPI register that is not supported, so no error message.306*/307ACPI_MOVE_64_TO_64 (Address, &Reg->Address);308if (!(*Address))309{310return (AE_BAD_ADDRESS);311}312313/* Validate the SpaceID */314315if ((Reg->SpaceId != ACPI_ADR_SPACE_SYSTEM_MEMORY) &&316(Reg->SpaceId != ACPI_ADR_SPACE_SYSTEM_IO))317{318ACPI_ERROR ((AE_INFO,319"Unsupported address space: 0x%X", Reg->SpaceId));320return (AE_SUPPORT);321}322323/* Validate the AccessWidth */324325if (Reg->AccessWidth > 4)326{327ACPI_ERROR ((AE_INFO,328"Unsupported register access width: 0x%X", Reg->AccessWidth));329return (AE_SUPPORT);330}331332/* Validate the BitWidth, convert AccessWidth into number of bits */333334AccessWidth = AcpiHwGetAccessBitWidth (*Address, Reg, MaxBitWidth);335BitWidth = ACPI_ROUND_UP (Reg->BitOffset + Reg->BitWidth, AccessWidth);336if (MaxBitWidth < BitWidth)337{338ACPI_WARNING ((AE_INFO,339"Requested bit width 0x%X is smaller than register bit width 0x%X",340MaxBitWidth, BitWidth));341return (AE_SUPPORT);342}343344return (AE_OK);345}346347348/******************************************************************************349*350* FUNCTION: AcpiHwRead351*352* PARAMETERS: Value - Where the value is returned353* Reg - GAS register structure354*355* RETURN: Status356*357* DESCRIPTION: Read from either memory or IO space. This is a 64-bit max358* version of AcpiRead.359*360* LIMITATIONS: <These limitations also apply to AcpiHwWrite>361* SpaceID must be SystemMemory or SystemIO.362*363******************************************************************************/364365ACPI_STATUS366AcpiHwRead (367UINT64 *Value,368ACPI_GENERIC_ADDRESS *Reg)369{370UINT64 Address;371UINT8 AccessWidth;372UINT32 BitWidth;373UINT8 BitOffset;374UINT64 Value64;375UINT32 Value32;376UINT8 Index;377ACPI_STATUS Status;378379380ACPI_FUNCTION_NAME (HwRead);381382383/* Validate contents of the GAS register */384385Status = AcpiHwValidateRegister (Reg, 64, &Address);386if (ACPI_FAILURE (Status))387{388return (Status);389}390391/*392* Initialize entire 64-bit return value to zero, convert AccessWidth393* into number of bits based394*/395*Value = 0;396AccessWidth = AcpiHwGetAccessBitWidth (Address, Reg, 64);397BitWidth = Reg->BitOffset + Reg->BitWidth;398BitOffset = Reg->BitOffset;399400/*401* Two address spaces supported: Memory or IO. PCI_Config is402* not supported here because the GAS structure is insufficient403*/404Index = 0;405while (BitWidth)406{407if (BitOffset >= AccessWidth)408{409Value64 = 0;410BitOffset -= AccessWidth;411}412else413{414if (Reg->SpaceId == ACPI_ADR_SPACE_SYSTEM_MEMORY)415{416Status = AcpiOsReadMemory ((ACPI_PHYSICAL_ADDRESS)417Address + Index * ACPI_DIV_8 (AccessWidth),418&Value64, AccessWidth);419}420else /* ACPI_ADR_SPACE_SYSTEM_IO, validated earlier */421{422Status = AcpiHwReadPort ((ACPI_IO_ADDRESS)423Address + Index * ACPI_DIV_8 (AccessWidth),424&Value32, AccessWidth);425Value64 = (UINT64) Value32;426}427}428429/*430* Use offset style bit writes because "Index * AccessWidth" is431* ensured to be less than 64-bits by AcpiHwValidateRegister().432*/433ACPI_SET_BITS (Value, Index * AccessWidth,434ACPI_MASK_BITS_ABOVE_64 (AccessWidth), Value64);435436BitWidth -= BitWidth > AccessWidth ? AccessWidth : BitWidth;437Index++;438}439440ACPI_DEBUG_PRINT ((ACPI_DB_IO,441"Read: %8.8X%8.8X width %2d from %8.8X%8.8X (%s)\n",442ACPI_FORMAT_UINT64 (*Value), AccessWidth,443ACPI_FORMAT_UINT64 (Address), AcpiUtGetRegionName (Reg->SpaceId)));444445return (Status);446}447448449/******************************************************************************450*451* FUNCTION: AcpiHwWrite452*453* PARAMETERS: Value - Value to be written454* Reg - GAS register structure455*456* RETURN: Status457*458* DESCRIPTION: Write to either memory or IO space. This is a 64-bit max459* version of AcpiWrite.460*461******************************************************************************/462463ACPI_STATUS464AcpiHwWrite (465UINT64 Value,466ACPI_GENERIC_ADDRESS *Reg)467{468UINT64 Address;469UINT8 AccessWidth;470UINT32 BitWidth;471UINT8 BitOffset;472UINT64 Value64;473UINT8 Index;474ACPI_STATUS Status;475476477ACPI_FUNCTION_NAME (HwWrite);478479480/* Validate contents of the GAS register */481482Status = AcpiHwValidateRegister (Reg, 64, &Address);483if (ACPI_FAILURE (Status))484{485return (Status);486}487488/* Convert AccessWidth into number of bits based */489490AccessWidth = AcpiHwGetAccessBitWidth (Address, Reg, 64);491BitWidth = Reg->BitOffset + Reg->BitWidth;492BitOffset = Reg->BitOffset;493494/*495* Two address spaces supported: Memory or IO. PCI_Config is496* not supported here because the GAS structure is insufficient497*/498Index = 0;499while (BitWidth)500{501/*502* Use offset style bit reads because "Index * AccessWidth" is503* ensured to be less than 64-bits by AcpiHwValidateRegister().504*/505Value64 = ACPI_GET_BITS (&Value, Index * AccessWidth,506ACPI_MASK_BITS_ABOVE_64 (AccessWidth));507508if (BitOffset >= AccessWidth)509{510BitOffset -= AccessWidth;511}512else513{514if (Reg->SpaceId == ACPI_ADR_SPACE_SYSTEM_MEMORY)515{516Status = AcpiOsWriteMemory ((ACPI_PHYSICAL_ADDRESS)517Address + Index * ACPI_DIV_8 (AccessWidth),518Value64, AccessWidth);519}520else /* ACPI_ADR_SPACE_SYSTEM_IO, validated earlier */521{522Status = AcpiHwWritePort ((ACPI_IO_ADDRESS)523Address + Index * ACPI_DIV_8 (AccessWidth),524(UINT32) Value64, AccessWidth);525}526}527528/*529* Index * AccessWidth is ensured to be less than 32-bits by530* AcpiHwValidateRegister().531*/532BitWidth -= BitWidth > AccessWidth ? AccessWidth : BitWidth;533Index++;534}535536ACPI_DEBUG_PRINT ((ACPI_DB_IO,537"Wrote: %8.8X%8.8X width %2d to %8.8X%8.8X (%s)\n",538ACPI_FORMAT_UINT64 (Value), AccessWidth,539ACPI_FORMAT_UINT64 (Address), AcpiUtGetRegionName (Reg->SpaceId)));540541return (Status);542}543544545#if (!ACPI_REDUCED_HARDWARE)546/*******************************************************************************547*548* FUNCTION: AcpiHwClearAcpiStatus549*550* PARAMETERS: None551*552* RETURN: Status553*554* DESCRIPTION: Clears all fixed and general purpose status bits555*556******************************************************************************/557558ACPI_STATUS559AcpiHwClearAcpiStatus (560void)561{562ACPI_STATUS Status;563ACPI_CPU_FLAGS LockFlags = 0;564565566ACPI_FUNCTION_TRACE (HwClearAcpiStatus);567568569ACPI_DEBUG_PRINT ((ACPI_DB_IO, "About to write %04X to %8.8X%8.8X\n",570ACPI_BITMASK_ALL_FIXED_STATUS,571ACPI_FORMAT_UINT64 (AcpiGbl_XPm1aStatus.Address)));572573LockFlags = AcpiOsAcquireLock (AcpiGbl_HardwareLock);574575/* Clear the fixed events in PM1 A/B */576577Status = AcpiHwRegisterWrite (ACPI_REGISTER_PM1_STATUS,578ACPI_BITMASK_ALL_FIXED_STATUS);579580AcpiOsReleaseLock (AcpiGbl_HardwareLock, LockFlags);581582if (ACPI_FAILURE (Status))583{584goto Exit;585}586587/* Clear the GPE Bits in all GPE registers in all GPE blocks */588589Status = AcpiEvWalkGpeList (AcpiHwClearGpeBlock, NULL);590591Exit:592return_ACPI_STATUS (Status);593}594595596/*******************************************************************************597*598* FUNCTION: AcpiHwGetBitRegisterInfo599*600* PARAMETERS: RegisterId - Index of ACPI Register to access601*602* RETURN: The bitmask to be used when accessing the register603*604* DESCRIPTION: Map RegisterId into a register bitmask.605*606******************************************************************************/607608ACPI_BIT_REGISTER_INFO *609AcpiHwGetBitRegisterInfo (610UINT32 RegisterId)611{612ACPI_FUNCTION_ENTRY ();613614615if (RegisterId > ACPI_BITREG_MAX)616{617ACPI_ERROR ((AE_INFO, "Invalid BitRegister ID: 0x%X", RegisterId));618return (NULL);619}620621return (&AcpiGbl_BitRegisterInfo[RegisterId]);622}623624625/******************************************************************************626*627* FUNCTION: AcpiHwWritePm1Control628*629* PARAMETERS: Pm1aControl - Value to be written to PM1A control630* Pm1bControl - Value to be written to PM1B control631*632* RETURN: Status633*634* DESCRIPTION: Write the PM1 A/B control registers. These registers are635* different than the PM1 A/B status and enable registers636* in that different values can be written to the A/B registers.637* Most notably, the SLP_TYP bits can be different, as per the638* values returned from the _Sx predefined methods.639*640******************************************************************************/641642ACPI_STATUS643AcpiHwWritePm1Control (644UINT32 Pm1aControl,645UINT32 Pm1bControl)646{647ACPI_STATUS Status;648649650ACPI_FUNCTION_TRACE (HwWritePm1Control);651652653Status = AcpiHwWrite (Pm1aControl, &AcpiGbl_FADT.XPm1aControlBlock);654if (ACPI_FAILURE (Status))655{656return_ACPI_STATUS (Status);657}658659if (AcpiGbl_FADT.XPm1bControlBlock.Address)660{661Status = AcpiHwWrite (Pm1bControl, &AcpiGbl_FADT.XPm1bControlBlock);662}663return_ACPI_STATUS (Status);664}665666667/******************************************************************************668*669* FUNCTION: AcpiHwRegisterRead670*671* PARAMETERS: RegisterId - ACPI Register ID672* ReturnValue - Where the register value is returned673*674* RETURN: Status and the value read.675*676* DESCRIPTION: Read from the specified ACPI register677*678******************************************************************************/679680ACPI_STATUS681AcpiHwRegisterRead (682UINT32 RegisterId,683UINT32 *ReturnValue)684{685UINT32 Value = 0;686UINT64 Value64;687ACPI_STATUS Status;688689690ACPI_FUNCTION_TRACE (HwRegisterRead);691692693switch (RegisterId)694{695case ACPI_REGISTER_PM1_STATUS: /* PM1 A/B: 16-bit access each */696697Status = AcpiHwReadMultiple (&Value,698&AcpiGbl_XPm1aStatus,699&AcpiGbl_XPm1bStatus);700break;701702case ACPI_REGISTER_PM1_ENABLE: /* PM1 A/B: 16-bit access each */703704Status = AcpiHwReadMultiple (&Value,705&AcpiGbl_XPm1aEnable,706&AcpiGbl_XPm1bEnable);707break;708709case ACPI_REGISTER_PM1_CONTROL: /* PM1 A/B: 16-bit access each */710711Status = AcpiHwReadMultiple (&Value,712&AcpiGbl_FADT.XPm1aControlBlock,713&AcpiGbl_FADT.XPm1bControlBlock);714715/*716* Zero the write-only bits. From the ACPI specification, "Hardware717* Write-Only Bits": "Upon reads to registers with write-only bits,718* software masks out all write-only bits."719*/720Value &= ~ACPI_PM1_CONTROL_WRITEONLY_BITS;721break;722723case ACPI_REGISTER_PM2_CONTROL: /* 8-bit access */724725Status = AcpiHwRead (&Value64, &AcpiGbl_FADT.XPm2ControlBlock);726if (ACPI_SUCCESS (Status))727{728Value = (UINT32) Value64;729}730break;731732case ACPI_REGISTER_PM_TIMER: /* 32-bit access */733734Status = AcpiHwRead (&Value64, &AcpiGbl_FADT.XPmTimerBlock);735if (ACPI_SUCCESS (Status))736{737Value = (UINT32) Value64;738}739740break;741742case ACPI_REGISTER_SMI_COMMAND_BLOCK: /* 8-bit access */743744Status = AcpiHwReadPort (AcpiGbl_FADT.SmiCommand, &Value, 8);745break;746747default:748749ACPI_ERROR ((AE_INFO, "Unknown Register ID: 0x%X",750RegisterId));751Status = AE_BAD_PARAMETER;752break;753}754755if (ACPI_SUCCESS (Status))756{757*ReturnValue = (UINT32) Value;758}759760return_ACPI_STATUS (Status);761}762763764/******************************************************************************765*766* FUNCTION: AcpiHwRegisterWrite767*768* PARAMETERS: RegisterId - ACPI Register ID769* Value - The value to write770*771* RETURN: Status772*773* DESCRIPTION: Write to the specified ACPI register774*775* NOTE: In accordance with the ACPI specification, this function automatically776* preserves the value of the following bits, meaning that these bits cannot be777* changed via this interface:778*779* PM1_CONTROL[0] = SCI_EN780* PM1_CONTROL[9]781* PM1_STATUS[11]782*783* ACPI References:784* 1) Hardware Ignored Bits: When software writes to a register with ignored785* bit fields, it preserves the ignored bit fields786* 2) SCI_EN: OSPM always preserves this bit position787*788******************************************************************************/789790ACPI_STATUS791AcpiHwRegisterWrite (792UINT32 RegisterId,793UINT32 Value)794{795ACPI_STATUS Status;796UINT32 ReadValue;797UINT64 ReadValue64;798799800ACPI_FUNCTION_TRACE (HwRegisterWrite);801802803switch (RegisterId)804{805case ACPI_REGISTER_PM1_STATUS: /* PM1 A/B: 16-bit access each */806/*807* Handle the "ignored" bit in PM1 Status. According to the ACPI808* specification, ignored bits are to be preserved when writing.809* Normally, this would mean a read/modify/write sequence. However,810* preserving a bit in the status register is different. Writing a811* one clears the status, and writing a zero preserves the status.812* Therefore, we must always write zero to the ignored bit.813*814* This behavior is clarified in the ACPI 4.0 specification.815*/816Value &= ~ACPI_PM1_STATUS_PRESERVED_BITS;817818Status = AcpiHwWriteMultiple (Value,819&AcpiGbl_XPm1aStatus,820&AcpiGbl_XPm1bStatus);821break;822823case ACPI_REGISTER_PM1_ENABLE: /* PM1 A/B: 16-bit access each */824825Status = AcpiHwWriteMultiple (Value,826&AcpiGbl_XPm1aEnable,827&AcpiGbl_XPm1bEnable);828break;829830case ACPI_REGISTER_PM1_CONTROL: /* PM1 A/B: 16-bit access each */831/*832* Perform a read first to preserve certain bits (per ACPI spec)833* Note: This includes SCI_EN, we never want to change this bit834*/835Status = AcpiHwReadMultiple (&ReadValue,836&AcpiGbl_FADT.XPm1aControlBlock,837&AcpiGbl_FADT.XPm1bControlBlock);838if (ACPI_FAILURE (Status))839{840goto Exit;841}842843/* Insert the bits to be preserved */844845ACPI_INSERT_BITS (Value, ACPI_PM1_CONTROL_PRESERVED_BITS, ReadValue);846847/* Now we can write the data */848849Status = AcpiHwWriteMultiple (Value,850&AcpiGbl_FADT.XPm1aControlBlock,851&AcpiGbl_FADT.XPm1bControlBlock);852break;853854case ACPI_REGISTER_PM2_CONTROL: /* 8-bit access */855/*856* For control registers, all reserved bits must be preserved,857* as per the ACPI spec.858*/859Status = AcpiHwRead (&ReadValue64, &AcpiGbl_FADT.XPm2ControlBlock);860if (ACPI_FAILURE (Status))861{862goto Exit;863}864ReadValue = (UINT32) ReadValue64;865866/* Insert the bits to be preserved */867868ACPI_INSERT_BITS (Value, ACPI_PM2_CONTROL_PRESERVED_BITS, ReadValue);869870Status = AcpiHwWrite (Value, &AcpiGbl_FADT.XPm2ControlBlock);871break;872873case ACPI_REGISTER_PM_TIMER: /* 32-bit access */874875Status = AcpiHwWrite (Value, &AcpiGbl_FADT.XPmTimerBlock);876break;877878case ACPI_REGISTER_SMI_COMMAND_BLOCK: /* 8-bit access */879880/* SMI_CMD is currently always in IO space */881882Status = AcpiHwWritePort (AcpiGbl_FADT.SmiCommand, Value, 8);883break;884885default:886887ACPI_ERROR ((AE_INFO, "Unknown Register ID: 0x%X",888RegisterId));889Status = AE_BAD_PARAMETER;890break;891}892893Exit:894return_ACPI_STATUS (Status);895}896897898/******************************************************************************899*900* FUNCTION: AcpiHwReadMultiple901*902* PARAMETERS: Value - Where the register value is returned903* RegisterA - First ACPI register (required)904* RegisterB - Second ACPI register (optional)905*906* RETURN: Status907*908* DESCRIPTION: Read from the specified two-part ACPI register (such as PM1 A/B)909*910******************************************************************************/911912static ACPI_STATUS913AcpiHwReadMultiple (914UINT32 *Value,915ACPI_GENERIC_ADDRESS *RegisterA,916ACPI_GENERIC_ADDRESS *RegisterB)917{918UINT32 ValueA = 0;919UINT32 ValueB = 0;920UINT64 Value64;921ACPI_STATUS Status;922923924/* The first register is always required */925926Status = AcpiHwRead (&Value64, RegisterA);927if (ACPI_FAILURE (Status))928{929return (Status);930}931ValueA = (UINT32) Value64;932933/* Second register is optional */934935if (RegisterB->Address)936{937Status = AcpiHwRead (&Value64, RegisterB);938if (ACPI_FAILURE (Status))939{940return (Status);941}942ValueB = (UINT32) Value64;943}944945/*946* OR the two return values together. No shifting or masking is necessary,947* because of how the PM1 registers are defined in the ACPI specification:948*949* "Although the bits can be split between the two register blocks (each950* register block has a unique pointer within the FADT), the bit positions951* are maintained. The register block with unimplemented bits (that is,952* those implemented in the other register block) always returns zeros,953* and writes have no side effects"954*/955*Value = (ValueA | ValueB);956return (AE_OK);957}958959960/******************************************************************************961*962* FUNCTION: AcpiHwWriteMultiple963*964* PARAMETERS: Value - The value to write965* RegisterA - First ACPI register (required)966* RegisterB - Second ACPI register (optional)967*968* RETURN: Status969*970* DESCRIPTION: Write to the specified two-part ACPI register (such as PM1 A/B)971*972******************************************************************************/973974static ACPI_STATUS975AcpiHwWriteMultiple (976UINT32 Value,977ACPI_GENERIC_ADDRESS *RegisterA,978ACPI_GENERIC_ADDRESS *RegisterB)979{980ACPI_STATUS Status;981982983/* The first register is always required */984985Status = AcpiHwWrite (Value, RegisterA);986if (ACPI_FAILURE (Status))987{988return (Status);989}990991/*992* Second register is optional993*994* No bit shifting or clearing is necessary, because of how the PM1995* registers are defined in the ACPI specification:996*997* "Although the bits can be split between the two register blocks (each998* register block has a unique pointer within the FADT), the bit positions999* are maintained. The register block with unimplemented bits (that is,1000* those implemented in the other register block) always returns zeros,1001* and writes have no side effects"1002*/1003if (RegisterB->Address)1004{1005Status = AcpiHwWrite (Value, RegisterB);1006}10071008return (Status);1009}10101011#endif /* !ACPI_REDUCED_HARDWARE */101210131014