10d02842fSSascha Wildner /*******************************************************************************
20d02842fSSascha Wildner *
30d02842fSSascha Wildner * Module Name: hwregs - Read/write access functions for the various ACPI
40d02842fSSascha Wildner * control and status registers.
50d02842fSSascha Wildner *
60d02842fSSascha Wildner ******************************************************************************/
70d02842fSSascha Wildner
8b4315fc7SSascha Wildner /******************************************************************************
9b4315fc7SSascha Wildner *
10b4315fc7SSascha Wildner * 1. Copyright Notice
11b4315fc7SSascha Wildner *
12*383048acSSascha Wildner * Some or all of this work - Copyright (c) 1999 - 2021, Intel Corp.
130d02842fSSascha Wildner * All rights reserved.
140d02842fSSascha Wildner *
15b4315fc7SSascha Wildner * 2. License
16b4315fc7SSascha Wildner *
17b4315fc7SSascha Wildner * 2.1. This is your license from Intel Corp. under its intellectual property
18b4315fc7SSascha Wildner * rights. You may have additional license terms from the party that provided
19b4315fc7SSascha Wildner * you this software, covering your right to use that party's intellectual
20b4315fc7SSascha Wildner * property rights.
21b4315fc7SSascha Wildner *
22b4315fc7SSascha Wildner * 2.2. Intel grants, free of charge, to any person ("Licensee") obtaining a
23b4315fc7SSascha Wildner * copy of the source code appearing in this file ("Covered Code") an
24b4315fc7SSascha Wildner * irrevocable, perpetual, worldwide license under Intel's copyrights in the
25b4315fc7SSascha Wildner * base code distributed originally by Intel ("Original Intel Code") to copy,
26b4315fc7SSascha Wildner * make derivatives, distribute, use and display any portion of the Covered
27b4315fc7SSascha Wildner * Code in any form, with the right to sublicense such rights; and
28b4315fc7SSascha Wildner *
29b4315fc7SSascha Wildner * 2.3. Intel grants Licensee a non-exclusive and non-transferable patent
30b4315fc7SSascha Wildner * license (with the right to sublicense), under only those claims of Intel
31b4315fc7SSascha Wildner * patents that are infringed by the Original Intel Code, to make, use, sell,
32b4315fc7SSascha Wildner * offer to sell, and import the Covered Code and derivative works thereof
33b4315fc7SSascha Wildner * solely to the minimum extent necessary to exercise the above copyright
34b4315fc7SSascha Wildner * license, and in no event shall the patent license extend to any additions
35b4315fc7SSascha Wildner * to or modifications of the Original Intel Code. No other license or right
36b4315fc7SSascha Wildner * is granted directly or by implication, estoppel or otherwise;
37b4315fc7SSascha Wildner *
38b4315fc7SSascha Wildner * The above copyright and patent license is granted only if the following
39b4315fc7SSascha Wildner * conditions are met:
40b4315fc7SSascha Wildner *
41b4315fc7SSascha Wildner * 3. Conditions
42b4315fc7SSascha Wildner *
43b4315fc7SSascha Wildner * 3.1. Redistribution of Source with Rights to Further Distribute Source.
44b4315fc7SSascha Wildner * Redistribution of source code of any substantial portion of the Covered
45b4315fc7SSascha Wildner * Code or modification with rights to further distribute source must include
46b4315fc7SSascha Wildner * the above Copyright Notice, the above License, this list of Conditions,
47b4315fc7SSascha Wildner * and the following Disclaimer and Export Compliance provision. In addition,
48b4315fc7SSascha Wildner * Licensee must cause all Covered Code to which Licensee contributes to
49b4315fc7SSascha Wildner * contain a file documenting the changes Licensee made to create that Covered
50b4315fc7SSascha Wildner * Code and the date of any change. Licensee must include in that file the
51b4315fc7SSascha Wildner * documentation of any changes made by any predecessor Licensee. Licensee
52b4315fc7SSascha Wildner * must include a prominent statement that the modification is derived,
53b4315fc7SSascha Wildner * directly or indirectly, from Original Intel Code.
54b4315fc7SSascha Wildner *
55b4315fc7SSascha Wildner * 3.2. Redistribution of Source with no Rights to Further Distribute Source.
56b4315fc7SSascha Wildner * Redistribution of source code of any substantial portion of the Covered
57b4315fc7SSascha Wildner * Code or modification without rights to further distribute source must
58b4315fc7SSascha Wildner * include the following Disclaimer and Export Compliance provision in the
59b4315fc7SSascha Wildner * documentation and/or other materials provided with distribution. In
60b4315fc7SSascha Wildner * addition, Licensee may not authorize further sublicense of source of any
61b4315fc7SSascha Wildner * portion of the Covered Code, and must include terms to the effect that the
62b4315fc7SSascha Wildner * license from Licensee to its licensee is limited to the intellectual
63b4315fc7SSascha Wildner * property embodied in the software Licensee provides to its licensee, and
64b4315fc7SSascha Wildner * not to intellectual property embodied in modifications its licensee may
65b4315fc7SSascha Wildner * make.
66b4315fc7SSascha Wildner *
67b4315fc7SSascha Wildner * 3.3. Redistribution of Executable. Redistribution in executable form of any
68b4315fc7SSascha Wildner * substantial portion of the Covered Code or modification must reproduce the
69b4315fc7SSascha Wildner * above Copyright Notice, and the following Disclaimer and Export Compliance
70b4315fc7SSascha Wildner * provision in the documentation and/or other materials provided with the
71b4315fc7SSascha Wildner * distribution.
72b4315fc7SSascha Wildner *
73b4315fc7SSascha Wildner * 3.4. Intel retains all right, title, and interest in and to the Original
74b4315fc7SSascha Wildner * Intel Code.
75b4315fc7SSascha Wildner *
76b4315fc7SSascha Wildner * 3.5. Neither the name Intel nor any other trademark owned or controlled by
77b4315fc7SSascha Wildner * Intel shall be used in advertising or otherwise to promote the sale, use or
78b4315fc7SSascha Wildner * other dealings in products derived from or relating to the Covered Code
79b4315fc7SSascha Wildner * without prior written authorization from Intel.
80b4315fc7SSascha Wildner *
81b4315fc7SSascha Wildner * 4. Disclaimer and Export Compliance
82b4315fc7SSascha Wildner *
83b4315fc7SSascha Wildner * 4.1. INTEL MAKES NO WARRANTY OF ANY KIND REGARDING ANY SOFTWARE PROVIDED
84b4315fc7SSascha Wildner * HERE. ANY SOFTWARE ORIGINATING FROM INTEL OR DERIVED FROM INTEL SOFTWARE
85b4315fc7SSascha Wildner * IS PROVIDED "AS IS," AND INTEL WILL NOT PROVIDE ANY SUPPORT, ASSISTANCE,
86b4315fc7SSascha Wildner * INSTALLATION, TRAINING OR OTHER SERVICES. INTEL WILL NOT PROVIDE ANY
87b4315fc7SSascha Wildner * UPDATES, ENHANCEMENTS OR EXTENSIONS. INTEL SPECIFICALLY DISCLAIMS ANY
88b4315fc7SSascha Wildner * IMPLIED WARRANTIES OF MERCHANTABILITY, NONINFRINGEMENT AND FITNESS FOR A
89b4315fc7SSascha Wildner * PARTICULAR PURPOSE.
90b4315fc7SSascha Wildner *
91b4315fc7SSascha Wildner * 4.2. IN NO EVENT SHALL INTEL HAVE ANY LIABILITY TO LICENSEE, ITS LICENSEES
92b4315fc7SSascha Wildner * OR ANY OTHER THIRD PARTY, FOR ANY LOST PROFITS, LOST DATA, LOSS OF USE OR
93b4315fc7SSascha Wildner * COSTS OF PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, OR FOR ANY INDIRECT,
94b4315fc7SSascha Wildner * SPECIAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THIS AGREEMENT, UNDER ANY
95b4315fc7SSascha Wildner * CAUSE OF ACTION OR THEORY OF LIABILITY, AND IRRESPECTIVE OF WHETHER INTEL
96b4315fc7SSascha Wildner * HAS ADVANCE NOTICE OF THE POSSIBILITY OF SUCH DAMAGES. THESE LIMITATIONS
97b4315fc7SSascha Wildner * SHALL APPLY NOTWITHSTANDING THE FAILURE OF THE ESSENTIAL PURPOSE OF ANY
98b4315fc7SSascha Wildner * LIMITED REMEDY.
99b4315fc7SSascha Wildner *
100b4315fc7SSascha Wildner * 4.3. Licensee shall not export, either directly or indirectly, any of this
101b4315fc7SSascha Wildner * software or system incorporating such software without first obtaining any
102b4315fc7SSascha Wildner * required license or other approval from the U. S. Department of Commerce or
103b4315fc7SSascha Wildner * any other agency or department of the United States Government. In the
104b4315fc7SSascha Wildner * event Licensee exports any such software from the United States or
105b4315fc7SSascha Wildner * re-exports any such software from a foreign destination, Licensee shall
106b4315fc7SSascha Wildner * ensure that the distribution and export/re-export of the software is in
107b4315fc7SSascha Wildner * compliance with all laws, regulations, orders, or other restrictions of the
108b4315fc7SSascha Wildner * U.S. Export Administration Regulations. Licensee agrees that neither it nor
109b4315fc7SSascha Wildner * any of its subsidiaries will export/re-export any technical data, process,
110b4315fc7SSascha Wildner * software, or service, directly or indirectly, to any country for which the
111b4315fc7SSascha Wildner * United States government or any agency thereof requires an export license,
112b4315fc7SSascha Wildner * other governmental approval, or letter of assurance, without first obtaining
113b4315fc7SSascha Wildner * such license, approval or letter.
114b4315fc7SSascha Wildner *
115b4315fc7SSascha Wildner *****************************************************************************
116b4315fc7SSascha Wildner *
117b4315fc7SSascha Wildner * Alternatively, you may choose to be licensed under the terms of the
118b4315fc7SSascha Wildner * following license:
119b4315fc7SSascha Wildner *
1200d02842fSSascha Wildner * Redistribution and use in source and binary forms, with or without
1210d02842fSSascha Wildner * modification, are permitted provided that the following conditions
1220d02842fSSascha Wildner * are met:
1230d02842fSSascha Wildner * 1. Redistributions of source code must retain the above copyright
1240d02842fSSascha Wildner * notice, this list of conditions, and the following disclaimer,
1250d02842fSSascha Wildner * without modification.
1260d02842fSSascha Wildner * 2. Redistributions in binary form must reproduce at minimum a disclaimer
1270d02842fSSascha Wildner * substantially similar to the "NO WARRANTY" disclaimer below
1280d02842fSSascha Wildner * ("Disclaimer") and any redistribution must be conditioned upon
1290d02842fSSascha Wildner * including a substantially similar Disclaimer requirement for further
1300d02842fSSascha Wildner * binary redistribution.
1310d02842fSSascha Wildner * 3. Neither the names of the above-listed copyright holders nor the names
1320d02842fSSascha Wildner * of any contributors may be used to endorse or promote products derived
1330d02842fSSascha Wildner * from this software without specific prior written permission.
1340d02842fSSascha Wildner *
135b4315fc7SSascha Wildner * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
136b4315fc7SSascha Wildner * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
137b4315fc7SSascha Wildner * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
138b4315fc7SSascha Wildner * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
139b4315fc7SSascha Wildner * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
140b4315fc7SSascha Wildner * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
141b4315fc7SSascha Wildner * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
142b4315fc7SSascha Wildner * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
143b4315fc7SSascha Wildner * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
144b4315fc7SSascha Wildner * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
145b4315fc7SSascha Wildner * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
146b4315fc7SSascha Wildner *
147b4315fc7SSascha Wildner * Alternatively, you may choose to be licensed under the terms of the
1480d02842fSSascha Wildner * GNU General Public License ("GPL") version 2 as published by the Free
1490d02842fSSascha Wildner * Software Foundation.
1500d02842fSSascha Wildner *
151b4315fc7SSascha Wildner *****************************************************************************/
1520d02842fSSascha Wildner
1530d02842fSSascha Wildner #include "acpi.h"
1540d02842fSSascha Wildner #include "accommon.h"
1550d02842fSSascha Wildner #include "acevents.h"
1560d02842fSSascha Wildner
1570d02842fSSascha Wildner #define _COMPONENT ACPI_HARDWARE
1580d02842fSSascha Wildner ACPI_MODULE_NAME ("hwregs")
1590d02842fSSascha Wildner
1600d02842fSSascha Wildner
1610d02842fSSascha Wildner #if (!ACPI_REDUCED_HARDWARE)
1620d02842fSSascha Wildner
1630d02842fSSascha Wildner /* Local Prototypes */
1640d02842fSSascha Wildner
16538b5d46cSSascha Wildner static UINT8
16638b5d46cSSascha Wildner AcpiHwGetAccessBitWidth (
16738b5d46cSSascha Wildner UINT64 Address,
16838b5d46cSSascha Wildner ACPI_GENERIC_ADDRESS *Reg,
16938b5d46cSSascha Wildner UINT8 MaxBitWidth);
17038b5d46cSSascha Wildner
1710d02842fSSascha Wildner static ACPI_STATUS
1720d02842fSSascha Wildner AcpiHwReadMultiple (
1730d02842fSSascha Wildner UINT32 *Value,
1740d02842fSSascha Wildner ACPI_GENERIC_ADDRESS *RegisterA,
1750d02842fSSascha Wildner ACPI_GENERIC_ADDRESS *RegisterB);
1760d02842fSSascha Wildner
1770d02842fSSascha Wildner static ACPI_STATUS
1780d02842fSSascha Wildner AcpiHwWriteMultiple (
1790d02842fSSascha Wildner UINT32 Value,
1800d02842fSSascha Wildner ACPI_GENERIC_ADDRESS *RegisterA,
1810d02842fSSascha Wildner ACPI_GENERIC_ADDRESS *RegisterB);
1820d02842fSSascha Wildner
1830d02842fSSascha Wildner #endif /* !ACPI_REDUCED_HARDWARE */
1840d02842fSSascha Wildner
185820c5b08SSascha Wildner
1860d02842fSSascha Wildner /******************************************************************************
1870d02842fSSascha Wildner *
18838b5d46cSSascha Wildner * FUNCTION: AcpiHwGetAccessBitWidth
18938b5d46cSSascha Wildner *
19038b5d46cSSascha Wildner * PARAMETERS: Address - GAS register address
19138b5d46cSSascha Wildner * Reg - GAS register structure
19238b5d46cSSascha Wildner * MaxBitWidth - Max BitWidth supported (32 or 64)
19338b5d46cSSascha Wildner *
19438b5d46cSSascha Wildner * RETURN: Status
19538b5d46cSSascha Wildner *
19638b5d46cSSascha Wildner * DESCRIPTION: Obtain optimal access bit width
19738b5d46cSSascha Wildner *
19838b5d46cSSascha Wildner ******************************************************************************/
19938b5d46cSSascha Wildner
20038b5d46cSSascha Wildner static UINT8
AcpiHwGetAccessBitWidth(UINT64 Address,ACPI_GENERIC_ADDRESS * Reg,UINT8 MaxBitWidth)20138b5d46cSSascha Wildner AcpiHwGetAccessBitWidth (
20238b5d46cSSascha Wildner UINT64 Address,
20338b5d46cSSascha Wildner ACPI_GENERIC_ADDRESS *Reg,
20438b5d46cSSascha Wildner UINT8 MaxBitWidth)
20538b5d46cSSascha Wildner {
20638b5d46cSSascha Wildner UINT8 AccessBitWidth;
20738b5d46cSSascha Wildner
20838b5d46cSSascha Wildner
20938b5d46cSSascha Wildner /*
21038b5d46cSSascha Wildner * GAS format "register", used by FADT:
21138b5d46cSSascha Wildner * 1. Detected if BitOffset is 0 and BitWidth is 8/16/32/64;
21238b5d46cSSascha Wildner * 2. AccessSize field is ignored and BitWidth field is used for
21338b5d46cSSascha Wildner * determining the boundary of the IO accesses.
21438b5d46cSSascha Wildner * GAS format "region", used by APEI registers:
21538b5d46cSSascha Wildner * 1. Detected if BitOffset is not 0 or BitWidth is not 8/16/32/64;
21638b5d46cSSascha Wildner * 2. AccessSize field is used for determining the boundary of the
21738b5d46cSSascha Wildner * IO accesses;
21838b5d46cSSascha Wildner * 3. BitOffset/BitWidth fields are used to describe the "region".
21938b5d46cSSascha Wildner *
22038b5d46cSSascha Wildner * Note: This algorithm assumes that the "Address" fields should always
22138b5d46cSSascha Wildner * contain aligned values.
22238b5d46cSSascha Wildner */
22338b5d46cSSascha Wildner if (!Reg->BitOffset && Reg->BitWidth &&
22438b5d46cSSascha Wildner ACPI_IS_POWER_OF_TWO (Reg->BitWidth) &&
22538b5d46cSSascha Wildner ACPI_IS_ALIGNED (Reg->BitWidth, 8))
22638b5d46cSSascha Wildner {
22738b5d46cSSascha Wildner AccessBitWidth = Reg->BitWidth;
22838b5d46cSSascha Wildner }
22938b5d46cSSascha Wildner else if (Reg->AccessWidth)
23038b5d46cSSascha Wildner {
2313c639e0cSSascha Wildner AccessBitWidth = ACPI_ACCESS_BIT_WIDTH (Reg->AccessWidth);
23238b5d46cSSascha Wildner }
23338b5d46cSSascha Wildner else
23438b5d46cSSascha Wildner {
23538b5d46cSSascha Wildner AccessBitWidth = ACPI_ROUND_UP_POWER_OF_TWO_8 (
23638b5d46cSSascha Wildner Reg->BitOffset + Reg->BitWidth);
23738b5d46cSSascha Wildner if (AccessBitWidth <= 8)
23838b5d46cSSascha Wildner {
23938b5d46cSSascha Wildner AccessBitWidth = 8;
24038b5d46cSSascha Wildner }
24138b5d46cSSascha Wildner else
24238b5d46cSSascha Wildner {
24338b5d46cSSascha Wildner while (!ACPI_IS_ALIGNED (Address, AccessBitWidth >> 3))
24438b5d46cSSascha Wildner {
24538b5d46cSSascha Wildner AccessBitWidth >>= 1;
24638b5d46cSSascha Wildner }
24738b5d46cSSascha Wildner }
24838b5d46cSSascha Wildner }
24938b5d46cSSascha Wildner
25038b5d46cSSascha Wildner /* Maximum IO port access bit width is 32 */
25138b5d46cSSascha Wildner
25238b5d46cSSascha Wildner if (Reg->SpaceId == ACPI_ADR_SPACE_SYSTEM_IO)
25338b5d46cSSascha Wildner {
25438b5d46cSSascha Wildner MaxBitWidth = 32;
25538b5d46cSSascha Wildner }
25638b5d46cSSascha Wildner
25738b5d46cSSascha Wildner /*
25838b5d46cSSascha Wildner * Return access width according to the requested maximum access bit width,
25938b5d46cSSascha Wildner * as the caller should know the format of the register and may enforce
26038b5d46cSSascha Wildner * a 32-bit accesses.
26138b5d46cSSascha Wildner */
26238b5d46cSSascha Wildner if (AccessBitWidth < MaxBitWidth)
26338b5d46cSSascha Wildner {
26438b5d46cSSascha Wildner return (AccessBitWidth);
26538b5d46cSSascha Wildner }
26638b5d46cSSascha Wildner return (MaxBitWidth);
26738b5d46cSSascha Wildner }
26838b5d46cSSascha Wildner
26938b5d46cSSascha Wildner
27038b5d46cSSascha Wildner /******************************************************************************
27138b5d46cSSascha Wildner *
2720d02842fSSascha Wildner * FUNCTION: AcpiHwValidateRegister
2730d02842fSSascha Wildner *
2740d02842fSSascha Wildner * PARAMETERS: Reg - GAS register structure
2750d02842fSSascha Wildner * MaxBitWidth - Max BitWidth supported (32 or 64)
2760d02842fSSascha Wildner * Address - Pointer to where the gas->address
2770d02842fSSascha Wildner * is returned
2780d02842fSSascha Wildner *
2790d02842fSSascha Wildner * RETURN: Status
2800d02842fSSascha Wildner *
2810d02842fSSascha Wildner * DESCRIPTION: Validate the contents of a GAS register. Checks the GAS
2820d02842fSSascha Wildner * pointer, Address, SpaceId, BitWidth, and BitOffset.
2830d02842fSSascha Wildner *
2840d02842fSSascha Wildner ******************************************************************************/
2850d02842fSSascha Wildner
2860d02842fSSascha Wildner ACPI_STATUS
AcpiHwValidateRegister(ACPI_GENERIC_ADDRESS * Reg,UINT8 MaxBitWidth,UINT64 * Address)2870d02842fSSascha Wildner AcpiHwValidateRegister (
2880d02842fSSascha Wildner ACPI_GENERIC_ADDRESS *Reg,
2890d02842fSSascha Wildner UINT8 MaxBitWidth,
2900d02842fSSascha Wildner UINT64 *Address)
2910d02842fSSascha Wildner {
29238b5d46cSSascha Wildner UINT8 BitWidth;
29338b5d46cSSascha Wildner UINT8 AccessWidth;
29438b5d46cSSascha Wildner
2950d02842fSSascha Wildner
2960d02842fSSascha Wildner /* Must have a valid pointer to a GAS structure */
2970d02842fSSascha Wildner
2980d02842fSSascha Wildner if (!Reg)
2990d02842fSSascha Wildner {
3000d02842fSSascha Wildner return (AE_BAD_PARAMETER);
3010d02842fSSascha Wildner }
3020d02842fSSascha Wildner
3030d02842fSSascha Wildner /*
3040d02842fSSascha Wildner * Copy the target address. This handles possible alignment issues.
3050d02842fSSascha Wildner * Address must not be null. A null address also indicates an optional
3060d02842fSSascha Wildner * ACPI register that is not supported, so no error message.
3070d02842fSSascha Wildner */
3080d02842fSSascha Wildner ACPI_MOVE_64_TO_64 (Address, &Reg->Address);
3090d02842fSSascha Wildner if (!(*Address))
3100d02842fSSascha Wildner {
3110d02842fSSascha Wildner return (AE_BAD_ADDRESS);
3120d02842fSSascha Wildner }
3130d02842fSSascha Wildner
3140d02842fSSascha Wildner /* Validate the SpaceID */
3150d02842fSSascha Wildner
3160d02842fSSascha Wildner if ((Reg->SpaceId != ACPI_ADR_SPACE_SYSTEM_MEMORY) &&
3170d02842fSSascha Wildner (Reg->SpaceId != ACPI_ADR_SPACE_SYSTEM_IO))
3180d02842fSSascha Wildner {
3190d02842fSSascha Wildner ACPI_ERROR ((AE_INFO,
3200d02842fSSascha Wildner "Unsupported address space: 0x%X", Reg->SpaceId));
3210d02842fSSascha Wildner return (AE_SUPPORT);
3220d02842fSSascha Wildner }
3230d02842fSSascha Wildner
32438b5d46cSSascha Wildner /* Validate the AccessWidth */
3250d02842fSSascha Wildner
32638b5d46cSSascha Wildner if (Reg->AccessWidth > 4)
3270d02842fSSascha Wildner {
3280d02842fSSascha Wildner ACPI_ERROR ((AE_INFO,
32938b5d46cSSascha Wildner "Unsupported register access width: 0x%X", Reg->AccessWidth));
3300d02842fSSascha Wildner return (AE_SUPPORT);
3310d02842fSSascha Wildner }
3320d02842fSSascha Wildner
33338b5d46cSSascha Wildner /* Validate the BitWidth, convert AccessWidth into number of bits */
3340d02842fSSascha Wildner
33538b5d46cSSascha Wildner AccessWidth = AcpiHwGetAccessBitWidth (*Address, Reg, MaxBitWidth);
33638b5d46cSSascha Wildner BitWidth = ACPI_ROUND_UP (Reg->BitOffset + Reg->BitWidth, AccessWidth);
33738b5d46cSSascha Wildner if (MaxBitWidth < BitWidth)
3380d02842fSSascha Wildner {
3390d02842fSSascha Wildner ACPI_WARNING ((AE_INFO,
34038b5d46cSSascha Wildner "Requested bit width 0x%X is smaller than register bit width 0x%X",
34138b5d46cSSascha Wildner MaxBitWidth, BitWidth));
34238b5d46cSSascha Wildner return (AE_SUPPORT);
3430d02842fSSascha Wildner }
3440d02842fSSascha Wildner
3450d02842fSSascha Wildner return (AE_OK);
3460d02842fSSascha Wildner }
3470d02842fSSascha Wildner
3480d02842fSSascha Wildner
3490d02842fSSascha Wildner /******************************************************************************
3500d02842fSSascha Wildner *
3510d02842fSSascha Wildner * FUNCTION: AcpiHwRead
3520d02842fSSascha Wildner *
3530d02842fSSascha Wildner * PARAMETERS: Value - Where the value is returned
3540d02842fSSascha Wildner * Reg - GAS register structure
3550d02842fSSascha Wildner *
3560d02842fSSascha Wildner * RETURN: Status
3570d02842fSSascha Wildner *
358cf6b3eb1SSascha Wildner * DESCRIPTION: Read from either memory or IO space. This is a 64-bit max
359cf6b3eb1SSascha Wildner * version of AcpiRead.
3600d02842fSSascha Wildner *
3610d02842fSSascha Wildner * LIMITATIONS: <These limitations also apply to AcpiHwWrite>
3620d02842fSSascha Wildner * SpaceID must be SystemMemory or SystemIO.
3630d02842fSSascha Wildner *
3640d02842fSSascha Wildner ******************************************************************************/
3650d02842fSSascha Wildner
3660d02842fSSascha Wildner ACPI_STATUS
AcpiHwRead(UINT64 * Value,ACPI_GENERIC_ADDRESS * Reg)3670d02842fSSascha Wildner AcpiHwRead (
368cf6b3eb1SSascha Wildner UINT64 *Value,
3690d02842fSSascha Wildner ACPI_GENERIC_ADDRESS *Reg)
3700d02842fSSascha Wildner {
3710d02842fSSascha Wildner UINT64 Address;
37238b5d46cSSascha Wildner UINT8 AccessWidth;
37338b5d46cSSascha Wildner UINT32 BitWidth;
37438b5d46cSSascha Wildner UINT8 BitOffset;
3750d02842fSSascha Wildner UINT64 Value64;
37638b5d46cSSascha Wildner UINT32 Value32;
37738b5d46cSSascha Wildner UINT8 Index;
3780d02842fSSascha Wildner ACPI_STATUS Status;
3790d02842fSSascha Wildner
3800d02842fSSascha Wildner
3810d02842fSSascha Wildner ACPI_FUNCTION_NAME (HwRead);
3820d02842fSSascha Wildner
3830d02842fSSascha Wildner
3840d02842fSSascha Wildner /* Validate contents of the GAS register */
3850d02842fSSascha Wildner
386cf6b3eb1SSascha Wildner Status = AcpiHwValidateRegister (Reg, 64, &Address);
3870d02842fSSascha Wildner if (ACPI_FAILURE (Status))
3880d02842fSSascha Wildner {
3890d02842fSSascha Wildner return (Status);
3900d02842fSSascha Wildner }
3910d02842fSSascha Wildner
39238b5d46cSSascha Wildner /*
393cf6b3eb1SSascha Wildner * Initialize entire 64-bit return value to zero, convert AccessWidth
39438b5d46cSSascha Wildner * into number of bits based
39538b5d46cSSascha Wildner */
3960d02842fSSascha Wildner *Value = 0;
397cf6b3eb1SSascha Wildner AccessWidth = AcpiHwGetAccessBitWidth (Address, Reg, 64);
39838b5d46cSSascha Wildner BitWidth = Reg->BitOffset + Reg->BitWidth;
39938b5d46cSSascha Wildner BitOffset = Reg->BitOffset;
4000d02842fSSascha Wildner
4010d02842fSSascha Wildner /*
4020d02842fSSascha Wildner * Two address spaces supported: Memory or IO. PCI_Config is
4030d02842fSSascha Wildner * not supported here because the GAS structure is insufficient
4040d02842fSSascha Wildner */
40538b5d46cSSascha Wildner Index = 0;
40638b5d46cSSascha Wildner while (BitWidth)
40738b5d46cSSascha Wildner {
40838b5d46cSSascha Wildner if (BitOffset >= AccessWidth)
40938b5d46cSSascha Wildner {
410cf6b3eb1SSascha Wildner Value64 = 0;
41138b5d46cSSascha Wildner BitOffset -= AccessWidth;
41238b5d46cSSascha Wildner }
41338b5d46cSSascha Wildner else
41438b5d46cSSascha Wildner {
4150d02842fSSascha Wildner if (Reg->SpaceId == ACPI_ADR_SPACE_SYSTEM_MEMORY)
4160d02842fSSascha Wildner {
4170d02842fSSascha Wildner Status = AcpiOsReadMemory ((ACPI_PHYSICAL_ADDRESS)
41838b5d46cSSascha Wildner Address + Index * ACPI_DIV_8 (AccessWidth),
41938b5d46cSSascha Wildner &Value64, AccessWidth);
4200d02842fSSascha Wildner }
4210d02842fSSascha Wildner else /* ACPI_ADR_SPACE_SYSTEM_IO, validated earlier */
4220d02842fSSascha Wildner {
4230d02842fSSascha Wildner Status = AcpiHwReadPort ((ACPI_IO_ADDRESS)
42438b5d46cSSascha Wildner Address + Index * ACPI_DIV_8 (AccessWidth),
42538b5d46cSSascha Wildner &Value32, AccessWidth);
426cf6b3eb1SSascha Wildner Value64 = (UINT64) Value32;
42738b5d46cSSascha Wildner }
42838b5d46cSSascha Wildner }
42938b5d46cSSascha Wildner
43038b5d46cSSascha Wildner /*
43138b5d46cSSascha Wildner * Use offset style bit writes because "Index * AccessWidth" is
432cf6b3eb1SSascha Wildner * ensured to be less than 64-bits by AcpiHwValidateRegister().
43338b5d46cSSascha Wildner */
43438b5d46cSSascha Wildner ACPI_SET_BITS (Value, Index * AccessWidth,
435cf6b3eb1SSascha Wildner ACPI_MASK_BITS_ABOVE_64 (AccessWidth), Value64);
43638b5d46cSSascha Wildner
43738b5d46cSSascha Wildner BitWidth -= BitWidth > AccessWidth ? AccessWidth : BitWidth;
43838b5d46cSSascha Wildner Index++;
4390d02842fSSascha Wildner }
4400d02842fSSascha Wildner
4410d02842fSSascha Wildner ACPI_DEBUG_PRINT ((ACPI_DB_IO,
442cf6b3eb1SSascha Wildner "Read: %8.8X%8.8X width %2d from %8.8X%8.8X (%s)\n",
443cf6b3eb1SSascha Wildner ACPI_FORMAT_UINT64 (*Value), AccessWidth,
444cf6b3eb1SSascha Wildner ACPI_FORMAT_UINT64 (Address), AcpiUtGetRegionName (Reg->SpaceId)));
4450d02842fSSascha Wildner
4460d02842fSSascha Wildner return (Status);
4470d02842fSSascha Wildner }
4480d02842fSSascha Wildner
4490d02842fSSascha Wildner
4500d02842fSSascha Wildner /******************************************************************************
4510d02842fSSascha Wildner *
4520d02842fSSascha Wildner * FUNCTION: AcpiHwWrite
4530d02842fSSascha Wildner *
4540d02842fSSascha Wildner * PARAMETERS: Value - Value to be written
4550d02842fSSascha Wildner * Reg - GAS register structure
4560d02842fSSascha Wildner *
4570d02842fSSascha Wildner * RETURN: Status
4580d02842fSSascha Wildner *
459cf6b3eb1SSascha Wildner * DESCRIPTION: Write to either memory or IO space. This is a 64-bit max
460cf6b3eb1SSascha Wildner * version of AcpiWrite.
4610d02842fSSascha Wildner *
4620d02842fSSascha Wildner ******************************************************************************/
4630d02842fSSascha Wildner
4640d02842fSSascha Wildner ACPI_STATUS
AcpiHwWrite(UINT64 Value,ACPI_GENERIC_ADDRESS * Reg)4650d02842fSSascha Wildner AcpiHwWrite (
466cf6b3eb1SSascha Wildner UINT64 Value,
4670d02842fSSascha Wildner ACPI_GENERIC_ADDRESS *Reg)
4680d02842fSSascha Wildner {
4690d02842fSSascha Wildner UINT64 Address;
47038b5d46cSSascha Wildner UINT8 AccessWidth;
47138b5d46cSSascha Wildner UINT32 BitWidth;
47238b5d46cSSascha Wildner UINT8 BitOffset;
47338b5d46cSSascha Wildner UINT64 Value64;
47438b5d46cSSascha Wildner UINT8 Index;
4750d02842fSSascha Wildner ACPI_STATUS Status;
4760d02842fSSascha Wildner
4770d02842fSSascha Wildner
4780d02842fSSascha Wildner ACPI_FUNCTION_NAME (HwWrite);
4790d02842fSSascha Wildner
4800d02842fSSascha Wildner
4810d02842fSSascha Wildner /* Validate contents of the GAS register */
4820d02842fSSascha Wildner
483cf6b3eb1SSascha Wildner Status = AcpiHwValidateRegister (Reg, 64, &Address);
4840d02842fSSascha Wildner if (ACPI_FAILURE (Status))
4850d02842fSSascha Wildner {
4860d02842fSSascha Wildner return (Status);
4870d02842fSSascha Wildner }
4880d02842fSSascha Wildner
48938b5d46cSSascha Wildner /* Convert AccessWidth into number of bits based */
49038b5d46cSSascha Wildner
491cf6b3eb1SSascha Wildner AccessWidth = AcpiHwGetAccessBitWidth (Address, Reg, 64);
49238b5d46cSSascha Wildner BitWidth = Reg->BitOffset + Reg->BitWidth;
49338b5d46cSSascha Wildner BitOffset = Reg->BitOffset;
49438b5d46cSSascha Wildner
4950d02842fSSascha Wildner /*
4960d02842fSSascha Wildner * Two address spaces supported: Memory or IO. PCI_Config is
4970d02842fSSascha Wildner * not supported here because the GAS structure is insufficient
4980d02842fSSascha Wildner */
49938b5d46cSSascha Wildner Index = 0;
50038b5d46cSSascha Wildner while (BitWidth)
50138b5d46cSSascha Wildner {
50238b5d46cSSascha Wildner /*
50338b5d46cSSascha Wildner * Use offset style bit reads because "Index * AccessWidth" is
504cf6b3eb1SSascha Wildner * ensured to be less than 64-bits by AcpiHwValidateRegister().
50538b5d46cSSascha Wildner */
506cf6b3eb1SSascha Wildner Value64 = ACPI_GET_BITS (&Value, Index * AccessWidth,
507cf6b3eb1SSascha Wildner ACPI_MASK_BITS_ABOVE_64 (AccessWidth));
50838b5d46cSSascha Wildner
50938b5d46cSSascha Wildner if (BitOffset >= AccessWidth)
51038b5d46cSSascha Wildner {
51138b5d46cSSascha Wildner BitOffset -= AccessWidth;
51238b5d46cSSascha Wildner }
51338b5d46cSSascha Wildner else
51438b5d46cSSascha Wildner {
5150d02842fSSascha Wildner if (Reg->SpaceId == ACPI_ADR_SPACE_SYSTEM_MEMORY)
5160d02842fSSascha Wildner {
5170d02842fSSascha Wildner Status = AcpiOsWriteMemory ((ACPI_PHYSICAL_ADDRESS)
51838b5d46cSSascha Wildner Address + Index * ACPI_DIV_8 (AccessWidth),
51938b5d46cSSascha Wildner Value64, AccessWidth);
5200d02842fSSascha Wildner }
5210d02842fSSascha Wildner else /* ACPI_ADR_SPACE_SYSTEM_IO, validated earlier */
5220d02842fSSascha Wildner {
5230d02842fSSascha Wildner Status = AcpiHwWritePort ((ACPI_IO_ADDRESS)
52438b5d46cSSascha Wildner Address + Index * ACPI_DIV_8 (AccessWidth),
525cf6b3eb1SSascha Wildner (UINT32) Value64, AccessWidth);
52638b5d46cSSascha Wildner }
52738b5d46cSSascha Wildner }
52838b5d46cSSascha Wildner
52938b5d46cSSascha Wildner /*
53038b5d46cSSascha Wildner * Index * AccessWidth is ensured to be less than 32-bits by
53138b5d46cSSascha Wildner * AcpiHwValidateRegister().
53238b5d46cSSascha Wildner */
53338b5d46cSSascha Wildner BitWidth -= BitWidth > AccessWidth ? AccessWidth : BitWidth;
53438b5d46cSSascha Wildner Index++;
5350d02842fSSascha Wildner }
5360d02842fSSascha Wildner
5370d02842fSSascha Wildner ACPI_DEBUG_PRINT ((ACPI_DB_IO,
538cf6b3eb1SSascha Wildner "Wrote: %8.8X%8.8X width %2d to %8.8X%8.8X (%s)\n",
539cf6b3eb1SSascha Wildner ACPI_FORMAT_UINT64 (Value), AccessWidth,
540cf6b3eb1SSascha Wildner ACPI_FORMAT_UINT64 (Address), AcpiUtGetRegionName (Reg->SpaceId)));
5410d02842fSSascha Wildner
5420d02842fSSascha Wildner return (Status);
5430d02842fSSascha Wildner }
5440d02842fSSascha Wildner
5450d02842fSSascha Wildner
5460d02842fSSascha Wildner #if (!ACPI_REDUCED_HARDWARE)
5470d02842fSSascha Wildner /*******************************************************************************
5480d02842fSSascha Wildner *
5490d02842fSSascha Wildner * FUNCTION: AcpiHwClearAcpiStatus
5500d02842fSSascha Wildner *
5510d02842fSSascha Wildner * PARAMETERS: None
5520d02842fSSascha Wildner *
5530d02842fSSascha Wildner * RETURN: Status
5540d02842fSSascha Wildner *
5550d02842fSSascha Wildner * DESCRIPTION: Clears all fixed and general purpose status bits
5560d02842fSSascha Wildner *
5570d02842fSSascha Wildner ******************************************************************************/
5580d02842fSSascha Wildner
5590d02842fSSascha Wildner ACPI_STATUS
AcpiHwClearAcpiStatus(void)5600d02842fSSascha Wildner AcpiHwClearAcpiStatus (
5610d02842fSSascha Wildner void)
5620d02842fSSascha Wildner {
5630d02842fSSascha Wildner ACPI_STATUS Status;
5640d02842fSSascha Wildner ACPI_CPU_FLAGS LockFlags = 0;
5650d02842fSSascha Wildner
5660d02842fSSascha Wildner
5670d02842fSSascha Wildner ACPI_FUNCTION_TRACE (HwClearAcpiStatus);
5680d02842fSSascha Wildner
5690d02842fSSascha Wildner
5700d02842fSSascha Wildner ACPI_DEBUG_PRINT ((ACPI_DB_IO, "About to write %04X to %8.8X%8.8X\n",
5710d02842fSSascha Wildner ACPI_BITMASK_ALL_FIXED_STATUS,
5720d02842fSSascha Wildner ACPI_FORMAT_UINT64 (AcpiGbl_XPm1aStatus.Address)));
5730d02842fSSascha Wildner
5740d02842fSSascha Wildner LockFlags = AcpiOsAcquireLock (AcpiGbl_HardwareLock);
5750d02842fSSascha Wildner
5760d02842fSSascha Wildner /* Clear the fixed events in PM1 A/B */
5770d02842fSSascha Wildner
5780d02842fSSascha Wildner Status = AcpiHwRegisterWrite (ACPI_REGISTER_PM1_STATUS,
5790d02842fSSascha Wildner ACPI_BITMASK_ALL_FIXED_STATUS);
5805f39c7e7SSascha Wildner
5815f39c7e7SSascha Wildner AcpiOsReleaseLock (AcpiGbl_HardwareLock, LockFlags);
5825f39c7e7SSascha Wildner
5830d02842fSSascha Wildner if (ACPI_FAILURE (Status))
5840d02842fSSascha Wildner {
5855f39c7e7SSascha Wildner goto Exit;
5860d02842fSSascha Wildner }
5870d02842fSSascha Wildner
5880d02842fSSascha Wildner /* Clear the GPE Bits in all GPE registers in all GPE blocks */
5890d02842fSSascha Wildner
5900d02842fSSascha Wildner Status = AcpiEvWalkGpeList (AcpiHwClearGpeBlock, NULL);
5910d02842fSSascha Wildner
5925f39c7e7SSascha Wildner Exit:
5930d02842fSSascha Wildner return_ACPI_STATUS (Status);
5940d02842fSSascha Wildner }
5950d02842fSSascha Wildner
5960d02842fSSascha Wildner
5970d02842fSSascha Wildner /*******************************************************************************
5980d02842fSSascha Wildner *
5990d02842fSSascha Wildner * FUNCTION: AcpiHwGetBitRegisterInfo
6000d02842fSSascha Wildner *
6010d02842fSSascha Wildner * PARAMETERS: RegisterId - Index of ACPI Register to access
6020d02842fSSascha Wildner *
6030d02842fSSascha Wildner * RETURN: The bitmask to be used when accessing the register
6040d02842fSSascha Wildner *
6050d02842fSSascha Wildner * DESCRIPTION: Map RegisterId into a register bitmask.
6060d02842fSSascha Wildner *
6070d02842fSSascha Wildner ******************************************************************************/
6080d02842fSSascha Wildner
6090d02842fSSascha Wildner ACPI_BIT_REGISTER_INFO *
AcpiHwGetBitRegisterInfo(UINT32 RegisterId)6100d02842fSSascha Wildner AcpiHwGetBitRegisterInfo (
6110d02842fSSascha Wildner UINT32 RegisterId)
6120d02842fSSascha Wildner {
6130d02842fSSascha Wildner ACPI_FUNCTION_ENTRY ();
6140d02842fSSascha Wildner
6150d02842fSSascha Wildner
6160d02842fSSascha Wildner if (RegisterId > ACPI_BITREG_MAX)
6170d02842fSSascha Wildner {
6180d02842fSSascha Wildner ACPI_ERROR ((AE_INFO, "Invalid BitRegister ID: 0x%X", RegisterId));
6190d02842fSSascha Wildner return (NULL);
6200d02842fSSascha Wildner }
6210d02842fSSascha Wildner
6220d02842fSSascha Wildner return (&AcpiGbl_BitRegisterInfo[RegisterId]);
6230d02842fSSascha Wildner }
6240d02842fSSascha Wildner
6250d02842fSSascha Wildner
6260d02842fSSascha Wildner /******************************************************************************
6270d02842fSSascha Wildner *
6280d02842fSSascha Wildner * FUNCTION: AcpiHwWritePm1Control
6290d02842fSSascha Wildner *
6300d02842fSSascha Wildner * PARAMETERS: Pm1aControl - Value to be written to PM1A control
6310d02842fSSascha Wildner * Pm1bControl - Value to be written to PM1B control
6320d02842fSSascha Wildner *
6330d02842fSSascha Wildner * RETURN: Status
6340d02842fSSascha Wildner *
6350d02842fSSascha Wildner * DESCRIPTION: Write the PM1 A/B control registers. These registers are
6360d02842fSSascha Wildner * different than than the PM1 A/B status and enable registers
6370d02842fSSascha Wildner * in that different values can be written to the A/B registers.
6380d02842fSSascha Wildner * Most notably, the SLP_TYP bits can be different, as per the
6390d02842fSSascha Wildner * values returned from the _Sx predefined methods.
6400d02842fSSascha Wildner *
6410d02842fSSascha Wildner ******************************************************************************/
6420d02842fSSascha Wildner
6430d02842fSSascha Wildner ACPI_STATUS
AcpiHwWritePm1Control(UINT32 Pm1aControl,UINT32 Pm1bControl)6440d02842fSSascha Wildner AcpiHwWritePm1Control (
6450d02842fSSascha Wildner UINT32 Pm1aControl,
6460d02842fSSascha Wildner UINT32 Pm1bControl)
6470d02842fSSascha Wildner {
6480d02842fSSascha Wildner ACPI_STATUS Status;
6490d02842fSSascha Wildner
6500d02842fSSascha Wildner
6510d02842fSSascha Wildner ACPI_FUNCTION_TRACE (HwWritePm1Control);
6520d02842fSSascha Wildner
6530d02842fSSascha Wildner
6540d02842fSSascha Wildner Status = AcpiHwWrite (Pm1aControl, &AcpiGbl_FADT.XPm1aControlBlock);
6550d02842fSSascha Wildner if (ACPI_FAILURE (Status))
6560d02842fSSascha Wildner {
6570d02842fSSascha Wildner return_ACPI_STATUS (Status);
6580d02842fSSascha Wildner }
6590d02842fSSascha Wildner
6600d02842fSSascha Wildner if (AcpiGbl_FADT.XPm1bControlBlock.Address)
6610d02842fSSascha Wildner {
6620d02842fSSascha Wildner Status = AcpiHwWrite (Pm1bControl, &AcpiGbl_FADT.XPm1bControlBlock);
6630d02842fSSascha Wildner }
6640d02842fSSascha Wildner return_ACPI_STATUS (Status);
6650d02842fSSascha Wildner }
6660d02842fSSascha Wildner
6670d02842fSSascha Wildner
6680d02842fSSascha Wildner /******************************************************************************
6690d02842fSSascha Wildner *
6700d02842fSSascha Wildner * FUNCTION: AcpiHwRegisterRead
6710d02842fSSascha Wildner *
6720d02842fSSascha Wildner * PARAMETERS: RegisterId - ACPI Register ID
6730d02842fSSascha Wildner * ReturnValue - Where the register value is returned
6740d02842fSSascha Wildner *
6750d02842fSSascha Wildner * RETURN: Status and the value read.
6760d02842fSSascha Wildner *
6770d02842fSSascha Wildner * DESCRIPTION: Read from the specified ACPI register
6780d02842fSSascha Wildner *
6790d02842fSSascha Wildner ******************************************************************************/
6800d02842fSSascha Wildner
6810d02842fSSascha Wildner ACPI_STATUS
AcpiHwRegisterRead(UINT32 RegisterId,UINT32 * ReturnValue)6820d02842fSSascha Wildner AcpiHwRegisterRead (
6830d02842fSSascha Wildner UINT32 RegisterId,
6840d02842fSSascha Wildner UINT32 *ReturnValue)
6850d02842fSSascha Wildner {
6860d02842fSSascha Wildner UINT32 Value = 0;
687cf6b3eb1SSascha Wildner UINT64 Value64;
6880d02842fSSascha Wildner ACPI_STATUS Status;
6890d02842fSSascha Wildner
6900d02842fSSascha Wildner
6910d02842fSSascha Wildner ACPI_FUNCTION_TRACE (HwRegisterRead);
6920d02842fSSascha Wildner
6930d02842fSSascha Wildner
6940d02842fSSascha Wildner switch (RegisterId)
6950d02842fSSascha Wildner {
6960d02842fSSascha Wildner case ACPI_REGISTER_PM1_STATUS: /* PM1 A/B: 16-bit access each */
6970d02842fSSascha Wildner
6980d02842fSSascha Wildner Status = AcpiHwReadMultiple (&Value,
6990d02842fSSascha Wildner &AcpiGbl_XPm1aStatus,
7000d02842fSSascha Wildner &AcpiGbl_XPm1bStatus);
7010d02842fSSascha Wildner break;
7020d02842fSSascha Wildner
7030d02842fSSascha Wildner case ACPI_REGISTER_PM1_ENABLE: /* PM1 A/B: 16-bit access each */
7040d02842fSSascha Wildner
7050d02842fSSascha Wildner Status = AcpiHwReadMultiple (&Value,
7060d02842fSSascha Wildner &AcpiGbl_XPm1aEnable,
7070d02842fSSascha Wildner &AcpiGbl_XPm1bEnable);
7080d02842fSSascha Wildner break;
7090d02842fSSascha Wildner
7100d02842fSSascha Wildner case ACPI_REGISTER_PM1_CONTROL: /* PM1 A/B: 16-bit access each */
7110d02842fSSascha Wildner
7120d02842fSSascha Wildner Status = AcpiHwReadMultiple (&Value,
7130d02842fSSascha Wildner &AcpiGbl_FADT.XPm1aControlBlock,
7140d02842fSSascha Wildner &AcpiGbl_FADT.XPm1bControlBlock);
7150d02842fSSascha Wildner
7160d02842fSSascha Wildner /*
7170d02842fSSascha Wildner * Zero the write-only bits. From the ACPI specification, "Hardware
7180d02842fSSascha Wildner * Write-Only Bits": "Upon reads to registers with write-only bits,
7190d02842fSSascha Wildner * software masks out all write-only bits."
7200d02842fSSascha Wildner */
7210d02842fSSascha Wildner Value &= ~ACPI_PM1_CONTROL_WRITEONLY_BITS;
7220d02842fSSascha Wildner break;
7230d02842fSSascha Wildner
7240d02842fSSascha Wildner case ACPI_REGISTER_PM2_CONTROL: /* 8-bit access */
7250d02842fSSascha Wildner
726cf6b3eb1SSascha Wildner Status = AcpiHwRead (&Value64, &AcpiGbl_FADT.XPm2ControlBlock);
7272afeb59bSSascha Wildner if (ACPI_SUCCESS (Status))
7282afeb59bSSascha Wildner {
729cf6b3eb1SSascha Wildner Value = (UINT32) Value64;
7302afeb59bSSascha Wildner }
7310d02842fSSascha Wildner break;
7320d02842fSSascha Wildner
7330d02842fSSascha Wildner case ACPI_REGISTER_PM_TIMER: /* 32-bit access */
7340d02842fSSascha Wildner
735cf6b3eb1SSascha Wildner Status = AcpiHwRead (&Value64, &AcpiGbl_FADT.XPmTimerBlock);
7362afeb59bSSascha Wildner if (ACPI_SUCCESS (Status))
7372afeb59bSSascha Wildner {
738cf6b3eb1SSascha Wildner Value = (UINT32) Value64;
7392afeb59bSSascha Wildner }
7402afeb59bSSascha Wildner
7410d02842fSSascha Wildner break;
7420d02842fSSascha Wildner
7430d02842fSSascha Wildner case ACPI_REGISTER_SMI_COMMAND_BLOCK: /* 8-bit access */
7440d02842fSSascha Wildner
7450d02842fSSascha Wildner Status = AcpiHwReadPort (AcpiGbl_FADT.SmiCommand, &Value, 8);
7460d02842fSSascha Wildner break;
7470d02842fSSascha Wildner
7480d02842fSSascha Wildner default:
7490d02842fSSascha Wildner
7500d02842fSSascha Wildner ACPI_ERROR ((AE_INFO, "Unknown Register ID: 0x%X",
7510d02842fSSascha Wildner RegisterId));
7520d02842fSSascha Wildner Status = AE_BAD_PARAMETER;
7530d02842fSSascha Wildner break;
7540d02842fSSascha Wildner }
7550d02842fSSascha Wildner
7560d02842fSSascha Wildner if (ACPI_SUCCESS (Status))
7570d02842fSSascha Wildner {
758cf6b3eb1SSascha Wildner *ReturnValue = (UINT32) Value;
7590d02842fSSascha Wildner }
7600d02842fSSascha Wildner
7610d02842fSSascha Wildner return_ACPI_STATUS (Status);
7620d02842fSSascha Wildner }
7630d02842fSSascha Wildner
7640d02842fSSascha Wildner
7650d02842fSSascha Wildner /******************************************************************************
7660d02842fSSascha Wildner *
7670d02842fSSascha Wildner * FUNCTION: AcpiHwRegisterWrite
7680d02842fSSascha Wildner *
7690d02842fSSascha Wildner * PARAMETERS: RegisterId - ACPI Register ID
7700d02842fSSascha Wildner * Value - The value to write
7710d02842fSSascha Wildner *
7720d02842fSSascha Wildner * RETURN: Status
7730d02842fSSascha Wildner *
7740d02842fSSascha Wildner * DESCRIPTION: Write to the specified ACPI register
7750d02842fSSascha Wildner *
7760d02842fSSascha Wildner * NOTE: In accordance with the ACPI specification, this function automatically
7770d02842fSSascha Wildner * preserves the value of the following bits, meaning that these bits cannot be
7780d02842fSSascha Wildner * changed via this interface:
7790d02842fSSascha Wildner *
7800d02842fSSascha Wildner * PM1_CONTROL[0] = SCI_EN
7810d02842fSSascha Wildner * PM1_CONTROL[9]
7820d02842fSSascha Wildner * PM1_STATUS[11]
7830d02842fSSascha Wildner *
7840d02842fSSascha Wildner * ACPI References:
7850d02842fSSascha Wildner * 1) Hardware Ignored Bits: When software writes to a register with ignored
7860d02842fSSascha Wildner * bit fields, it preserves the ignored bit fields
7870d02842fSSascha Wildner * 2) SCI_EN: OSPM always preserves this bit position
7880d02842fSSascha Wildner *
7890d02842fSSascha Wildner ******************************************************************************/
7900d02842fSSascha Wildner
7910d02842fSSascha Wildner ACPI_STATUS
AcpiHwRegisterWrite(UINT32 RegisterId,UINT32 Value)7920d02842fSSascha Wildner AcpiHwRegisterWrite (
7930d02842fSSascha Wildner UINT32 RegisterId,
7940d02842fSSascha Wildner UINT32 Value)
7950d02842fSSascha Wildner {
7960d02842fSSascha Wildner ACPI_STATUS Status;
7970d02842fSSascha Wildner UINT32 ReadValue;
798cf6b3eb1SSascha Wildner UINT64 ReadValue64;
7990d02842fSSascha Wildner
8000d02842fSSascha Wildner
8010d02842fSSascha Wildner ACPI_FUNCTION_TRACE (HwRegisterWrite);
8020d02842fSSascha Wildner
8030d02842fSSascha Wildner
8040d02842fSSascha Wildner switch (RegisterId)
8050d02842fSSascha Wildner {
8060d02842fSSascha Wildner case ACPI_REGISTER_PM1_STATUS: /* PM1 A/B: 16-bit access each */
8070d02842fSSascha Wildner /*
8080d02842fSSascha Wildner * Handle the "ignored" bit in PM1 Status. According to the ACPI
8090d02842fSSascha Wildner * specification, ignored bits are to be preserved when writing.
8100d02842fSSascha Wildner * Normally, this would mean a read/modify/write sequence. However,
8110d02842fSSascha Wildner * preserving a bit in the status register is different. Writing a
8120d02842fSSascha Wildner * one clears the status, and writing a zero preserves the status.
8130d02842fSSascha Wildner * Therefore, we must always write zero to the ignored bit.
8140d02842fSSascha Wildner *
8150d02842fSSascha Wildner * This behavior is clarified in the ACPI 4.0 specification.
8160d02842fSSascha Wildner */
8170d02842fSSascha Wildner Value &= ~ACPI_PM1_STATUS_PRESERVED_BITS;
8180d02842fSSascha Wildner
8190d02842fSSascha Wildner Status = AcpiHwWriteMultiple (Value,
8200d02842fSSascha Wildner &AcpiGbl_XPm1aStatus,
8210d02842fSSascha Wildner &AcpiGbl_XPm1bStatus);
8220d02842fSSascha Wildner break;
8230d02842fSSascha Wildner
8240d02842fSSascha Wildner case ACPI_REGISTER_PM1_ENABLE: /* PM1 A/B: 16-bit access each */
8250d02842fSSascha Wildner
8260d02842fSSascha Wildner Status = AcpiHwWriteMultiple (Value,
8270d02842fSSascha Wildner &AcpiGbl_XPm1aEnable,
8280d02842fSSascha Wildner &AcpiGbl_XPm1bEnable);
8290d02842fSSascha Wildner break;
8300d02842fSSascha Wildner
8310d02842fSSascha Wildner case ACPI_REGISTER_PM1_CONTROL: /* PM1 A/B: 16-bit access each */
8320d02842fSSascha Wildner /*
8330d02842fSSascha Wildner * Perform a read first to preserve certain bits (per ACPI spec)
8340d02842fSSascha Wildner * Note: This includes SCI_EN, we never want to change this bit
8350d02842fSSascha Wildner */
8360d02842fSSascha Wildner Status = AcpiHwReadMultiple (&ReadValue,
8370d02842fSSascha Wildner &AcpiGbl_FADT.XPm1aControlBlock,
8380d02842fSSascha Wildner &AcpiGbl_FADT.XPm1bControlBlock);
8390d02842fSSascha Wildner if (ACPI_FAILURE (Status))
8400d02842fSSascha Wildner {
8410d02842fSSascha Wildner goto Exit;
8420d02842fSSascha Wildner }
8430d02842fSSascha Wildner
8440d02842fSSascha Wildner /* Insert the bits to be preserved */
8450d02842fSSascha Wildner
8460d02842fSSascha Wildner ACPI_INSERT_BITS (Value, ACPI_PM1_CONTROL_PRESERVED_BITS, ReadValue);
8470d02842fSSascha Wildner
8480d02842fSSascha Wildner /* Now we can write the data */
8490d02842fSSascha Wildner
8500d02842fSSascha Wildner Status = AcpiHwWriteMultiple (Value,
8510d02842fSSascha Wildner &AcpiGbl_FADT.XPm1aControlBlock,
8520d02842fSSascha Wildner &AcpiGbl_FADT.XPm1bControlBlock);
8530d02842fSSascha Wildner break;
8540d02842fSSascha Wildner
8550d02842fSSascha Wildner case ACPI_REGISTER_PM2_CONTROL: /* 8-bit access */
8560d02842fSSascha Wildner /*
8570d02842fSSascha Wildner * For control registers, all reserved bits must be preserved,
8580d02842fSSascha Wildner * as per the ACPI spec.
8590d02842fSSascha Wildner */
860cf6b3eb1SSascha Wildner Status = AcpiHwRead (&ReadValue64, &AcpiGbl_FADT.XPm2ControlBlock);
8610d02842fSSascha Wildner if (ACPI_FAILURE (Status))
8620d02842fSSascha Wildner {
8630d02842fSSascha Wildner goto Exit;
8640d02842fSSascha Wildner }
865cf6b3eb1SSascha Wildner ReadValue = (UINT32) ReadValue64;
8660d02842fSSascha Wildner
8670d02842fSSascha Wildner /* Insert the bits to be preserved */
8680d02842fSSascha Wildner
8690d02842fSSascha Wildner ACPI_INSERT_BITS (Value, ACPI_PM2_CONTROL_PRESERVED_BITS, ReadValue);
8700d02842fSSascha Wildner
8710d02842fSSascha Wildner Status = AcpiHwWrite (Value, &AcpiGbl_FADT.XPm2ControlBlock);
8720d02842fSSascha Wildner break;
8730d02842fSSascha Wildner
8740d02842fSSascha Wildner case ACPI_REGISTER_PM_TIMER: /* 32-bit access */
8750d02842fSSascha Wildner
8760d02842fSSascha Wildner Status = AcpiHwWrite (Value, &AcpiGbl_FADT.XPmTimerBlock);
8770d02842fSSascha Wildner break;
8780d02842fSSascha Wildner
8790d02842fSSascha Wildner case ACPI_REGISTER_SMI_COMMAND_BLOCK: /* 8-bit access */
8800d02842fSSascha Wildner
8810d02842fSSascha Wildner /* SMI_CMD is currently always in IO space */
8820d02842fSSascha Wildner
8830d02842fSSascha Wildner Status = AcpiHwWritePort (AcpiGbl_FADT.SmiCommand, Value, 8);
8840d02842fSSascha Wildner break;
8850d02842fSSascha Wildner
8860d02842fSSascha Wildner default:
8870d02842fSSascha Wildner
8880d02842fSSascha Wildner ACPI_ERROR ((AE_INFO, "Unknown Register ID: 0x%X",
8890d02842fSSascha Wildner RegisterId));
8900d02842fSSascha Wildner Status = AE_BAD_PARAMETER;
8910d02842fSSascha Wildner break;
8920d02842fSSascha Wildner }
8930d02842fSSascha Wildner
8940d02842fSSascha Wildner Exit:
8950d02842fSSascha Wildner return_ACPI_STATUS (Status);
8960d02842fSSascha Wildner }
8970d02842fSSascha Wildner
8980d02842fSSascha Wildner
8990d02842fSSascha Wildner /******************************************************************************
9000d02842fSSascha Wildner *
9010d02842fSSascha Wildner * FUNCTION: AcpiHwReadMultiple
9020d02842fSSascha Wildner *
9030d02842fSSascha Wildner * PARAMETERS: Value - Where the register value is returned
9040d02842fSSascha Wildner * RegisterA - First ACPI register (required)
9050d02842fSSascha Wildner * RegisterB - Second ACPI register (optional)
9060d02842fSSascha Wildner *
9070d02842fSSascha Wildner * RETURN: Status
9080d02842fSSascha Wildner *
9090d02842fSSascha Wildner * DESCRIPTION: Read from the specified two-part ACPI register (such as PM1 A/B)
9100d02842fSSascha Wildner *
9110d02842fSSascha Wildner ******************************************************************************/
9120d02842fSSascha Wildner
9130d02842fSSascha Wildner static ACPI_STATUS
AcpiHwReadMultiple(UINT32 * Value,ACPI_GENERIC_ADDRESS * RegisterA,ACPI_GENERIC_ADDRESS * RegisterB)9140d02842fSSascha Wildner AcpiHwReadMultiple (
9150d02842fSSascha Wildner UINT32 *Value,
9160d02842fSSascha Wildner ACPI_GENERIC_ADDRESS *RegisterA,
9170d02842fSSascha Wildner ACPI_GENERIC_ADDRESS *RegisterB)
9180d02842fSSascha Wildner {
9190d02842fSSascha Wildner UINT32 ValueA = 0;
9200d02842fSSascha Wildner UINT32 ValueB = 0;
921cf6b3eb1SSascha Wildner UINT64 Value64;
9220d02842fSSascha Wildner ACPI_STATUS Status;
9230d02842fSSascha Wildner
9240d02842fSSascha Wildner
9250d02842fSSascha Wildner /* The first register is always required */
9260d02842fSSascha Wildner
927cf6b3eb1SSascha Wildner Status = AcpiHwRead (&Value64, RegisterA);
9280d02842fSSascha Wildner if (ACPI_FAILURE (Status))
9290d02842fSSascha Wildner {
9300d02842fSSascha Wildner return (Status);
9310d02842fSSascha Wildner }
932cf6b3eb1SSascha Wildner ValueA = (UINT32) Value64;
9330d02842fSSascha Wildner
9340d02842fSSascha Wildner /* Second register is optional */
9350d02842fSSascha Wildner
9360d02842fSSascha Wildner if (RegisterB->Address)
9370d02842fSSascha Wildner {
938cf6b3eb1SSascha Wildner Status = AcpiHwRead (&Value64, RegisterB);
9390d02842fSSascha Wildner if (ACPI_FAILURE (Status))
9400d02842fSSascha Wildner {
9410d02842fSSascha Wildner return (Status);
9420d02842fSSascha Wildner }
943cf6b3eb1SSascha Wildner ValueB = (UINT32) Value64;
9440d02842fSSascha Wildner }
9450d02842fSSascha Wildner
9460d02842fSSascha Wildner /*
9470d02842fSSascha Wildner * OR the two return values together. No shifting or masking is necessary,
9480d02842fSSascha Wildner * because of how the PM1 registers are defined in the ACPI specification:
9490d02842fSSascha Wildner *
9500d02842fSSascha Wildner * "Although the bits can be split between the two register blocks (each
9510d02842fSSascha Wildner * register block has a unique pointer within the FADT), the bit positions
9520d02842fSSascha Wildner * are maintained. The register block with unimplemented bits (that is,
9530d02842fSSascha Wildner * those implemented in the other register block) always returns zeros,
9540d02842fSSascha Wildner * and writes have no side effects"
9550d02842fSSascha Wildner */
9560d02842fSSascha Wildner *Value = (ValueA | ValueB);
9570d02842fSSascha Wildner return (AE_OK);
9580d02842fSSascha Wildner }
9590d02842fSSascha Wildner
9600d02842fSSascha Wildner
9610d02842fSSascha Wildner /******************************************************************************
9620d02842fSSascha Wildner *
9630d02842fSSascha Wildner * FUNCTION: AcpiHwWriteMultiple
9640d02842fSSascha Wildner *
9650d02842fSSascha Wildner * PARAMETERS: Value - The value to write
9660d02842fSSascha Wildner * RegisterA - First ACPI register (required)
9670d02842fSSascha Wildner * RegisterB - Second ACPI register (optional)
9680d02842fSSascha Wildner *
9690d02842fSSascha Wildner * RETURN: Status
9700d02842fSSascha Wildner *
9710d02842fSSascha Wildner * DESCRIPTION: Write to the specified two-part ACPI register (such as PM1 A/B)
9720d02842fSSascha Wildner *
9730d02842fSSascha Wildner ******************************************************************************/
9740d02842fSSascha Wildner
9750d02842fSSascha Wildner static ACPI_STATUS
AcpiHwWriteMultiple(UINT32 Value,ACPI_GENERIC_ADDRESS * RegisterA,ACPI_GENERIC_ADDRESS * RegisterB)9760d02842fSSascha Wildner AcpiHwWriteMultiple (
9770d02842fSSascha Wildner UINT32 Value,
9780d02842fSSascha Wildner ACPI_GENERIC_ADDRESS *RegisterA,
9790d02842fSSascha Wildner ACPI_GENERIC_ADDRESS *RegisterB)
9800d02842fSSascha Wildner {
9810d02842fSSascha Wildner ACPI_STATUS Status;
9820d02842fSSascha Wildner
9830d02842fSSascha Wildner
9840d02842fSSascha Wildner /* The first register is always required */
9850d02842fSSascha Wildner
9860d02842fSSascha Wildner Status = AcpiHwWrite (Value, RegisterA);
9870d02842fSSascha Wildner if (ACPI_FAILURE (Status))
9880d02842fSSascha Wildner {
9890d02842fSSascha Wildner return (Status);
9900d02842fSSascha Wildner }
9910d02842fSSascha Wildner
9920d02842fSSascha Wildner /*
9930d02842fSSascha Wildner * Second register is optional
9940d02842fSSascha Wildner *
9950d02842fSSascha Wildner * No bit shifting or clearing is necessary, because of how the PM1
9960d02842fSSascha Wildner * registers are defined in the ACPI specification:
9970d02842fSSascha Wildner *
9980d02842fSSascha Wildner * "Although the bits can be split between the two register blocks (each
9990d02842fSSascha Wildner * register block has a unique pointer within the FADT), the bit positions
10000d02842fSSascha Wildner * are maintained. The register block with unimplemented bits (that is,
10010d02842fSSascha Wildner * those implemented in the other register block) always returns zeros,
10020d02842fSSascha Wildner * and writes have no side effects"
10030d02842fSSascha Wildner */
10040d02842fSSascha Wildner if (RegisterB->Address)
10050d02842fSSascha Wildner {
10060d02842fSSascha Wildner Status = AcpiHwWrite (Value, RegisterB);
10070d02842fSSascha Wildner }
10080d02842fSSascha Wildner
10090d02842fSSascha Wildner return (Status);
10100d02842fSSascha Wildner }
10110d02842fSSascha Wildner
10120d02842fSSascha Wildner #endif /* !ACPI_REDUCED_HARDWARE */
1013