xref: /freebsd/sys/contrib/dev/acpica/components/hardware/hwregs.c (revision f8146b882bc156c1d8ddf14bbea67253ebc064bb)
1a159c266SJung-uk Kim /*******************************************************************************
2a159c266SJung-uk Kim  *
3a159c266SJung-uk Kim  * Module Name: hwregs - Read/write access functions for the various ACPI
4a159c266SJung-uk Kim  *                       control and status registers.
5a159c266SJung-uk Kim  *
6a159c266SJung-uk Kim  ******************************************************************************/
7a159c266SJung-uk Kim 
8a159c266SJung-uk Kim /*
9*f8146b88SJung-uk Kim  * Copyright (C) 2000 - 2016, Intel Corp.
10a159c266SJung-uk Kim  * All rights reserved.
11a159c266SJung-uk Kim  *
12a159c266SJung-uk Kim  * Redistribution and use in source and binary forms, with or without
13a159c266SJung-uk Kim  * modification, are permitted provided that the following conditions
14a159c266SJung-uk Kim  * are met:
15a159c266SJung-uk Kim  * 1. Redistributions of source code must retain the above copyright
16a159c266SJung-uk Kim  *    notice, this list of conditions, and the following disclaimer,
17a159c266SJung-uk Kim  *    without modification.
18a159c266SJung-uk Kim  * 2. Redistributions in binary form must reproduce at minimum a disclaimer
19a159c266SJung-uk Kim  *    substantially similar to the "NO WARRANTY" disclaimer below
20a159c266SJung-uk Kim  *    ("Disclaimer") and any redistribution must be conditioned upon
21a159c266SJung-uk Kim  *    including a substantially similar Disclaimer requirement for further
22a159c266SJung-uk Kim  *    binary redistribution.
23a159c266SJung-uk Kim  * 3. Neither the names of the above-listed copyright holders nor the names
24a159c266SJung-uk Kim  *    of any contributors may be used to endorse or promote products derived
25a159c266SJung-uk Kim  *    from this software without specific prior written permission.
26a159c266SJung-uk Kim  *
27a159c266SJung-uk Kim  * Alternatively, this software may be distributed under the terms of the
28a159c266SJung-uk Kim  * GNU General Public License ("GPL") version 2 as published by the Free
29a159c266SJung-uk Kim  * Software Foundation.
30a159c266SJung-uk Kim  *
31a159c266SJung-uk Kim  * NO WARRANTY
32a159c266SJung-uk Kim  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
33a159c266SJung-uk Kim  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
34a159c266SJung-uk Kim  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
35a159c266SJung-uk Kim  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
36a159c266SJung-uk Kim  * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
37a159c266SJung-uk Kim  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
38a159c266SJung-uk Kim  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
39a159c266SJung-uk Kim  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
40a159c266SJung-uk Kim  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
41a159c266SJung-uk Kim  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
42a159c266SJung-uk Kim  * POSSIBILITY OF SUCH DAMAGES.
43a159c266SJung-uk Kim  */
44a159c266SJung-uk Kim 
45a159c266SJung-uk Kim #include <contrib/dev/acpica/include/acpi.h>
46a159c266SJung-uk Kim #include <contrib/dev/acpica/include/accommon.h>
47a159c266SJung-uk Kim #include <contrib/dev/acpica/include/acevents.h>
48a159c266SJung-uk Kim 
49a159c266SJung-uk Kim #define _COMPONENT          ACPI_HARDWARE
50a159c266SJung-uk Kim         ACPI_MODULE_NAME    ("hwregs")
51a159c266SJung-uk Kim 
52a159c266SJung-uk Kim 
53a159c266SJung-uk Kim #if (!ACPI_REDUCED_HARDWARE)
54a159c266SJung-uk Kim 
55a159c266SJung-uk Kim /* Local Prototypes */
56a159c266SJung-uk Kim 
57*f8146b88SJung-uk Kim static UINT8
58*f8146b88SJung-uk Kim AcpiHwGetAccessBitWidth (
59*f8146b88SJung-uk Kim     ACPI_GENERIC_ADDRESS    *Reg,
60*f8146b88SJung-uk Kim     UINT8                   MaxBitWidth);
61*f8146b88SJung-uk Kim 
62a159c266SJung-uk Kim static ACPI_STATUS
63a159c266SJung-uk Kim AcpiHwReadMultiple (
64a159c266SJung-uk Kim     UINT32                  *Value,
65a159c266SJung-uk Kim     ACPI_GENERIC_ADDRESS    *RegisterA,
66a159c266SJung-uk Kim     ACPI_GENERIC_ADDRESS    *RegisterB);
67a159c266SJung-uk Kim 
68a159c266SJung-uk Kim static ACPI_STATUS
69a159c266SJung-uk Kim AcpiHwWriteMultiple (
70a159c266SJung-uk Kim     UINT32                  Value,
71a159c266SJung-uk Kim     ACPI_GENERIC_ADDRESS    *RegisterA,
72a159c266SJung-uk Kim     ACPI_GENERIC_ADDRESS    *RegisterB);
73a159c266SJung-uk Kim 
74a159c266SJung-uk Kim #endif /* !ACPI_REDUCED_HARDWARE */
75a159c266SJung-uk Kim 
76*f8146b88SJung-uk Kim 
77*f8146b88SJung-uk Kim /******************************************************************************
78*f8146b88SJung-uk Kim  *
79*f8146b88SJung-uk Kim  * FUNCTION:    AcpiHwGetAccessBitWidth
80*f8146b88SJung-uk Kim  *
81*f8146b88SJung-uk Kim  * PARAMETERS:  Reg                 - GAS register structure
82*f8146b88SJung-uk Kim  *              MaxBitWidth         - Max BitWidth supported (32 or 64)
83*f8146b88SJung-uk Kim  *
84*f8146b88SJung-uk Kim  * RETURN:      Status
85*f8146b88SJung-uk Kim  *
86*f8146b88SJung-uk Kim  * DESCRIPTION: Obtain optimal access bit width
87*f8146b88SJung-uk Kim  *
88*f8146b88SJung-uk Kim  ******************************************************************************/
89*f8146b88SJung-uk Kim 
90*f8146b88SJung-uk Kim static UINT8
91*f8146b88SJung-uk Kim AcpiHwGetAccessBitWidth (
92*f8146b88SJung-uk Kim     ACPI_GENERIC_ADDRESS    *Reg,
93*f8146b88SJung-uk Kim     UINT8                   MaxBitWidth)
94*f8146b88SJung-uk Kim {
95*f8146b88SJung-uk Kim 
96*f8146b88SJung-uk Kim     if (!Reg->AccessWidth)
97*f8146b88SJung-uk Kim     {
98*f8146b88SJung-uk Kim         if (Reg->SpaceId == ACPI_ADR_SPACE_SYSTEM_IO)
99*f8146b88SJung-uk Kim         {
100*f8146b88SJung-uk Kim             return (32);
101*f8146b88SJung-uk Kim         }
102*f8146b88SJung-uk Kim         else
103*f8146b88SJung-uk Kim         {
104*f8146b88SJung-uk Kim             return (MaxBitWidth);
105*f8146b88SJung-uk Kim         }
106*f8146b88SJung-uk Kim     }
107*f8146b88SJung-uk Kim     else
108*f8146b88SJung-uk Kim     {
109*f8146b88SJung-uk Kim         return (1 << (Reg->AccessWidth + 2));
110*f8146b88SJung-uk Kim     }
111*f8146b88SJung-uk Kim }
112*f8146b88SJung-uk Kim 
113*f8146b88SJung-uk Kim 
114a159c266SJung-uk Kim /******************************************************************************
115a159c266SJung-uk Kim  *
116a159c266SJung-uk Kim  * FUNCTION:    AcpiHwValidateRegister
117a159c266SJung-uk Kim  *
118a159c266SJung-uk Kim  * PARAMETERS:  Reg                 - GAS register structure
119a159c266SJung-uk Kim  *              MaxBitWidth         - Max BitWidth supported (32 or 64)
120a159c266SJung-uk Kim  *              Address             - Pointer to where the gas->address
121a159c266SJung-uk Kim  *                                    is returned
122a159c266SJung-uk Kim  *
123a159c266SJung-uk Kim  * RETURN:      Status
124a159c266SJung-uk Kim  *
125a159c266SJung-uk Kim  * DESCRIPTION: Validate the contents of a GAS register. Checks the GAS
126a159c266SJung-uk Kim  *              pointer, Address, SpaceId, BitWidth, and BitOffset.
127a159c266SJung-uk Kim  *
128a159c266SJung-uk Kim  ******************************************************************************/
129a159c266SJung-uk Kim 
130a159c266SJung-uk Kim ACPI_STATUS
131a159c266SJung-uk Kim AcpiHwValidateRegister (
132a159c266SJung-uk Kim     ACPI_GENERIC_ADDRESS    *Reg,
133a159c266SJung-uk Kim     UINT8                   MaxBitWidth,
134a159c266SJung-uk Kim     UINT64                  *Address)
135a159c266SJung-uk Kim {
136*f8146b88SJung-uk Kim     UINT8                   BitWidth;
137*f8146b88SJung-uk Kim     UINT8                   AccessWidth;
138*f8146b88SJung-uk Kim 
139a159c266SJung-uk Kim 
140a159c266SJung-uk Kim     /* Must have a valid pointer to a GAS structure */
141a159c266SJung-uk Kim 
142a159c266SJung-uk Kim     if (!Reg)
143a159c266SJung-uk Kim     {
144a159c266SJung-uk Kim         return (AE_BAD_PARAMETER);
145a159c266SJung-uk Kim     }
146a159c266SJung-uk Kim 
147a159c266SJung-uk Kim     /*
148a159c266SJung-uk Kim      * Copy the target address. This handles possible alignment issues.
149a159c266SJung-uk Kim      * Address must not be null. A null address also indicates an optional
150a159c266SJung-uk Kim      * ACPI register that is not supported, so no error message.
151a159c266SJung-uk Kim      */
152a159c266SJung-uk Kim     ACPI_MOVE_64_TO_64 (Address, &Reg->Address);
153a159c266SJung-uk Kim     if (!(*Address))
154a159c266SJung-uk Kim     {
155a159c266SJung-uk Kim         return (AE_BAD_ADDRESS);
156a159c266SJung-uk Kim     }
157a159c266SJung-uk Kim 
158a159c266SJung-uk Kim     /* Validate the SpaceID */
159a159c266SJung-uk Kim 
160a159c266SJung-uk Kim     if ((Reg->SpaceId != ACPI_ADR_SPACE_SYSTEM_MEMORY) &&
161a159c266SJung-uk Kim         (Reg->SpaceId != ACPI_ADR_SPACE_SYSTEM_IO))
162a159c266SJung-uk Kim     {
163a159c266SJung-uk Kim         ACPI_ERROR ((AE_INFO,
164a159c266SJung-uk Kim             "Unsupported address space: 0x%X", Reg->SpaceId));
165a159c266SJung-uk Kim         return (AE_SUPPORT);
166a159c266SJung-uk Kim     }
167a159c266SJung-uk Kim 
168*f8146b88SJung-uk Kim     /* Validate the AccessWidth */
169a159c266SJung-uk Kim 
170*f8146b88SJung-uk Kim     if (Reg->AccessWidth > 4)
171a159c266SJung-uk Kim     {
172a159c266SJung-uk Kim         ACPI_ERROR ((AE_INFO,
173*f8146b88SJung-uk Kim             "Unsupported register access width: 0x%X", Reg->AccessWidth));
174a159c266SJung-uk Kim         return (AE_SUPPORT);
175a159c266SJung-uk Kim     }
176a159c266SJung-uk Kim 
177*f8146b88SJung-uk Kim     /* Validate the BitWidth, convert AccessWidth into number of bits */
178a159c266SJung-uk Kim 
179*f8146b88SJung-uk Kim     AccessWidth = AcpiHwGetAccessBitWidth (Reg, MaxBitWidth);
180*f8146b88SJung-uk Kim     BitWidth = ACPI_ROUND_UP (Reg->BitOffset + Reg->BitWidth, AccessWidth);
181*f8146b88SJung-uk Kim     if (MaxBitWidth < BitWidth)
182a159c266SJung-uk Kim     {
183a159c266SJung-uk Kim         ACPI_WARNING ((AE_INFO,
184*f8146b88SJung-uk Kim             "Requested bit width 0x%X is smaller than register bit width 0x%X",
185*f8146b88SJung-uk Kim             MaxBitWidth, BitWidth));
186*f8146b88SJung-uk Kim         return (AE_SUPPORT);
187a159c266SJung-uk Kim     }
188a159c266SJung-uk Kim 
189a159c266SJung-uk Kim     return (AE_OK);
190a159c266SJung-uk Kim }
191a159c266SJung-uk Kim 
192a159c266SJung-uk Kim 
193a159c266SJung-uk Kim /******************************************************************************
194a159c266SJung-uk Kim  *
195a159c266SJung-uk Kim  * FUNCTION:    AcpiHwRead
196a159c266SJung-uk Kim  *
197a159c266SJung-uk Kim  * PARAMETERS:  Value               - Where the value is returned
198a159c266SJung-uk Kim  *              Reg                 - GAS register structure
199a159c266SJung-uk Kim  *
200a159c266SJung-uk Kim  * RETURN:      Status
201a159c266SJung-uk Kim  *
202a159c266SJung-uk Kim  * DESCRIPTION: Read from either memory or IO space. This is a 32-bit max
203a159c266SJung-uk Kim  *              version of AcpiRead, used internally since the overhead of
204a159c266SJung-uk Kim  *              64-bit values is not needed.
205a159c266SJung-uk Kim  *
206a159c266SJung-uk Kim  * LIMITATIONS: <These limitations also apply to AcpiHwWrite>
207a159c266SJung-uk Kim  *      SpaceID must be SystemMemory or SystemIO.
208a159c266SJung-uk Kim  *
209a159c266SJung-uk Kim  ******************************************************************************/
210a159c266SJung-uk Kim 
211a159c266SJung-uk Kim ACPI_STATUS
212a159c266SJung-uk Kim AcpiHwRead (
213a159c266SJung-uk Kim     UINT32                  *Value,
214a159c266SJung-uk Kim     ACPI_GENERIC_ADDRESS    *Reg)
215a159c266SJung-uk Kim {
216a159c266SJung-uk Kim     UINT64                  Address;
217*f8146b88SJung-uk Kim     UINT8                   AccessWidth;
218*f8146b88SJung-uk Kim     UINT32                  BitWidth;
219*f8146b88SJung-uk Kim     UINT8                   BitOffset;
220a159c266SJung-uk Kim     UINT64                  Value64;
221*f8146b88SJung-uk Kim     UINT32                  Value32;
222*f8146b88SJung-uk Kim     UINT8                   Index;
223a159c266SJung-uk Kim     ACPI_STATUS             Status;
224a159c266SJung-uk Kim 
225a159c266SJung-uk Kim 
226a159c266SJung-uk Kim     ACPI_FUNCTION_NAME (HwRead);
227a159c266SJung-uk Kim 
228a159c266SJung-uk Kim 
229a159c266SJung-uk Kim     /* Validate contents of the GAS register */
230a159c266SJung-uk Kim 
231a159c266SJung-uk Kim     Status = AcpiHwValidateRegister (Reg, 32, &Address);
232a159c266SJung-uk Kim     if (ACPI_FAILURE (Status))
233a159c266SJung-uk Kim     {
234a159c266SJung-uk Kim         return (Status);
235a159c266SJung-uk Kim     }
236a159c266SJung-uk Kim 
237*f8146b88SJung-uk Kim     /*
238*f8146b88SJung-uk Kim      * Initialize entire 32-bit return value to zero, convert AccessWidth
239*f8146b88SJung-uk Kim      * into number of bits based
240*f8146b88SJung-uk Kim      */
241a159c266SJung-uk Kim     *Value = 0;
242*f8146b88SJung-uk Kim     AccessWidth = AcpiHwGetAccessBitWidth (Reg, 32);
243*f8146b88SJung-uk Kim     BitWidth = Reg->BitOffset + Reg->BitWidth;
244*f8146b88SJung-uk Kim     BitOffset = Reg->BitOffset;
245a159c266SJung-uk Kim 
246a159c266SJung-uk Kim     /*
247a159c266SJung-uk Kim      * Two address spaces supported: Memory or IO. PCI_Config is
248a159c266SJung-uk Kim      * not supported here because the GAS structure is insufficient
249a159c266SJung-uk Kim      */
250*f8146b88SJung-uk Kim     Index = 0;
251*f8146b88SJung-uk Kim     while (BitWidth)
252*f8146b88SJung-uk Kim     {
253*f8146b88SJung-uk Kim         if (BitOffset > AccessWidth)
254*f8146b88SJung-uk Kim         {
255*f8146b88SJung-uk Kim             Value32 = 0;
256*f8146b88SJung-uk Kim             BitOffset -= AccessWidth;
257*f8146b88SJung-uk Kim         }
258*f8146b88SJung-uk Kim         else
259*f8146b88SJung-uk Kim         {
260a159c266SJung-uk Kim             if (Reg->SpaceId == ACPI_ADR_SPACE_SYSTEM_MEMORY)
261a159c266SJung-uk Kim             {
262a159c266SJung-uk Kim                 Status = AcpiOsReadMemory ((ACPI_PHYSICAL_ADDRESS)
263*f8146b88SJung-uk Kim                     Address + Index * ACPI_DIV_8 (AccessWidth),
264*f8146b88SJung-uk Kim                     &Value64, AccessWidth);
265*f8146b88SJung-uk Kim                 Value32 = (UINT32) Value64;
266a159c266SJung-uk Kim             }
267a159c266SJung-uk Kim             else /* ACPI_ADR_SPACE_SYSTEM_IO, validated earlier */
268a159c266SJung-uk Kim             {
269a159c266SJung-uk Kim                 Status = AcpiHwReadPort ((ACPI_IO_ADDRESS)
270*f8146b88SJung-uk Kim                     Address + Index * ACPI_DIV_8 (AccessWidth),
271*f8146b88SJung-uk Kim                     &Value32, AccessWidth);
272*f8146b88SJung-uk Kim             }
273*f8146b88SJung-uk Kim 
274*f8146b88SJung-uk Kim             if (BitOffset)
275*f8146b88SJung-uk Kim             {
276*f8146b88SJung-uk Kim                 Value32 &= ACPI_MASK_BITS_BELOW (BitOffset);
277*f8146b88SJung-uk Kim                 BitOffset = 0;
278*f8146b88SJung-uk Kim             }
279*f8146b88SJung-uk Kim             if (BitWidth < AccessWidth)
280*f8146b88SJung-uk Kim             {
281*f8146b88SJung-uk Kim                 Value32 &= ACPI_MASK_BITS_ABOVE (BitWidth);
282*f8146b88SJung-uk Kim             }
283*f8146b88SJung-uk Kim         }
284*f8146b88SJung-uk Kim 
285*f8146b88SJung-uk Kim         ACPI_SET_BITS (Value, Index * AccessWidth,
286*f8146b88SJung-uk Kim             ACPI_MASK_BITS_ABOVE_32 (AccessWidth), Value32);
287*f8146b88SJung-uk Kim 
288*f8146b88SJung-uk Kim         BitWidth -= BitWidth > AccessWidth ? AccessWidth : BitWidth;
289*f8146b88SJung-uk Kim         Index++;
290a159c266SJung-uk Kim     }
291a159c266SJung-uk Kim 
292a159c266SJung-uk Kim     ACPI_DEBUG_PRINT ((ACPI_DB_IO,
293a159c266SJung-uk Kim         "Read:  %8.8X width %2d from %8.8X%8.8X (%s)\n",
294*f8146b88SJung-uk Kim         *Value, AccessWidth, ACPI_FORMAT_UINT64 (Address),
295a159c266SJung-uk Kim         AcpiUtGetRegionName (Reg->SpaceId)));
296a159c266SJung-uk Kim 
297a159c266SJung-uk Kim     return (Status);
298a159c266SJung-uk Kim }
299a159c266SJung-uk Kim 
300a159c266SJung-uk Kim 
301a159c266SJung-uk Kim /******************************************************************************
302a159c266SJung-uk Kim  *
303a159c266SJung-uk Kim  * FUNCTION:    AcpiHwWrite
304a159c266SJung-uk Kim  *
305a159c266SJung-uk Kim  * PARAMETERS:  Value               - Value to be written
306a159c266SJung-uk Kim  *              Reg                 - GAS register structure
307a159c266SJung-uk Kim  *
308a159c266SJung-uk Kim  * RETURN:      Status
309a159c266SJung-uk Kim  *
310a159c266SJung-uk Kim  * DESCRIPTION: Write to either memory or IO space. This is a 32-bit max
311a159c266SJung-uk Kim  *              version of AcpiWrite, used internally since the overhead of
312a159c266SJung-uk Kim  *              64-bit values is not needed.
313a159c266SJung-uk Kim  *
314a159c266SJung-uk Kim  ******************************************************************************/
315a159c266SJung-uk Kim 
316a159c266SJung-uk Kim ACPI_STATUS
317a159c266SJung-uk Kim AcpiHwWrite (
318a159c266SJung-uk Kim     UINT32                  Value,
319a159c266SJung-uk Kim     ACPI_GENERIC_ADDRESS    *Reg)
320a159c266SJung-uk Kim {
321a159c266SJung-uk Kim     UINT64                  Address;
322*f8146b88SJung-uk Kim     UINT8                   AccessWidth;
323*f8146b88SJung-uk Kim     UINT32                  BitWidth;
324*f8146b88SJung-uk Kim     UINT8                   BitOffset;
325*f8146b88SJung-uk Kim     UINT64                  Value64;
326*f8146b88SJung-uk Kim     UINT32                  NewValue32, OldValue32;
327*f8146b88SJung-uk Kim     UINT8                   Index;
328a159c266SJung-uk Kim     ACPI_STATUS             Status;
329a159c266SJung-uk Kim 
330a159c266SJung-uk Kim 
331a159c266SJung-uk Kim     ACPI_FUNCTION_NAME (HwWrite);
332a159c266SJung-uk Kim 
333a159c266SJung-uk Kim 
334a159c266SJung-uk Kim     /* Validate contents of the GAS register */
335a159c266SJung-uk Kim 
336a159c266SJung-uk Kim     Status = AcpiHwValidateRegister (Reg, 32, &Address);
337a159c266SJung-uk Kim     if (ACPI_FAILURE (Status))
338a159c266SJung-uk Kim     {
339a159c266SJung-uk Kim         return (Status);
340a159c266SJung-uk Kim     }
341a159c266SJung-uk Kim 
342*f8146b88SJung-uk Kim     /* Convert AccessWidth into number of bits based */
343*f8146b88SJung-uk Kim 
344*f8146b88SJung-uk Kim     AccessWidth = AcpiHwGetAccessBitWidth (Reg, 32);
345*f8146b88SJung-uk Kim     BitWidth = Reg->BitOffset + Reg->BitWidth;
346*f8146b88SJung-uk Kim     BitOffset = Reg->BitOffset;
347*f8146b88SJung-uk Kim 
348a159c266SJung-uk Kim     /*
349a159c266SJung-uk Kim      * Two address spaces supported: Memory or IO. PCI_Config is
350a159c266SJung-uk Kim      * not supported here because the GAS structure is insufficient
351a159c266SJung-uk Kim      */
352*f8146b88SJung-uk Kim     Index = 0;
353*f8146b88SJung-uk Kim     while (BitWidth)
354*f8146b88SJung-uk Kim     {
355*f8146b88SJung-uk Kim         NewValue32 = ACPI_GET_BITS (&Value, Index * AccessWidth,
356*f8146b88SJung-uk Kim             ACPI_MASK_BITS_ABOVE_32 (AccessWidth));
357*f8146b88SJung-uk Kim 
358*f8146b88SJung-uk Kim         if (BitOffset > AccessWidth)
359*f8146b88SJung-uk Kim         {
360*f8146b88SJung-uk Kim             BitOffset -= AccessWidth;
361*f8146b88SJung-uk Kim         }
362*f8146b88SJung-uk Kim         else
363*f8146b88SJung-uk Kim         {
364*f8146b88SJung-uk Kim             if (BitOffset)
365*f8146b88SJung-uk Kim             {
366*f8146b88SJung-uk Kim                 NewValue32 &= ACPI_MASK_BITS_BELOW (BitOffset);
367*f8146b88SJung-uk Kim             }
368*f8146b88SJung-uk Kim 
369*f8146b88SJung-uk Kim             if (BitWidth < AccessWidth)
370*f8146b88SJung-uk Kim             {
371*f8146b88SJung-uk Kim                 NewValue32 &= ACPI_MASK_BITS_ABOVE (BitWidth);
372*f8146b88SJung-uk Kim             }
373*f8146b88SJung-uk Kim 
374a159c266SJung-uk Kim             if (Reg->SpaceId == ACPI_ADR_SPACE_SYSTEM_MEMORY)
375a159c266SJung-uk Kim             {
376*f8146b88SJung-uk Kim                 if (BitOffset || BitWidth < AccessWidth)
377*f8146b88SJung-uk Kim                 {
378*f8146b88SJung-uk Kim                     /*
379*f8146b88SJung-uk Kim                      * Read old values in order not to modify the bits that
380*f8146b88SJung-uk Kim                      * are beyond the register BitWidth/BitOffset setting.
381*f8146b88SJung-uk Kim                      */
382*f8146b88SJung-uk Kim                     Status = AcpiOsReadMemory ((ACPI_PHYSICAL_ADDRESS)
383*f8146b88SJung-uk Kim                         Address + Index * ACPI_DIV_8 (AccessWidth),
384*f8146b88SJung-uk Kim                         &Value64, AccessWidth);
385*f8146b88SJung-uk Kim                     OldValue32 = (UINT32) Value64;
386*f8146b88SJung-uk Kim 
387*f8146b88SJung-uk Kim                     if (BitOffset)
388*f8146b88SJung-uk Kim                     {
389*f8146b88SJung-uk Kim                         OldValue32 &= ACPI_MASK_BITS_ABOVE (BitOffset + 1);
390*f8146b88SJung-uk Kim                         BitOffset = 0;
391*f8146b88SJung-uk Kim                     }
392*f8146b88SJung-uk Kim 
393*f8146b88SJung-uk Kim                     if (BitWidth < AccessWidth)
394*f8146b88SJung-uk Kim                     {
395*f8146b88SJung-uk Kim                         OldValue32 &= ACPI_MASK_BITS_BELOW (BitWidth - 1);
396*f8146b88SJung-uk Kim                     }
397*f8146b88SJung-uk Kim 
398*f8146b88SJung-uk Kim                     NewValue32 |= OldValue32;
399*f8146b88SJung-uk Kim                 }
400*f8146b88SJung-uk Kim 
401*f8146b88SJung-uk Kim                 Value64 = (UINT64) NewValue32;
402a159c266SJung-uk Kim                 Status = AcpiOsWriteMemory ((ACPI_PHYSICAL_ADDRESS)
403*f8146b88SJung-uk Kim                     Address + Index * ACPI_DIV_8 (AccessWidth),
404*f8146b88SJung-uk Kim                     Value64, AccessWidth);
405a159c266SJung-uk Kim             }
406a159c266SJung-uk Kim             else /* ACPI_ADR_SPACE_SYSTEM_IO, validated earlier */
407a159c266SJung-uk Kim             {
408*f8146b88SJung-uk Kim                 if (BitOffset || BitWidth < AccessWidth)
409*f8146b88SJung-uk Kim                 {
410*f8146b88SJung-uk Kim                     /*
411*f8146b88SJung-uk Kim                      * Read old values in order not to modify the bits that
412*f8146b88SJung-uk Kim                      * are beyond the register BitWidth/BitOffset setting.
413*f8146b88SJung-uk Kim                      */
414*f8146b88SJung-uk Kim                     Status = AcpiHwReadPort ((ACPI_IO_ADDRESS)
415*f8146b88SJung-uk Kim                         Address + Index * ACPI_DIV_8 (AccessWidth),
416*f8146b88SJung-uk Kim                         &OldValue32, AccessWidth);
417*f8146b88SJung-uk Kim 
418*f8146b88SJung-uk Kim                     if (BitOffset)
419*f8146b88SJung-uk Kim                     {
420*f8146b88SJung-uk Kim                         OldValue32 &= ACPI_MASK_BITS_ABOVE (BitOffset + 1);
421*f8146b88SJung-uk Kim                         BitOffset = 0;
422*f8146b88SJung-uk Kim                     }
423*f8146b88SJung-uk Kim 
424*f8146b88SJung-uk Kim                     if (BitWidth < AccessWidth)
425*f8146b88SJung-uk Kim                     {
426*f8146b88SJung-uk Kim                         OldValue32 &= ACPI_MASK_BITS_BELOW (BitWidth - 1);
427*f8146b88SJung-uk Kim                     }
428*f8146b88SJung-uk Kim 
429*f8146b88SJung-uk Kim                     NewValue32 |= OldValue32;
430*f8146b88SJung-uk Kim                 }
431*f8146b88SJung-uk Kim 
432a159c266SJung-uk Kim                 Status = AcpiHwWritePort ((ACPI_IO_ADDRESS)
433*f8146b88SJung-uk Kim                     Address + Index * ACPI_DIV_8 (AccessWidth),
434*f8146b88SJung-uk Kim                     NewValue32, AccessWidth);
435*f8146b88SJung-uk Kim             }
436*f8146b88SJung-uk Kim         }
437*f8146b88SJung-uk Kim 
438*f8146b88SJung-uk Kim         BitWidth -= BitWidth > AccessWidth ? AccessWidth : BitWidth;
439*f8146b88SJung-uk Kim         Index++;
440a159c266SJung-uk Kim     }
441a159c266SJung-uk Kim 
442a159c266SJung-uk Kim     ACPI_DEBUG_PRINT ((ACPI_DB_IO,
443a159c266SJung-uk Kim         "Wrote: %8.8X width %2d   to %8.8X%8.8X (%s)\n",
444*f8146b88SJung-uk Kim         Value, AccessWidth, ACPI_FORMAT_UINT64 (Address),
445a159c266SJung-uk Kim         AcpiUtGetRegionName (Reg->SpaceId)));
446a159c266SJung-uk Kim 
447a159c266SJung-uk Kim     return (Status);
448a159c266SJung-uk Kim }
449a159c266SJung-uk Kim 
450a159c266SJung-uk Kim 
451a159c266SJung-uk Kim #if (!ACPI_REDUCED_HARDWARE)
452a159c266SJung-uk Kim /*******************************************************************************
453a159c266SJung-uk Kim  *
454a159c266SJung-uk Kim  * FUNCTION:    AcpiHwClearAcpiStatus
455a159c266SJung-uk Kim  *
456a159c266SJung-uk Kim  * PARAMETERS:  None
457a159c266SJung-uk Kim  *
458a159c266SJung-uk Kim  * RETURN:      Status
459a159c266SJung-uk Kim  *
460a159c266SJung-uk Kim  * DESCRIPTION: Clears all fixed and general purpose status bits
461a159c266SJung-uk Kim  *
462a159c266SJung-uk Kim  ******************************************************************************/
463a159c266SJung-uk Kim 
464a159c266SJung-uk Kim ACPI_STATUS
465a159c266SJung-uk Kim AcpiHwClearAcpiStatus (
466a159c266SJung-uk Kim     void)
467a159c266SJung-uk Kim {
468a159c266SJung-uk Kim     ACPI_STATUS             Status;
469a159c266SJung-uk Kim     ACPI_CPU_FLAGS          LockFlags = 0;
470a159c266SJung-uk Kim 
471a159c266SJung-uk Kim 
472a159c266SJung-uk Kim     ACPI_FUNCTION_TRACE (HwClearAcpiStatus);
473a159c266SJung-uk Kim 
474a159c266SJung-uk Kim 
475a159c266SJung-uk Kim     ACPI_DEBUG_PRINT ((ACPI_DB_IO, "About to write %04X to %8.8X%8.8X\n",
476a159c266SJung-uk Kim         ACPI_BITMASK_ALL_FIXED_STATUS,
477a159c266SJung-uk Kim         ACPI_FORMAT_UINT64 (AcpiGbl_XPm1aStatus.Address)));
478a159c266SJung-uk Kim 
479a159c266SJung-uk Kim     LockFlags = AcpiOsAcquireLock (AcpiGbl_HardwareLock);
480a159c266SJung-uk Kim 
481a159c266SJung-uk Kim     /* Clear the fixed events in PM1 A/B */
482a159c266SJung-uk Kim 
483a159c266SJung-uk Kim     Status = AcpiHwRegisterWrite (ACPI_REGISTER_PM1_STATUS,
484a159c266SJung-uk Kim         ACPI_BITMASK_ALL_FIXED_STATUS);
485313a0c13SJung-uk Kim 
486313a0c13SJung-uk Kim     AcpiOsReleaseLock (AcpiGbl_HardwareLock, LockFlags);
487313a0c13SJung-uk Kim 
488a159c266SJung-uk Kim     if (ACPI_FAILURE (Status))
489a159c266SJung-uk Kim     {
490313a0c13SJung-uk Kim         goto Exit;
491a159c266SJung-uk Kim     }
492a159c266SJung-uk Kim 
493a159c266SJung-uk Kim     /* Clear the GPE Bits in all GPE registers in all GPE blocks */
494a159c266SJung-uk Kim 
495a159c266SJung-uk Kim     Status = AcpiEvWalkGpeList (AcpiHwClearGpeBlock, NULL);
496a159c266SJung-uk Kim 
497313a0c13SJung-uk Kim Exit:
498a159c266SJung-uk Kim     return_ACPI_STATUS (Status);
499a159c266SJung-uk Kim }
500a159c266SJung-uk Kim 
501a159c266SJung-uk Kim 
502a159c266SJung-uk Kim /*******************************************************************************
503a159c266SJung-uk Kim  *
504a159c266SJung-uk Kim  * FUNCTION:    AcpiHwGetBitRegisterInfo
505a159c266SJung-uk Kim  *
506a159c266SJung-uk Kim  * PARAMETERS:  RegisterId          - Index of ACPI Register to access
507a159c266SJung-uk Kim  *
508a159c266SJung-uk Kim  * RETURN:      The bitmask to be used when accessing the register
509a159c266SJung-uk Kim  *
510a159c266SJung-uk Kim  * DESCRIPTION: Map RegisterId into a register bitmask.
511a159c266SJung-uk Kim  *
512a159c266SJung-uk Kim  ******************************************************************************/
513a159c266SJung-uk Kim 
514a159c266SJung-uk Kim ACPI_BIT_REGISTER_INFO *
515a159c266SJung-uk Kim AcpiHwGetBitRegisterInfo (
516a159c266SJung-uk Kim     UINT32                  RegisterId)
517a159c266SJung-uk Kim {
518a159c266SJung-uk Kim     ACPI_FUNCTION_ENTRY ();
519a159c266SJung-uk Kim 
520a159c266SJung-uk Kim 
521a159c266SJung-uk Kim     if (RegisterId > ACPI_BITREG_MAX)
522a159c266SJung-uk Kim     {
523a159c266SJung-uk Kim         ACPI_ERROR ((AE_INFO, "Invalid BitRegister ID: 0x%X", RegisterId));
524a159c266SJung-uk Kim         return (NULL);
525a159c266SJung-uk Kim     }
526a159c266SJung-uk Kim 
527a159c266SJung-uk Kim     return (&AcpiGbl_BitRegisterInfo[RegisterId]);
528a159c266SJung-uk Kim }
529a159c266SJung-uk Kim 
530a159c266SJung-uk Kim 
531a159c266SJung-uk Kim /******************************************************************************
532a159c266SJung-uk Kim  *
533a159c266SJung-uk Kim  * FUNCTION:    AcpiHwWritePm1Control
534a159c266SJung-uk Kim  *
535a159c266SJung-uk Kim  * PARAMETERS:  Pm1aControl         - Value to be written to PM1A control
536a159c266SJung-uk Kim  *              Pm1bControl         - Value to be written to PM1B control
537a159c266SJung-uk Kim  *
538a159c266SJung-uk Kim  * RETURN:      Status
539a159c266SJung-uk Kim  *
540a159c266SJung-uk Kim  * DESCRIPTION: Write the PM1 A/B control registers. These registers are
541a159c266SJung-uk Kim  *              different than than the PM1 A/B status and enable registers
542a159c266SJung-uk Kim  *              in that different values can be written to the A/B registers.
543a159c266SJung-uk Kim  *              Most notably, the SLP_TYP bits can be different, as per the
544a159c266SJung-uk Kim  *              values returned from the _Sx predefined methods.
545a159c266SJung-uk Kim  *
546a159c266SJung-uk Kim  ******************************************************************************/
547a159c266SJung-uk Kim 
548a159c266SJung-uk Kim ACPI_STATUS
549a159c266SJung-uk Kim AcpiHwWritePm1Control (
550a159c266SJung-uk Kim     UINT32                  Pm1aControl,
551a159c266SJung-uk Kim     UINT32                  Pm1bControl)
552a159c266SJung-uk Kim {
553a159c266SJung-uk Kim     ACPI_STATUS             Status;
554a159c266SJung-uk Kim 
555a159c266SJung-uk Kim 
556a159c266SJung-uk Kim     ACPI_FUNCTION_TRACE (HwWritePm1Control);
557a159c266SJung-uk Kim 
558a159c266SJung-uk Kim 
559a159c266SJung-uk Kim     Status = AcpiHwWrite (Pm1aControl, &AcpiGbl_FADT.XPm1aControlBlock);
560a159c266SJung-uk Kim     if (ACPI_FAILURE (Status))
561a159c266SJung-uk Kim     {
562a159c266SJung-uk Kim         return_ACPI_STATUS (Status);
563a159c266SJung-uk Kim     }
564a159c266SJung-uk Kim 
565a159c266SJung-uk Kim     if (AcpiGbl_FADT.XPm1bControlBlock.Address)
566a159c266SJung-uk Kim     {
567a159c266SJung-uk Kim         Status = AcpiHwWrite (Pm1bControl, &AcpiGbl_FADT.XPm1bControlBlock);
568a159c266SJung-uk Kim     }
569a159c266SJung-uk Kim     return_ACPI_STATUS (Status);
570a159c266SJung-uk Kim }
571a159c266SJung-uk Kim 
572a159c266SJung-uk Kim 
573a159c266SJung-uk Kim /******************************************************************************
574a159c266SJung-uk Kim  *
575a159c266SJung-uk Kim  * FUNCTION:    AcpiHwRegisterRead
576a159c266SJung-uk Kim  *
577a159c266SJung-uk Kim  * PARAMETERS:  RegisterId          - ACPI Register ID
578a159c266SJung-uk Kim  *              ReturnValue         - Where the register value is returned
579a159c266SJung-uk Kim  *
580a159c266SJung-uk Kim  * RETURN:      Status and the value read.
581a159c266SJung-uk Kim  *
582a159c266SJung-uk Kim  * DESCRIPTION: Read from the specified ACPI register
583a159c266SJung-uk Kim  *
584a159c266SJung-uk Kim  ******************************************************************************/
585a159c266SJung-uk Kim 
586a159c266SJung-uk Kim ACPI_STATUS
587a159c266SJung-uk Kim AcpiHwRegisterRead (
588a159c266SJung-uk Kim     UINT32                  RegisterId,
589a159c266SJung-uk Kim     UINT32                  *ReturnValue)
590a159c266SJung-uk Kim {
591a159c266SJung-uk Kim     UINT32                  Value = 0;
592a159c266SJung-uk Kim     ACPI_STATUS             Status;
593a159c266SJung-uk Kim 
594a159c266SJung-uk Kim 
595a159c266SJung-uk Kim     ACPI_FUNCTION_TRACE (HwRegisterRead);
596a159c266SJung-uk Kim 
597a159c266SJung-uk Kim 
598a159c266SJung-uk Kim     switch (RegisterId)
599a159c266SJung-uk Kim     {
600a159c266SJung-uk Kim     case ACPI_REGISTER_PM1_STATUS:           /* PM1 A/B: 16-bit access each */
601a159c266SJung-uk Kim 
602a159c266SJung-uk Kim         Status = AcpiHwReadMultiple (&Value,
603a159c266SJung-uk Kim             &AcpiGbl_XPm1aStatus,
604a159c266SJung-uk Kim             &AcpiGbl_XPm1bStatus);
605a159c266SJung-uk Kim         break;
606a159c266SJung-uk Kim 
607a159c266SJung-uk Kim     case ACPI_REGISTER_PM1_ENABLE:           /* PM1 A/B: 16-bit access each */
608a159c266SJung-uk Kim 
609a159c266SJung-uk Kim         Status = AcpiHwReadMultiple (&Value,
610a159c266SJung-uk Kim             &AcpiGbl_XPm1aEnable,
611a159c266SJung-uk Kim             &AcpiGbl_XPm1bEnable);
612a159c266SJung-uk Kim         break;
613a159c266SJung-uk Kim 
614a159c266SJung-uk Kim     case ACPI_REGISTER_PM1_CONTROL:          /* PM1 A/B: 16-bit access each */
615a159c266SJung-uk Kim 
616a159c266SJung-uk Kim         Status = AcpiHwReadMultiple (&Value,
617a159c266SJung-uk Kim             &AcpiGbl_FADT.XPm1aControlBlock,
618a159c266SJung-uk Kim             &AcpiGbl_FADT.XPm1bControlBlock);
619a159c266SJung-uk Kim 
620a159c266SJung-uk Kim         /*
621a159c266SJung-uk Kim          * Zero the write-only bits. From the ACPI specification, "Hardware
622a159c266SJung-uk Kim          * Write-Only Bits": "Upon reads to registers with write-only bits,
623a159c266SJung-uk Kim          * software masks out all write-only bits."
624a159c266SJung-uk Kim          */
625a159c266SJung-uk Kim         Value &= ~ACPI_PM1_CONTROL_WRITEONLY_BITS;
626a159c266SJung-uk Kim         break;
627a159c266SJung-uk Kim 
628a159c266SJung-uk Kim     case ACPI_REGISTER_PM2_CONTROL:          /* 8-bit access */
629a159c266SJung-uk Kim 
630a159c266SJung-uk Kim         Status = AcpiHwRead (&Value, &AcpiGbl_FADT.XPm2ControlBlock);
631a159c266SJung-uk Kim         break;
632a159c266SJung-uk Kim 
633a159c266SJung-uk Kim     case ACPI_REGISTER_PM_TIMER:             /* 32-bit access */
634a159c266SJung-uk Kim 
635a159c266SJung-uk Kim         Status = AcpiHwRead (&Value, &AcpiGbl_FADT.XPmTimerBlock);
636a159c266SJung-uk Kim         break;
637a159c266SJung-uk Kim 
638a159c266SJung-uk Kim     case ACPI_REGISTER_SMI_COMMAND_BLOCK:    /* 8-bit access */
639a159c266SJung-uk Kim 
640a159c266SJung-uk Kim         Status = AcpiHwReadPort (AcpiGbl_FADT.SmiCommand, &Value, 8);
641a159c266SJung-uk Kim         break;
642a159c266SJung-uk Kim 
643a159c266SJung-uk Kim     default:
644a9d8d09cSJung-uk Kim 
645a159c266SJung-uk Kim         ACPI_ERROR ((AE_INFO, "Unknown Register ID: 0x%X",
646a159c266SJung-uk Kim             RegisterId));
647a159c266SJung-uk Kim         Status = AE_BAD_PARAMETER;
648a159c266SJung-uk Kim         break;
649a159c266SJung-uk Kim     }
650a159c266SJung-uk Kim 
651a159c266SJung-uk Kim     if (ACPI_SUCCESS (Status))
652a159c266SJung-uk Kim     {
653a159c266SJung-uk Kim         *ReturnValue = Value;
654a159c266SJung-uk Kim     }
655a159c266SJung-uk Kim 
656a159c266SJung-uk Kim     return_ACPI_STATUS (Status);
657a159c266SJung-uk Kim }
658a159c266SJung-uk Kim 
659a159c266SJung-uk Kim 
660a159c266SJung-uk Kim /******************************************************************************
661a159c266SJung-uk Kim  *
662a159c266SJung-uk Kim  * FUNCTION:    AcpiHwRegisterWrite
663a159c266SJung-uk Kim  *
664a159c266SJung-uk Kim  * PARAMETERS:  RegisterId          - ACPI Register ID
665a159c266SJung-uk Kim  *              Value               - The value to write
666a159c266SJung-uk Kim  *
667a159c266SJung-uk Kim  * RETURN:      Status
668a159c266SJung-uk Kim  *
669a159c266SJung-uk Kim  * DESCRIPTION: Write to the specified ACPI register
670a159c266SJung-uk Kim  *
671a159c266SJung-uk Kim  * NOTE: In accordance with the ACPI specification, this function automatically
672a159c266SJung-uk Kim  * preserves the value of the following bits, meaning that these bits cannot be
673a159c266SJung-uk Kim  * changed via this interface:
674a159c266SJung-uk Kim  *
675a159c266SJung-uk Kim  * PM1_CONTROL[0] = SCI_EN
676a159c266SJung-uk Kim  * PM1_CONTROL[9]
677a159c266SJung-uk Kim  * PM1_STATUS[11]
678a159c266SJung-uk Kim  *
679a159c266SJung-uk Kim  * ACPI References:
680a159c266SJung-uk Kim  * 1) Hardware Ignored Bits: When software writes to a register with ignored
681a159c266SJung-uk Kim  *      bit fields, it preserves the ignored bit fields
682a159c266SJung-uk Kim  * 2) SCI_EN: OSPM always preserves this bit position
683a159c266SJung-uk Kim  *
684a159c266SJung-uk Kim  ******************************************************************************/
685a159c266SJung-uk Kim 
686a159c266SJung-uk Kim ACPI_STATUS
687a159c266SJung-uk Kim AcpiHwRegisterWrite (
688a159c266SJung-uk Kim     UINT32                  RegisterId,
689a159c266SJung-uk Kim     UINT32                  Value)
690a159c266SJung-uk Kim {
691a159c266SJung-uk Kim     ACPI_STATUS             Status;
692a159c266SJung-uk Kim     UINT32                  ReadValue;
693a159c266SJung-uk Kim 
694a159c266SJung-uk Kim 
695a159c266SJung-uk Kim     ACPI_FUNCTION_TRACE (HwRegisterWrite);
696a159c266SJung-uk Kim 
697a159c266SJung-uk Kim 
698a159c266SJung-uk Kim     switch (RegisterId)
699a159c266SJung-uk Kim     {
700a159c266SJung-uk Kim     case ACPI_REGISTER_PM1_STATUS:           /* PM1 A/B: 16-bit access each */
701a159c266SJung-uk Kim         /*
702a159c266SJung-uk Kim          * Handle the "ignored" bit in PM1 Status. According to the ACPI
703a159c266SJung-uk Kim          * specification, ignored bits are to be preserved when writing.
704a159c266SJung-uk Kim          * Normally, this would mean a read/modify/write sequence. However,
705a159c266SJung-uk Kim          * preserving a bit in the status register is different. Writing a
706a159c266SJung-uk Kim          * one clears the status, and writing a zero preserves the status.
707a159c266SJung-uk Kim          * Therefore, we must always write zero to the ignored bit.
708a159c266SJung-uk Kim          *
709a159c266SJung-uk Kim          * This behavior is clarified in the ACPI 4.0 specification.
710a159c266SJung-uk Kim          */
711a159c266SJung-uk Kim         Value &= ~ACPI_PM1_STATUS_PRESERVED_BITS;
712a159c266SJung-uk Kim 
713a159c266SJung-uk Kim         Status = AcpiHwWriteMultiple (Value,
714a159c266SJung-uk Kim             &AcpiGbl_XPm1aStatus,
715a159c266SJung-uk Kim             &AcpiGbl_XPm1bStatus);
716a159c266SJung-uk Kim         break;
717a159c266SJung-uk Kim 
718a159c266SJung-uk Kim     case ACPI_REGISTER_PM1_ENABLE:           /* PM1 A/B: 16-bit access each */
719a159c266SJung-uk Kim 
720a159c266SJung-uk Kim         Status = AcpiHwWriteMultiple (Value,
721a159c266SJung-uk Kim             &AcpiGbl_XPm1aEnable,
722a159c266SJung-uk Kim             &AcpiGbl_XPm1bEnable);
723a159c266SJung-uk Kim         break;
724a159c266SJung-uk Kim 
725a159c266SJung-uk Kim     case ACPI_REGISTER_PM1_CONTROL:          /* PM1 A/B: 16-bit access each */
726a159c266SJung-uk Kim         /*
727a159c266SJung-uk Kim          * Perform a read first to preserve certain bits (per ACPI spec)
728a159c266SJung-uk Kim          * Note: This includes SCI_EN, we never want to change this bit
729a159c266SJung-uk Kim          */
730a159c266SJung-uk Kim         Status = AcpiHwReadMultiple (&ReadValue,
731a159c266SJung-uk Kim             &AcpiGbl_FADT.XPm1aControlBlock,
732a159c266SJung-uk Kim             &AcpiGbl_FADT.XPm1bControlBlock);
733a159c266SJung-uk Kim         if (ACPI_FAILURE (Status))
734a159c266SJung-uk Kim         {
735a159c266SJung-uk Kim             goto Exit;
736a159c266SJung-uk Kim         }
737a159c266SJung-uk Kim 
738a159c266SJung-uk Kim         /* Insert the bits to be preserved */
739a159c266SJung-uk Kim 
740a159c266SJung-uk Kim         ACPI_INSERT_BITS (Value, ACPI_PM1_CONTROL_PRESERVED_BITS, ReadValue);
741a159c266SJung-uk Kim 
742a159c266SJung-uk Kim         /* Now we can write the data */
743a159c266SJung-uk Kim 
744a159c266SJung-uk Kim         Status = AcpiHwWriteMultiple (Value,
745a159c266SJung-uk Kim             &AcpiGbl_FADT.XPm1aControlBlock,
746a159c266SJung-uk Kim             &AcpiGbl_FADT.XPm1bControlBlock);
747a159c266SJung-uk Kim         break;
748a159c266SJung-uk Kim 
749a159c266SJung-uk Kim     case ACPI_REGISTER_PM2_CONTROL:          /* 8-bit access */
750a159c266SJung-uk Kim         /*
751a159c266SJung-uk Kim          * For control registers, all reserved bits must be preserved,
752a159c266SJung-uk Kim          * as per the ACPI spec.
753a159c266SJung-uk Kim          */
754a159c266SJung-uk Kim         Status = AcpiHwRead (&ReadValue, &AcpiGbl_FADT.XPm2ControlBlock);
755a159c266SJung-uk Kim         if (ACPI_FAILURE (Status))
756a159c266SJung-uk Kim         {
757a159c266SJung-uk Kim             goto Exit;
758a159c266SJung-uk Kim         }
759a159c266SJung-uk Kim 
760a159c266SJung-uk Kim         /* Insert the bits to be preserved */
761a159c266SJung-uk Kim 
762a159c266SJung-uk Kim         ACPI_INSERT_BITS (Value, ACPI_PM2_CONTROL_PRESERVED_BITS, ReadValue);
763a159c266SJung-uk Kim 
764a159c266SJung-uk Kim         Status = AcpiHwWrite (Value, &AcpiGbl_FADT.XPm2ControlBlock);
765a159c266SJung-uk Kim         break;
766a159c266SJung-uk Kim 
767a159c266SJung-uk Kim     case ACPI_REGISTER_PM_TIMER:             /* 32-bit access */
768a159c266SJung-uk Kim 
769a159c266SJung-uk Kim         Status = AcpiHwWrite (Value, &AcpiGbl_FADT.XPmTimerBlock);
770a159c266SJung-uk Kim         break;
771a159c266SJung-uk Kim 
772a159c266SJung-uk Kim     case ACPI_REGISTER_SMI_COMMAND_BLOCK:    /* 8-bit access */
773a159c266SJung-uk Kim 
774a159c266SJung-uk Kim         /* SMI_CMD is currently always in IO space */
775a159c266SJung-uk Kim 
776a159c266SJung-uk Kim         Status = AcpiHwWritePort (AcpiGbl_FADT.SmiCommand, Value, 8);
777a159c266SJung-uk Kim         break;
778a159c266SJung-uk Kim 
779a159c266SJung-uk Kim     default:
780a9d8d09cSJung-uk Kim 
781a159c266SJung-uk Kim         ACPI_ERROR ((AE_INFO, "Unknown Register ID: 0x%X",
782a159c266SJung-uk Kim             RegisterId));
783a159c266SJung-uk Kim         Status = AE_BAD_PARAMETER;
784a159c266SJung-uk Kim         break;
785a159c266SJung-uk Kim     }
786a159c266SJung-uk Kim 
787a159c266SJung-uk Kim Exit:
788a159c266SJung-uk Kim     return_ACPI_STATUS (Status);
789a159c266SJung-uk Kim }
790a159c266SJung-uk Kim 
791a159c266SJung-uk Kim 
792a159c266SJung-uk Kim /******************************************************************************
793a159c266SJung-uk Kim  *
794a159c266SJung-uk Kim  * FUNCTION:    AcpiHwReadMultiple
795a159c266SJung-uk Kim  *
796a159c266SJung-uk Kim  * PARAMETERS:  Value               - Where the register value is returned
797a159c266SJung-uk Kim  *              RegisterA           - First ACPI register (required)
798a159c266SJung-uk Kim  *              RegisterB           - Second ACPI register (optional)
799a159c266SJung-uk Kim  *
800a159c266SJung-uk Kim  * RETURN:      Status
801a159c266SJung-uk Kim  *
802a159c266SJung-uk Kim  * DESCRIPTION: Read from the specified two-part ACPI register (such as PM1 A/B)
803a159c266SJung-uk Kim  *
804a159c266SJung-uk Kim  ******************************************************************************/
805a159c266SJung-uk Kim 
806a159c266SJung-uk Kim static ACPI_STATUS
807a159c266SJung-uk Kim AcpiHwReadMultiple (
808a159c266SJung-uk Kim     UINT32                  *Value,
809a159c266SJung-uk Kim     ACPI_GENERIC_ADDRESS    *RegisterA,
810a159c266SJung-uk Kim     ACPI_GENERIC_ADDRESS    *RegisterB)
811a159c266SJung-uk Kim {
812a159c266SJung-uk Kim     UINT32                  ValueA = 0;
813a159c266SJung-uk Kim     UINT32                  ValueB = 0;
814a159c266SJung-uk Kim     ACPI_STATUS             Status;
815a159c266SJung-uk Kim 
816a159c266SJung-uk Kim 
817a159c266SJung-uk Kim     /* The first register is always required */
818a159c266SJung-uk Kim 
819a159c266SJung-uk Kim     Status = AcpiHwRead (&ValueA, RegisterA);
820a159c266SJung-uk Kim     if (ACPI_FAILURE (Status))
821a159c266SJung-uk Kim     {
822a159c266SJung-uk Kim         return (Status);
823a159c266SJung-uk Kim     }
824a159c266SJung-uk Kim 
825a159c266SJung-uk Kim     /* Second register is optional */
826a159c266SJung-uk Kim 
827a159c266SJung-uk Kim     if (RegisterB->Address)
828a159c266SJung-uk Kim     {
829a159c266SJung-uk Kim         Status = AcpiHwRead (&ValueB, RegisterB);
830a159c266SJung-uk Kim         if (ACPI_FAILURE (Status))
831a159c266SJung-uk Kim         {
832a159c266SJung-uk Kim             return (Status);
833a159c266SJung-uk Kim         }
834a159c266SJung-uk Kim     }
835a159c266SJung-uk Kim 
836a159c266SJung-uk Kim     /*
837a159c266SJung-uk Kim      * OR the two return values together. No shifting or masking is necessary,
838a159c266SJung-uk Kim      * because of how the PM1 registers are defined in the ACPI specification:
839a159c266SJung-uk Kim      *
840a159c266SJung-uk Kim      * "Although the bits can be split between the two register blocks (each
841a159c266SJung-uk Kim      * register block has a unique pointer within the FADT), the bit positions
842a159c266SJung-uk Kim      * are maintained. The register block with unimplemented bits (that is,
843a159c266SJung-uk Kim      * those implemented in the other register block) always returns zeros,
844a159c266SJung-uk Kim      * and writes have no side effects"
845a159c266SJung-uk Kim      */
846a159c266SJung-uk Kim     *Value = (ValueA | ValueB);
847a159c266SJung-uk Kim     return (AE_OK);
848a159c266SJung-uk Kim }
849a159c266SJung-uk Kim 
850a159c266SJung-uk Kim 
851a159c266SJung-uk Kim /******************************************************************************
852a159c266SJung-uk Kim  *
853a159c266SJung-uk Kim  * FUNCTION:    AcpiHwWriteMultiple
854a159c266SJung-uk Kim  *
855a159c266SJung-uk Kim  * PARAMETERS:  Value               - The value to write
856a159c266SJung-uk Kim  *              RegisterA           - First ACPI register (required)
857a159c266SJung-uk Kim  *              RegisterB           - Second ACPI register (optional)
858a159c266SJung-uk Kim  *
859a159c266SJung-uk Kim  * RETURN:      Status
860a159c266SJung-uk Kim  *
861a159c266SJung-uk Kim  * DESCRIPTION: Write to the specified two-part ACPI register (such as PM1 A/B)
862a159c266SJung-uk Kim  *
863a159c266SJung-uk Kim  ******************************************************************************/
864a159c266SJung-uk Kim 
865a159c266SJung-uk Kim static ACPI_STATUS
866a159c266SJung-uk Kim AcpiHwWriteMultiple (
867a159c266SJung-uk Kim     UINT32                  Value,
868a159c266SJung-uk Kim     ACPI_GENERIC_ADDRESS    *RegisterA,
869a159c266SJung-uk Kim     ACPI_GENERIC_ADDRESS    *RegisterB)
870a159c266SJung-uk Kim {
871a159c266SJung-uk Kim     ACPI_STATUS             Status;
872a159c266SJung-uk Kim 
873a159c266SJung-uk Kim 
874a159c266SJung-uk Kim     /* The first register is always required */
875a159c266SJung-uk Kim 
876a159c266SJung-uk Kim     Status = AcpiHwWrite (Value, RegisterA);
877a159c266SJung-uk Kim     if (ACPI_FAILURE (Status))
878a159c266SJung-uk Kim     {
879a159c266SJung-uk Kim         return (Status);
880a159c266SJung-uk Kim     }
881a159c266SJung-uk Kim 
882a159c266SJung-uk Kim     /*
883a159c266SJung-uk Kim      * Second register is optional
884a159c266SJung-uk Kim      *
885a159c266SJung-uk Kim      * No bit shifting or clearing is necessary, because of how the PM1
886a159c266SJung-uk Kim      * registers are defined in the ACPI specification:
887a159c266SJung-uk Kim      *
888a159c266SJung-uk Kim      * "Although the bits can be split between the two register blocks (each
889a159c266SJung-uk Kim      * register block has a unique pointer within the FADT), the bit positions
890a159c266SJung-uk Kim      * are maintained. The register block with unimplemented bits (that is,
891a159c266SJung-uk Kim      * those implemented in the other register block) always returns zeros,
892a159c266SJung-uk Kim      * and writes have no side effects"
893a159c266SJung-uk Kim      */
894a159c266SJung-uk Kim     if (RegisterB->Address)
895a159c266SJung-uk Kim     {
896a159c266SJung-uk Kim         Status = AcpiHwWrite (Value, RegisterB);
897a159c266SJung-uk Kim     }
898a159c266SJung-uk Kim 
899a159c266SJung-uk Kim     return (Status);
900a159c266SJung-uk Kim }
901a159c266SJung-uk Kim 
902a159c266SJung-uk Kim #endif /* !ACPI_REDUCED_HARDWARE */
903