xref: /freebsd/sys/contrib/dev/acpica/components/hardware/hwregs.c (revision a9d8d09c46ec699e45f3fd46ca9abcf02e5baca9)
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 /*
9efcc2a30SJung-uk Kim  * Copyright (C) 2000 - 2013, 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 #define __HWREGS_C__
46a159c266SJung-uk Kim 
47a159c266SJung-uk Kim #include <contrib/dev/acpica/include/acpi.h>
48a159c266SJung-uk Kim #include <contrib/dev/acpica/include/accommon.h>
49a159c266SJung-uk Kim #include <contrib/dev/acpica/include/acevents.h>
50a159c266SJung-uk Kim 
51a159c266SJung-uk Kim #define _COMPONENT          ACPI_HARDWARE
52a159c266SJung-uk Kim         ACPI_MODULE_NAME    ("hwregs")
53a159c266SJung-uk Kim 
54a159c266SJung-uk Kim 
55a159c266SJung-uk Kim #if (!ACPI_REDUCED_HARDWARE)
56a159c266SJung-uk Kim 
57a159c266SJung-uk Kim /* Local Prototypes */
58a159c266SJung-uk Kim 
59a159c266SJung-uk Kim static ACPI_STATUS
60a159c266SJung-uk Kim AcpiHwReadMultiple (
61a159c266SJung-uk Kim     UINT32                  *Value,
62a159c266SJung-uk Kim     ACPI_GENERIC_ADDRESS    *RegisterA,
63a159c266SJung-uk Kim     ACPI_GENERIC_ADDRESS    *RegisterB);
64a159c266SJung-uk Kim 
65a159c266SJung-uk Kim static ACPI_STATUS
66a159c266SJung-uk Kim AcpiHwWriteMultiple (
67a159c266SJung-uk Kim     UINT32                  Value,
68a159c266SJung-uk Kim     ACPI_GENERIC_ADDRESS    *RegisterA,
69a159c266SJung-uk Kim     ACPI_GENERIC_ADDRESS    *RegisterB);
70a159c266SJung-uk Kim 
71a159c266SJung-uk Kim #endif /* !ACPI_REDUCED_HARDWARE */
72a159c266SJung-uk Kim 
73a159c266SJung-uk Kim /******************************************************************************
74a159c266SJung-uk Kim  *
75a159c266SJung-uk Kim  * FUNCTION:    AcpiHwValidateRegister
76a159c266SJung-uk Kim  *
77a159c266SJung-uk Kim  * PARAMETERS:  Reg                 - GAS register structure
78a159c266SJung-uk Kim  *              MaxBitWidth         - Max BitWidth supported (32 or 64)
79a159c266SJung-uk Kim  *              Address             - Pointer to where the gas->address
80a159c266SJung-uk Kim  *                                    is returned
81a159c266SJung-uk Kim  *
82a159c266SJung-uk Kim  * RETURN:      Status
83a159c266SJung-uk Kim  *
84a159c266SJung-uk Kim  * DESCRIPTION: Validate the contents of a GAS register. Checks the GAS
85a159c266SJung-uk Kim  *              pointer, Address, SpaceId, BitWidth, and BitOffset.
86a159c266SJung-uk Kim  *
87a159c266SJung-uk Kim  ******************************************************************************/
88a159c266SJung-uk Kim 
89a159c266SJung-uk Kim ACPI_STATUS
90a159c266SJung-uk Kim AcpiHwValidateRegister (
91a159c266SJung-uk Kim     ACPI_GENERIC_ADDRESS    *Reg,
92a159c266SJung-uk Kim     UINT8                   MaxBitWidth,
93a159c266SJung-uk Kim     UINT64                  *Address)
94a159c266SJung-uk Kim {
95a159c266SJung-uk Kim 
96a159c266SJung-uk Kim     /* Must have a valid pointer to a GAS structure */
97a159c266SJung-uk Kim 
98a159c266SJung-uk Kim     if (!Reg)
99a159c266SJung-uk Kim     {
100a159c266SJung-uk Kim         return (AE_BAD_PARAMETER);
101a159c266SJung-uk Kim     }
102a159c266SJung-uk Kim 
103a159c266SJung-uk Kim     /*
104a159c266SJung-uk Kim      * Copy the target address. This handles possible alignment issues.
105a159c266SJung-uk Kim      * Address must not be null. A null address also indicates an optional
106a159c266SJung-uk Kim      * ACPI register that is not supported, so no error message.
107a159c266SJung-uk Kim      */
108a159c266SJung-uk Kim     ACPI_MOVE_64_TO_64 (Address, &Reg->Address);
109a159c266SJung-uk Kim     if (!(*Address))
110a159c266SJung-uk Kim     {
111a159c266SJung-uk Kim         return (AE_BAD_ADDRESS);
112a159c266SJung-uk Kim     }
113a159c266SJung-uk Kim 
114a159c266SJung-uk Kim     /* Validate the SpaceID */
115a159c266SJung-uk Kim 
116a159c266SJung-uk Kim     if ((Reg->SpaceId != ACPI_ADR_SPACE_SYSTEM_MEMORY) &&
117a159c266SJung-uk Kim         (Reg->SpaceId != ACPI_ADR_SPACE_SYSTEM_IO))
118a159c266SJung-uk Kim     {
119a159c266SJung-uk Kim         ACPI_ERROR ((AE_INFO,
120a159c266SJung-uk Kim             "Unsupported address space: 0x%X", Reg->SpaceId));
121a159c266SJung-uk Kim         return (AE_SUPPORT);
122a159c266SJung-uk Kim     }
123a159c266SJung-uk Kim 
124a159c266SJung-uk Kim     /* Validate the BitWidth */
125a159c266SJung-uk Kim 
126a159c266SJung-uk Kim     if ((Reg->BitWidth != 8) &&
127a159c266SJung-uk Kim         (Reg->BitWidth != 16) &&
128a159c266SJung-uk Kim         (Reg->BitWidth != 32) &&
129a159c266SJung-uk Kim         (Reg->BitWidth != MaxBitWidth))
130a159c266SJung-uk Kim     {
131a159c266SJung-uk Kim         ACPI_ERROR ((AE_INFO,
132a159c266SJung-uk Kim             "Unsupported register bit width: 0x%X", Reg->BitWidth));
133a159c266SJung-uk Kim         return (AE_SUPPORT);
134a159c266SJung-uk Kim     }
135a159c266SJung-uk Kim 
136a159c266SJung-uk Kim     /* Validate the BitOffset. Just a warning for now. */
137a159c266SJung-uk Kim 
138a159c266SJung-uk Kim     if (Reg->BitOffset != 0)
139a159c266SJung-uk Kim     {
140a159c266SJung-uk Kim         ACPI_WARNING ((AE_INFO,
141a159c266SJung-uk Kim             "Unsupported register bit offset: 0x%X", Reg->BitOffset));
142a159c266SJung-uk Kim     }
143a159c266SJung-uk Kim 
144a159c266SJung-uk Kim     return (AE_OK);
145a159c266SJung-uk Kim }
146a159c266SJung-uk Kim 
147a159c266SJung-uk Kim 
148a159c266SJung-uk Kim /******************************************************************************
149a159c266SJung-uk Kim  *
150a159c266SJung-uk Kim  * FUNCTION:    AcpiHwRead
151a159c266SJung-uk Kim  *
152a159c266SJung-uk Kim  * PARAMETERS:  Value               - Where the value is returned
153a159c266SJung-uk Kim  *              Reg                 - GAS register structure
154a159c266SJung-uk Kim  *
155a159c266SJung-uk Kim  * RETURN:      Status
156a159c266SJung-uk Kim  *
157a159c266SJung-uk Kim  * DESCRIPTION: Read from either memory or IO space. This is a 32-bit max
158a159c266SJung-uk Kim  *              version of AcpiRead, used internally since the overhead of
159a159c266SJung-uk Kim  *              64-bit values is not needed.
160a159c266SJung-uk Kim  *
161a159c266SJung-uk Kim  * LIMITATIONS: <These limitations also apply to AcpiHwWrite>
162a159c266SJung-uk Kim  *      BitWidth must be exactly 8, 16, or 32.
163a159c266SJung-uk Kim  *      SpaceID must be SystemMemory or SystemIO.
164a159c266SJung-uk Kim  *      BitOffset and AccessWidth are currently ignored, as there has
165a159c266SJung-uk Kim  *          not been a need to implement these.
166a159c266SJung-uk Kim  *
167a159c266SJung-uk Kim  ******************************************************************************/
168a159c266SJung-uk Kim 
169a159c266SJung-uk Kim ACPI_STATUS
170a159c266SJung-uk Kim AcpiHwRead (
171a159c266SJung-uk Kim     UINT32                  *Value,
172a159c266SJung-uk Kim     ACPI_GENERIC_ADDRESS    *Reg)
173a159c266SJung-uk Kim {
174a159c266SJung-uk Kim     UINT64                  Address;
175a159c266SJung-uk Kim     UINT64                  Value64;
176a159c266SJung-uk Kim     ACPI_STATUS             Status;
177a159c266SJung-uk Kim 
178a159c266SJung-uk Kim 
179a159c266SJung-uk Kim     ACPI_FUNCTION_NAME (HwRead);
180a159c266SJung-uk Kim 
181a159c266SJung-uk Kim 
182a159c266SJung-uk Kim     /* Validate contents of the GAS register */
183a159c266SJung-uk Kim 
184a159c266SJung-uk Kim     Status = AcpiHwValidateRegister (Reg, 32, &Address);
185a159c266SJung-uk Kim     if (ACPI_FAILURE (Status))
186a159c266SJung-uk Kim     {
187a159c266SJung-uk Kim         return (Status);
188a159c266SJung-uk Kim     }
189a159c266SJung-uk Kim 
190a159c266SJung-uk Kim     /* Initialize entire 32-bit return value to zero */
191a159c266SJung-uk Kim 
192a159c266SJung-uk Kim     *Value = 0;
193a159c266SJung-uk Kim 
194a159c266SJung-uk Kim     /*
195a159c266SJung-uk Kim      * Two address spaces supported: Memory or IO. PCI_Config is
196a159c266SJung-uk Kim      * not supported here because the GAS structure is insufficient
197a159c266SJung-uk Kim      */
198a159c266SJung-uk Kim     if (Reg->SpaceId == ACPI_ADR_SPACE_SYSTEM_MEMORY)
199a159c266SJung-uk Kim     {
200a159c266SJung-uk Kim         Status = AcpiOsReadMemory ((ACPI_PHYSICAL_ADDRESS)
201a159c266SJung-uk Kim                     Address, &Value64, Reg->BitWidth);
202a159c266SJung-uk Kim 
203a159c266SJung-uk Kim         *Value = (UINT32) Value64;
204a159c266SJung-uk Kim     }
205a159c266SJung-uk Kim     else /* ACPI_ADR_SPACE_SYSTEM_IO, validated earlier */
206a159c266SJung-uk Kim     {
207a159c266SJung-uk Kim         Status = AcpiHwReadPort ((ACPI_IO_ADDRESS)
208a159c266SJung-uk Kim                     Address, Value, Reg->BitWidth);
209a159c266SJung-uk Kim     }
210a159c266SJung-uk Kim 
211a159c266SJung-uk Kim     ACPI_DEBUG_PRINT ((ACPI_DB_IO,
212a159c266SJung-uk Kim         "Read:  %8.8X width %2d from %8.8X%8.8X (%s)\n",
213a159c266SJung-uk Kim         *Value, Reg->BitWidth, ACPI_FORMAT_UINT64 (Address),
214a159c266SJung-uk Kim         AcpiUtGetRegionName (Reg->SpaceId)));
215a159c266SJung-uk Kim 
216a159c266SJung-uk Kim     return (Status);
217a159c266SJung-uk Kim }
218a159c266SJung-uk Kim 
219a159c266SJung-uk Kim 
220a159c266SJung-uk Kim /******************************************************************************
221a159c266SJung-uk Kim  *
222a159c266SJung-uk Kim  * FUNCTION:    AcpiHwWrite
223a159c266SJung-uk Kim  *
224a159c266SJung-uk Kim  * PARAMETERS:  Value               - Value to be written
225a159c266SJung-uk Kim  *              Reg                 - GAS register structure
226a159c266SJung-uk Kim  *
227a159c266SJung-uk Kim  * RETURN:      Status
228a159c266SJung-uk Kim  *
229a159c266SJung-uk Kim  * DESCRIPTION: Write to either memory or IO space. This is a 32-bit max
230a159c266SJung-uk Kim  *              version of AcpiWrite, used internally since the overhead of
231a159c266SJung-uk Kim  *              64-bit values is not needed.
232a159c266SJung-uk Kim  *
233a159c266SJung-uk Kim  ******************************************************************************/
234a159c266SJung-uk Kim 
235a159c266SJung-uk Kim ACPI_STATUS
236a159c266SJung-uk Kim AcpiHwWrite (
237a159c266SJung-uk Kim     UINT32                  Value,
238a159c266SJung-uk Kim     ACPI_GENERIC_ADDRESS    *Reg)
239a159c266SJung-uk Kim {
240a159c266SJung-uk Kim     UINT64                  Address;
241a159c266SJung-uk Kim     ACPI_STATUS             Status;
242a159c266SJung-uk Kim 
243a159c266SJung-uk Kim 
244a159c266SJung-uk Kim     ACPI_FUNCTION_NAME (HwWrite);
245a159c266SJung-uk Kim 
246a159c266SJung-uk Kim 
247a159c266SJung-uk Kim     /* Validate contents of the GAS register */
248a159c266SJung-uk Kim 
249a159c266SJung-uk Kim     Status = AcpiHwValidateRegister (Reg, 32, &Address);
250a159c266SJung-uk Kim     if (ACPI_FAILURE (Status))
251a159c266SJung-uk Kim     {
252a159c266SJung-uk Kim         return (Status);
253a159c266SJung-uk Kim     }
254a159c266SJung-uk Kim 
255a159c266SJung-uk Kim     /*
256a159c266SJung-uk Kim      * Two address spaces supported: Memory or IO. PCI_Config is
257a159c266SJung-uk Kim      * not supported here because the GAS structure is insufficient
258a159c266SJung-uk Kim      */
259a159c266SJung-uk Kim     if (Reg->SpaceId == ACPI_ADR_SPACE_SYSTEM_MEMORY)
260a159c266SJung-uk Kim     {
261a159c266SJung-uk Kim         Status = AcpiOsWriteMemory ((ACPI_PHYSICAL_ADDRESS)
262a159c266SJung-uk Kim                     Address, (UINT64) Value, Reg->BitWidth);
263a159c266SJung-uk Kim     }
264a159c266SJung-uk Kim     else /* ACPI_ADR_SPACE_SYSTEM_IO, validated earlier */
265a159c266SJung-uk Kim     {
266a159c266SJung-uk Kim         Status = AcpiHwWritePort ((ACPI_IO_ADDRESS)
267a159c266SJung-uk Kim                     Address, Value, Reg->BitWidth);
268a159c266SJung-uk Kim     }
269a159c266SJung-uk Kim 
270a159c266SJung-uk Kim     ACPI_DEBUG_PRINT ((ACPI_DB_IO,
271a159c266SJung-uk Kim         "Wrote: %8.8X width %2d   to %8.8X%8.8X (%s)\n",
272a159c266SJung-uk Kim         Value, Reg->BitWidth, ACPI_FORMAT_UINT64 (Address),
273a159c266SJung-uk Kim         AcpiUtGetRegionName (Reg->SpaceId)));
274a159c266SJung-uk Kim 
275a159c266SJung-uk Kim     return (Status);
276a159c266SJung-uk Kim }
277a159c266SJung-uk Kim 
278a159c266SJung-uk Kim 
279a159c266SJung-uk Kim #if (!ACPI_REDUCED_HARDWARE)
280a159c266SJung-uk Kim /*******************************************************************************
281a159c266SJung-uk Kim  *
282a159c266SJung-uk Kim  * FUNCTION:    AcpiHwClearAcpiStatus
283a159c266SJung-uk Kim  *
284a159c266SJung-uk Kim  * PARAMETERS:  None
285a159c266SJung-uk Kim  *
286a159c266SJung-uk Kim  * RETURN:      Status
287a159c266SJung-uk Kim  *
288a159c266SJung-uk Kim  * DESCRIPTION: Clears all fixed and general purpose status bits
289a159c266SJung-uk Kim  *
290a159c266SJung-uk Kim  ******************************************************************************/
291a159c266SJung-uk Kim 
292a159c266SJung-uk Kim ACPI_STATUS
293a159c266SJung-uk Kim AcpiHwClearAcpiStatus (
294a159c266SJung-uk Kim     void)
295a159c266SJung-uk Kim {
296a159c266SJung-uk Kim     ACPI_STATUS             Status;
297a159c266SJung-uk Kim     ACPI_CPU_FLAGS          LockFlags = 0;
298a159c266SJung-uk Kim 
299a159c266SJung-uk Kim 
300a159c266SJung-uk Kim     ACPI_FUNCTION_TRACE (HwClearAcpiStatus);
301a159c266SJung-uk Kim 
302a159c266SJung-uk Kim 
303a159c266SJung-uk Kim     ACPI_DEBUG_PRINT ((ACPI_DB_IO, "About to write %04X to %8.8X%8.8X\n",
304a159c266SJung-uk Kim         ACPI_BITMASK_ALL_FIXED_STATUS,
305a159c266SJung-uk Kim         ACPI_FORMAT_UINT64 (AcpiGbl_XPm1aStatus.Address)));
306a159c266SJung-uk Kim 
307a159c266SJung-uk Kim     LockFlags = AcpiOsAcquireLock (AcpiGbl_HardwareLock);
308a159c266SJung-uk Kim 
309a159c266SJung-uk Kim     /* Clear the fixed events in PM1 A/B */
310a159c266SJung-uk Kim 
311a159c266SJung-uk Kim     Status = AcpiHwRegisterWrite (ACPI_REGISTER_PM1_STATUS,
312a159c266SJung-uk Kim                 ACPI_BITMASK_ALL_FIXED_STATUS);
313a159c266SJung-uk Kim     if (ACPI_FAILURE (Status))
314a159c266SJung-uk Kim     {
315a159c266SJung-uk Kim         goto UnlockAndExit;
316a159c266SJung-uk Kim     }
317a159c266SJung-uk Kim 
318a159c266SJung-uk Kim     /* Clear the GPE Bits in all GPE registers in all GPE blocks */
319a159c266SJung-uk Kim 
320a159c266SJung-uk Kim     Status = AcpiEvWalkGpeList (AcpiHwClearGpeBlock, NULL);
321a159c266SJung-uk Kim 
322a159c266SJung-uk Kim UnlockAndExit:
323a159c266SJung-uk Kim     AcpiOsReleaseLock (AcpiGbl_HardwareLock, LockFlags);
324a159c266SJung-uk Kim     return_ACPI_STATUS (Status);
325a159c266SJung-uk Kim }
326a159c266SJung-uk Kim 
327a159c266SJung-uk Kim 
328a159c266SJung-uk Kim /*******************************************************************************
329a159c266SJung-uk Kim  *
330a159c266SJung-uk Kim  * FUNCTION:    AcpiHwGetBitRegisterInfo
331a159c266SJung-uk Kim  *
332a159c266SJung-uk Kim  * PARAMETERS:  RegisterId          - Index of ACPI Register to access
333a159c266SJung-uk Kim  *
334a159c266SJung-uk Kim  * RETURN:      The bitmask to be used when accessing the register
335a159c266SJung-uk Kim  *
336a159c266SJung-uk Kim  * DESCRIPTION: Map RegisterId into a register bitmask.
337a159c266SJung-uk Kim  *
338a159c266SJung-uk Kim  ******************************************************************************/
339a159c266SJung-uk Kim 
340a159c266SJung-uk Kim ACPI_BIT_REGISTER_INFO *
341a159c266SJung-uk Kim AcpiHwGetBitRegisterInfo (
342a159c266SJung-uk Kim     UINT32                  RegisterId)
343a159c266SJung-uk Kim {
344a159c266SJung-uk Kim     ACPI_FUNCTION_ENTRY ();
345a159c266SJung-uk Kim 
346a159c266SJung-uk Kim 
347a159c266SJung-uk Kim     if (RegisterId > ACPI_BITREG_MAX)
348a159c266SJung-uk Kim     {
349a159c266SJung-uk Kim         ACPI_ERROR ((AE_INFO, "Invalid BitRegister ID: 0x%X", RegisterId));
350a159c266SJung-uk Kim         return (NULL);
351a159c266SJung-uk Kim     }
352a159c266SJung-uk Kim 
353a159c266SJung-uk Kim     return (&AcpiGbl_BitRegisterInfo[RegisterId]);
354a159c266SJung-uk Kim }
355a159c266SJung-uk Kim 
356a159c266SJung-uk Kim 
357a159c266SJung-uk Kim /******************************************************************************
358a159c266SJung-uk Kim  *
359a159c266SJung-uk Kim  * FUNCTION:    AcpiHwWritePm1Control
360a159c266SJung-uk Kim  *
361a159c266SJung-uk Kim  * PARAMETERS:  Pm1aControl         - Value to be written to PM1A control
362a159c266SJung-uk Kim  *              Pm1bControl         - Value to be written to PM1B control
363a159c266SJung-uk Kim  *
364a159c266SJung-uk Kim  * RETURN:      Status
365a159c266SJung-uk Kim  *
366a159c266SJung-uk Kim  * DESCRIPTION: Write the PM1 A/B control registers. These registers are
367a159c266SJung-uk Kim  *              different than than the PM1 A/B status and enable registers
368a159c266SJung-uk Kim  *              in that different values can be written to the A/B registers.
369a159c266SJung-uk Kim  *              Most notably, the SLP_TYP bits can be different, as per the
370a159c266SJung-uk Kim  *              values returned from the _Sx predefined methods.
371a159c266SJung-uk Kim  *
372a159c266SJung-uk Kim  ******************************************************************************/
373a159c266SJung-uk Kim 
374a159c266SJung-uk Kim ACPI_STATUS
375a159c266SJung-uk Kim AcpiHwWritePm1Control (
376a159c266SJung-uk Kim     UINT32                  Pm1aControl,
377a159c266SJung-uk Kim     UINT32                  Pm1bControl)
378a159c266SJung-uk Kim {
379a159c266SJung-uk Kim     ACPI_STATUS             Status;
380a159c266SJung-uk Kim 
381a159c266SJung-uk Kim 
382a159c266SJung-uk Kim     ACPI_FUNCTION_TRACE (HwWritePm1Control);
383a159c266SJung-uk Kim 
384a159c266SJung-uk Kim 
385a159c266SJung-uk Kim     Status = AcpiHwWrite (Pm1aControl, &AcpiGbl_FADT.XPm1aControlBlock);
386a159c266SJung-uk Kim     if (ACPI_FAILURE (Status))
387a159c266SJung-uk Kim     {
388a159c266SJung-uk Kim         return_ACPI_STATUS (Status);
389a159c266SJung-uk Kim     }
390a159c266SJung-uk Kim 
391a159c266SJung-uk Kim     if (AcpiGbl_FADT.XPm1bControlBlock.Address)
392a159c266SJung-uk Kim     {
393a159c266SJung-uk Kim         Status = AcpiHwWrite (Pm1bControl, &AcpiGbl_FADT.XPm1bControlBlock);
394a159c266SJung-uk Kim     }
395a159c266SJung-uk Kim     return_ACPI_STATUS (Status);
396a159c266SJung-uk Kim }
397a159c266SJung-uk Kim 
398a159c266SJung-uk Kim 
399a159c266SJung-uk Kim /******************************************************************************
400a159c266SJung-uk Kim  *
401a159c266SJung-uk Kim  * FUNCTION:    AcpiHwRegisterRead
402a159c266SJung-uk Kim  *
403a159c266SJung-uk Kim  * PARAMETERS:  RegisterId          - ACPI Register ID
404a159c266SJung-uk Kim  *              ReturnValue         - Where the register value is returned
405a159c266SJung-uk Kim  *
406a159c266SJung-uk Kim  * RETURN:      Status and the value read.
407a159c266SJung-uk Kim  *
408a159c266SJung-uk Kim  * DESCRIPTION: Read from the specified ACPI register
409a159c266SJung-uk Kim  *
410a159c266SJung-uk Kim  ******************************************************************************/
411a159c266SJung-uk Kim 
412a159c266SJung-uk Kim ACPI_STATUS
413a159c266SJung-uk Kim AcpiHwRegisterRead (
414a159c266SJung-uk Kim     UINT32                  RegisterId,
415a159c266SJung-uk Kim     UINT32                  *ReturnValue)
416a159c266SJung-uk Kim {
417a159c266SJung-uk Kim     UINT32                  Value = 0;
418a159c266SJung-uk Kim     ACPI_STATUS             Status;
419a159c266SJung-uk Kim 
420a159c266SJung-uk Kim 
421a159c266SJung-uk Kim     ACPI_FUNCTION_TRACE (HwRegisterRead);
422a159c266SJung-uk Kim 
423a159c266SJung-uk Kim 
424a159c266SJung-uk Kim     switch (RegisterId)
425a159c266SJung-uk Kim     {
426a159c266SJung-uk Kim     case ACPI_REGISTER_PM1_STATUS:           /* PM1 A/B: 16-bit access each */
427a159c266SJung-uk Kim 
428a159c266SJung-uk Kim         Status = AcpiHwReadMultiple (&Value,
429a159c266SJung-uk Kim                     &AcpiGbl_XPm1aStatus,
430a159c266SJung-uk Kim                     &AcpiGbl_XPm1bStatus);
431a159c266SJung-uk Kim         break;
432a159c266SJung-uk Kim 
433a159c266SJung-uk Kim     case ACPI_REGISTER_PM1_ENABLE:           /* PM1 A/B: 16-bit access each */
434a159c266SJung-uk Kim 
435a159c266SJung-uk Kim         Status = AcpiHwReadMultiple (&Value,
436a159c266SJung-uk Kim                     &AcpiGbl_XPm1aEnable,
437a159c266SJung-uk Kim                     &AcpiGbl_XPm1bEnable);
438a159c266SJung-uk Kim         break;
439a159c266SJung-uk Kim 
440a159c266SJung-uk Kim     case ACPI_REGISTER_PM1_CONTROL:          /* PM1 A/B: 16-bit access each */
441a159c266SJung-uk Kim 
442a159c266SJung-uk Kim         Status = AcpiHwReadMultiple (&Value,
443a159c266SJung-uk Kim                     &AcpiGbl_FADT.XPm1aControlBlock,
444a159c266SJung-uk Kim                     &AcpiGbl_FADT.XPm1bControlBlock);
445a159c266SJung-uk Kim 
446a159c266SJung-uk Kim         /*
447a159c266SJung-uk Kim          * Zero the write-only bits. From the ACPI specification, "Hardware
448a159c266SJung-uk Kim          * Write-Only Bits": "Upon reads to registers with write-only bits,
449a159c266SJung-uk Kim          * software masks out all write-only bits."
450a159c266SJung-uk Kim          */
451a159c266SJung-uk Kim         Value &= ~ACPI_PM1_CONTROL_WRITEONLY_BITS;
452a159c266SJung-uk Kim         break;
453a159c266SJung-uk Kim 
454a159c266SJung-uk Kim     case ACPI_REGISTER_PM2_CONTROL:          /* 8-bit access */
455a159c266SJung-uk Kim 
456a159c266SJung-uk Kim         Status = AcpiHwRead (&Value, &AcpiGbl_FADT.XPm2ControlBlock);
457a159c266SJung-uk Kim         break;
458a159c266SJung-uk Kim 
459a159c266SJung-uk Kim     case ACPI_REGISTER_PM_TIMER:             /* 32-bit access */
460a159c266SJung-uk Kim 
461a159c266SJung-uk Kim         Status = AcpiHwRead (&Value, &AcpiGbl_FADT.XPmTimerBlock);
462a159c266SJung-uk Kim         break;
463a159c266SJung-uk Kim 
464a159c266SJung-uk Kim     case ACPI_REGISTER_SMI_COMMAND_BLOCK:    /* 8-bit access */
465a159c266SJung-uk Kim 
466a159c266SJung-uk Kim         Status = AcpiHwReadPort (AcpiGbl_FADT.SmiCommand, &Value, 8);
467a159c266SJung-uk Kim         break;
468a159c266SJung-uk Kim 
469a159c266SJung-uk Kim     default:
470*a9d8d09cSJung-uk Kim 
471a159c266SJung-uk Kim         ACPI_ERROR ((AE_INFO, "Unknown Register ID: 0x%X",
472a159c266SJung-uk Kim             RegisterId));
473a159c266SJung-uk Kim         Status = AE_BAD_PARAMETER;
474a159c266SJung-uk Kim         break;
475a159c266SJung-uk Kim     }
476a159c266SJung-uk Kim 
477a159c266SJung-uk Kim     if (ACPI_SUCCESS (Status))
478a159c266SJung-uk Kim     {
479a159c266SJung-uk Kim         *ReturnValue = Value;
480a159c266SJung-uk Kim     }
481a159c266SJung-uk Kim 
482a159c266SJung-uk Kim     return_ACPI_STATUS (Status);
483a159c266SJung-uk Kim }
484a159c266SJung-uk Kim 
485a159c266SJung-uk Kim 
486a159c266SJung-uk Kim /******************************************************************************
487a159c266SJung-uk Kim  *
488a159c266SJung-uk Kim  * FUNCTION:    AcpiHwRegisterWrite
489a159c266SJung-uk Kim  *
490a159c266SJung-uk Kim  * PARAMETERS:  RegisterId          - ACPI Register ID
491a159c266SJung-uk Kim  *              Value               - The value to write
492a159c266SJung-uk Kim  *
493a159c266SJung-uk Kim  * RETURN:      Status
494a159c266SJung-uk Kim  *
495a159c266SJung-uk Kim  * DESCRIPTION: Write to the specified ACPI register
496a159c266SJung-uk Kim  *
497a159c266SJung-uk Kim  * NOTE: In accordance with the ACPI specification, this function automatically
498a159c266SJung-uk Kim  * preserves the value of the following bits, meaning that these bits cannot be
499a159c266SJung-uk Kim  * changed via this interface:
500a159c266SJung-uk Kim  *
501a159c266SJung-uk Kim  * PM1_CONTROL[0] = SCI_EN
502a159c266SJung-uk Kim  * PM1_CONTROL[9]
503a159c266SJung-uk Kim  * PM1_STATUS[11]
504a159c266SJung-uk Kim  *
505a159c266SJung-uk Kim  * ACPI References:
506a159c266SJung-uk Kim  * 1) Hardware Ignored Bits: When software writes to a register with ignored
507a159c266SJung-uk Kim  *      bit fields, it preserves the ignored bit fields
508a159c266SJung-uk Kim  * 2) SCI_EN: OSPM always preserves this bit position
509a159c266SJung-uk Kim  *
510a159c266SJung-uk Kim  ******************************************************************************/
511a159c266SJung-uk Kim 
512a159c266SJung-uk Kim ACPI_STATUS
513a159c266SJung-uk Kim AcpiHwRegisterWrite (
514a159c266SJung-uk Kim     UINT32                  RegisterId,
515a159c266SJung-uk Kim     UINT32                  Value)
516a159c266SJung-uk Kim {
517a159c266SJung-uk Kim     ACPI_STATUS             Status;
518a159c266SJung-uk Kim     UINT32                  ReadValue;
519a159c266SJung-uk Kim 
520a159c266SJung-uk Kim 
521a159c266SJung-uk Kim     ACPI_FUNCTION_TRACE (HwRegisterWrite);
522a159c266SJung-uk Kim 
523a159c266SJung-uk Kim 
524a159c266SJung-uk Kim     switch (RegisterId)
525a159c266SJung-uk Kim     {
526a159c266SJung-uk Kim     case ACPI_REGISTER_PM1_STATUS:           /* PM1 A/B: 16-bit access each */
527a159c266SJung-uk Kim         /*
528a159c266SJung-uk Kim          * Handle the "ignored" bit in PM1 Status. According to the ACPI
529a159c266SJung-uk Kim          * specification, ignored bits are to be preserved when writing.
530a159c266SJung-uk Kim          * Normally, this would mean a read/modify/write sequence. However,
531a159c266SJung-uk Kim          * preserving a bit in the status register is different. Writing a
532a159c266SJung-uk Kim          * one clears the status, and writing a zero preserves the status.
533a159c266SJung-uk Kim          * Therefore, we must always write zero to the ignored bit.
534a159c266SJung-uk Kim          *
535a159c266SJung-uk Kim          * This behavior is clarified in the ACPI 4.0 specification.
536a159c266SJung-uk Kim          */
537a159c266SJung-uk Kim         Value &= ~ACPI_PM1_STATUS_PRESERVED_BITS;
538a159c266SJung-uk Kim 
539a159c266SJung-uk Kim         Status = AcpiHwWriteMultiple (Value,
540a159c266SJung-uk Kim                     &AcpiGbl_XPm1aStatus,
541a159c266SJung-uk Kim                     &AcpiGbl_XPm1bStatus);
542a159c266SJung-uk Kim         break;
543a159c266SJung-uk Kim 
544a159c266SJung-uk Kim     case ACPI_REGISTER_PM1_ENABLE:           /* PM1 A/B: 16-bit access each */
545a159c266SJung-uk Kim 
546a159c266SJung-uk Kim         Status = AcpiHwWriteMultiple (Value,
547a159c266SJung-uk Kim                     &AcpiGbl_XPm1aEnable,
548a159c266SJung-uk Kim                     &AcpiGbl_XPm1bEnable);
549a159c266SJung-uk Kim         break;
550a159c266SJung-uk Kim 
551a159c266SJung-uk Kim     case ACPI_REGISTER_PM1_CONTROL:          /* PM1 A/B: 16-bit access each */
552a159c266SJung-uk Kim         /*
553a159c266SJung-uk Kim          * Perform a read first to preserve certain bits (per ACPI spec)
554a159c266SJung-uk Kim          * Note: This includes SCI_EN, we never want to change this bit
555a159c266SJung-uk Kim          */
556a159c266SJung-uk Kim         Status = AcpiHwReadMultiple (&ReadValue,
557a159c266SJung-uk Kim                     &AcpiGbl_FADT.XPm1aControlBlock,
558a159c266SJung-uk Kim                     &AcpiGbl_FADT.XPm1bControlBlock);
559a159c266SJung-uk Kim         if (ACPI_FAILURE (Status))
560a159c266SJung-uk Kim         {
561a159c266SJung-uk Kim             goto Exit;
562a159c266SJung-uk Kim         }
563a159c266SJung-uk Kim 
564a159c266SJung-uk Kim         /* Insert the bits to be preserved */
565a159c266SJung-uk Kim 
566a159c266SJung-uk Kim         ACPI_INSERT_BITS (Value, ACPI_PM1_CONTROL_PRESERVED_BITS, ReadValue);
567a159c266SJung-uk Kim 
568a159c266SJung-uk Kim         /* Now we can write the data */
569a159c266SJung-uk Kim 
570a159c266SJung-uk Kim         Status = AcpiHwWriteMultiple (Value,
571a159c266SJung-uk Kim                     &AcpiGbl_FADT.XPm1aControlBlock,
572a159c266SJung-uk Kim                     &AcpiGbl_FADT.XPm1bControlBlock);
573a159c266SJung-uk Kim         break;
574a159c266SJung-uk Kim 
575a159c266SJung-uk Kim     case ACPI_REGISTER_PM2_CONTROL:          /* 8-bit access */
576a159c266SJung-uk Kim         /*
577a159c266SJung-uk Kim          * For control registers, all reserved bits must be preserved,
578a159c266SJung-uk Kim          * as per the ACPI spec.
579a159c266SJung-uk Kim          */
580a159c266SJung-uk Kim         Status = AcpiHwRead (&ReadValue, &AcpiGbl_FADT.XPm2ControlBlock);
581a159c266SJung-uk Kim         if (ACPI_FAILURE (Status))
582a159c266SJung-uk Kim         {
583a159c266SJung-uk Kim             goto Exit;
584a159c266SJung-uk Kim         }
585a159c266SJung-uk Kim 
586a159c266SJung-uk Kim         /* Insert the bits to be preserved */
587a159c266SJung-uk Kim 
588a159c266SJung-uk Kim         ACPI_INSERT_BITS (Value, ACPI_PM2_CONTROL_PRESERVED_BITS, ReadValue);
589a159c266SJung-uk Kim 
590a159c266SJung-uk Kim         Status = AcpiHwWrite (Value, &AcpiGbl_FADT.XPm2ControlBlock);
591a159c266SJung-uk Kim         break;
592a159c266SJung-uk Kim 
593a159c266SJung-uk Kim     case ACPI_REGISTER_PM_TIMER:             /* 32-bit access */
594a159c266SJung-uk Kim 
595a159c266SJung-uk Kim         Status = AcpiHwWrite (Value, &AcpiGbl_FADT.XPmTimerBlock);
596a159c266SJung-uk Kim         break;
597a159c266SJung-uk Kim 
598a159c266SJung-uk Kim     case ACPI_REGISTER_SMI_COMMAND_BLOCK:    /* 8-bit access */
599a159c266SJung-uk Kim 
600a159c266SJung-uk Kim         /* SMI_CMD is currently always in IO space */
601a159c266SJung-uk Kim 
602a159c266SJung-uk Kim         Status = AcpiHwWritePort (AcpiGbl_FADT.SmiCommand, Value, 8);
603a159c266SJung-uk Kim         break;
604a159c266SJung-uk Kim 
605a159c266SJung-uk Kim     default:
606*a9d8d09cSJung-uk Kim 
607a159c266SJung-uk Kim         ACPI_ERROR ((AE_INFO, "Unknown Register ID: 0x%X",
608a159c266SJung-uk Kim             RegisterId));
609a159c266SJung-uk Kim         Status = AE_BAD_PARAMETER;
610a159c266SJung-uk Kim         break;
611a159c266SJung-uk Kim     }
612a159c266SJung-uk Kim 
613a159c266SJung-uk Kim Exit:
614a159c266SJung-uk Kim     return_ACPI_STATUS (Status);
615a159c266SJung-uk Kim }
616a159c266SJung-uk Kim 
617a159c266SJung-uk Kim 
618a159c266SJung-uk Kim /******************************************************************************
619a159c266SJung-uk Kim  *
620a159c266SJung-uk Kim  * FUNCTION:    AcpiHwReadMultiple
621a159c266SJung-uk Kim  *
622a159c266SJung-uk Kim  * PARAMETERS:  Value               - Where the register value is returned
623a159c266SJung-uk Kim  *              RegisterA           - First ACPI register (required)
624a159c266SJung-uk Kim  *              RegisterB           - Second ACPI register (optional)
625a159c266SJung-uk Kim  *
626a159c266SJung-uk Kim  * RETURN:      Status
627a159c266SJung-uk Kim  *
628a159c266SJung-uk Kim  * DESCRIPTION: Read from the specified two-part ACPI register (such as PM1 A/B)
629a159c266SJung-uk Kim  *
630a159c266SJung-uk Kim  ******************************************************************************/
631a159c266SJung-uk Kim 
632a159c266SJung-uk Kim static ACPI_STATUS
633a159c266SJung-uk Kim AcpiHwReadMultiple (
634a159c266SJung-uk Kim     UINT32                  *Value,
635a159c266SJung-uk Kim     ACPI_GENERIC_ADDRESS    *RegisterA,
636a159c266SJung-uk Kim     ACPI_GENERIC_ADDRESS    *RegisterB)
637a159c266SJung-uk Kim {
638a159c266SJung-uk Kim     UINT32                  ValueA = 0;
639a159c266SJung-uk Kim     UINT32                  ValueB = 0;
640a159c266SJung-uk Kim     ACPI_STATUS             Status;
641a159c266SJung-uk Kim 
642a159c266SJung-uk Kim 
643a159c266SJung-uk Kim     /* The first register is always required */
644a159c266SJung-uk Kim 
645a159c266SJung-uk Kim     Status = AcpiHwRead (&ValueA, RegisterA);
646a159c266SJung-uk Kim     if (ACPI_FAILURE (Status))
647a159c266SJung-uk Kim     {
648a159c266SJung-uk Kim         return (Status);
649a159c266SJung-uk Kim     }
650a159c266SJung-uk Kim 
651a159c266SJung-uk Kim     /* Second register is optional */
652a159c266SJung-uk Kim 
653a159c266SJung-uk Kim     if (RegisterB->Address)
654a159c266SJung-uk Kim     {
655a159c266SJung-uk Kim         Status = AcpiHwRead (&ValueB, RegisterB);
656a159c266SJung-uk Kim         if (ACPI_FAILURE (Status))
657a159c266SJung-uk Kim         {
658a159c266SJung-uk Kim             return (Status);
659a159c266SJung-uk Kim         }
660a159c266SJung-uk Kim     }
661a159c266SJung-uk Kim 
662a159c266SJung-uk Kim     /*
663a159c266SJung-uk Kim      * OR the two return values together. No shifting or masking is necessary,
664a159c266SJung-uk Kim      * because of how the PM1 registers are defined in the ACPI specification:
665a159c266SJung-uk Kim      *
666a159c266SJung-uk Kim      * "Although the bits can be split between the two register blocks (each
667a159c266SJung-uk Kim      * register block has a unique pointer within the FADT), the bit positions
668a159c266SJung-uk Kim      * are maintained. The register block with unimplemented bits (that is,
669a159c266SJung-uk Kim      * those implemented in the other register block) always returns zeros,
670a159c266SJung-uk Kim      * and writes have no side effects"
671a159c266SJung-uk Kim      */
672a159c266SJung-uk Kim     *Value = (ValueA | ValueB);
673a159c266SJung-uk Kim     return (AE_OK);
674a159c266SJung-uk Kim }
675a159c266SJung-uk Kim 
676a159c266SJung-uk Kim 
677a159c266SJung-uk Kim /******************************************************************************
678a159c266SJung-uk Kim  *
679a159c266SJung-uk Kim  * FUNCTION:    AcpiHwWriteMultiple
680a159c266SJung-uk Kim  *
681a159c266SJung-uk Kim  * PARAMETERS:  Value               - The value to write
682a159c266SJung-uk Kim  *              RegisterA           - First ACPI register (required)
683a159c266SJung-uk Kim  *              RegisterB           - Second ACPI register (optional)
684a159c266SJung-uk Kim  *
685a159c266SJung-uk Kim  * RETURN:      Status
686a159c266SJung-uk Kim  *
687a159c266SJung-uk Kim  * DESCRIPTION: Write to the specified two-part ACPI register (such as PM1 A/B)
688a159c266SJung-uk Kim  *
689a159c266SJung-uk Kim  ******************************************************************************/
690a159c266SJung-uk Kim 
691a159c266SJung-uk Kim static ACPI_STATUS
692a159c266SJung-uk Kim AcpiHwWriteMultiple (
693a159c266SJung-uk Kim     UINT32                  Value,
694a159c266SJung-uk Kim     ACPI_GENERIC_ADDRESS    *RegisterA,
695a159c266SJung-uk Kim     ACPI_GENERIC_ADDRESS    *RegisterB)
696a159c266SJung-uk Kim {
697a159c266SJung-uk Kim     ACPI_STATUS             Status;
698a159c266SJung-uk Kim 
699a159c266SJung-uk Kim 
700a159c266SJung-uk Kim     /* The first register is always required */
701a159c266SJung-uk Kim 
702a159c266SJung-uk Kim     Status = AcpiHwWrite (Value, RegisterA);
703a159c266SJung-uk Kim     if (ACPI_FAILURE (Status))
704a159c266SJung-uk Kim     {
705a159c266SJung-uk Kim         return (Status);
706a159c266SJung-uk Kim     }
707a159c266SJung-uk Kim 
708a159c266SJung-uk Kim     /*
709a159c266SJung-uk Kim      * Second register is optional
710a159c266SJung-uk Kim      *
711a159c266SJung-uk Kim      * No bit shifting or clearing is necessary, because of how the PM1
712a159c266SJung-uk Kim      * registers are defined in the ACPI specification:
713a159c266SJung-uk Kim      *
714a159c266SJung-uk Kim      * "Although the bits can be split between the two register blocks (each
715a159c266SJung-uk Kim      * register block has a unique pointer within the FADT), the bit positions
716a159c266SJung-uk Kim      * are maintained. The register block with unimplemented bits (that is,
717a159c266SJung-uk Kim      * those implemented in the other register block) always returns zeros,
718a159c266SJung-uk Kim      * and writes have no side effects"
719a159c266SJung-uk Kim      */
720a159c266SJung-uk Kim     if (RegisterB->Address)
721a159c266SJung-uk Kim     {
722a159c266SJung-uk Kim         Status = AcpiHwWrite (Value, RegisterB);
723a159c266SJung-uk Kim     }
724a159c266SJung-uk Kim 
725a159c266SJung-uk Kim     return (Status);
726a159c266SJung-uk Kim }
727a159c266SJung-uk Kim 
728a159c266SJung-uk Kim #endif /* !ACPI_REDUCED_HARDWARE */
729