xref: /dflybsd-src/sys/contrib/dev/acpica/source/components/hardware/hwregs.c (revision 383048aca08c2de51d27aa8638a36982a0d74550)
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