167754Smsmith/*******************************************************************************
267754Smsmith *
367754Smsmith * Module Name: hwregs - Read/write access functions for the various ACPI
467754Smsmith *                       control and status registers.
567754Smsmith *
667754Smsmith ******************************************************************************/
767754Smsmith
8217365Sjkim/*
9245582Sjkim * Copyright (C) 2000 - 2013, Intel Corp.
1070243Smsmith * All rights reserved.
1167754Smsmith *
12217365Sjkim * Redistribution and use in source and binary forms, with or without
13217365Sjkim * modification, are permitted provided that the following conditions
14217365Sjkim * are met:
15217365Sjkim * 1. Redistributions of source code must retain the above copyright
16217365Sjkim *    notice, this list of conditions, and the following disclaimer,
17217365Sjkim *    without modification.
18217365Sjkim * 2. Redistributions in binary form must reproduce at minimum a disclaimer
19217365Sjkim *    substantially similar to the "NO WARRANTY" disclaimer below
20217365Sjkim *    ("Disclaimer") and any redistribution must be conditioned upon
21217365Sjkim *    including a substantially similar Disclaimer requirement for further
22217365Sjkim *    binary redistribution.
23217365Sjkim * 3. Neither the names of the above-listed copyright holders nor the names
24217365Sjkim *    of any contributors may be used to endorse or promote products derived
25217365Sjkim *    from this software without specific prior written permission.
2667754Smsmith *
27217365Sjkim * Alternatively, this software may be distributed under the terms of the
28217365Sjkim * GNU General Public License ("GPL") version 2 as published by the Free
29217365Sjkim * Software Foundation.
3067754Smsmith *
31217365Sjkim * NO WARRANTY
32217365Sjkim * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
33217365Sjkim * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
34217365Sjkim * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
35217365Sjkim * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
36217365Sjkim * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
37217365Sjkim * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
38217365Sjkim * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
39217365Sjkim * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
40217365Sjkim * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
41217365Sjkim * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
42217365Sjkim * POSSIBILITY OF SUCH DAMAGES.
43217365Sjkim */
4467754Smsmith
4567754Smsmith#define __HWREGS_C__
4667754Smsmith
47193341Sjkim#include <contrib/dev/acpica/include/acpi.h>
48193341Sjkim#include <contrib/dev/acpica/include/accommon.h>
49193341Sjkim#include <contrib/dev/acpica/include/acevents.h>
5067754Smsmith
5177424Smsmith#define _COMPONENT          ACPI_HARDWARE
5291116Smsmith        ACPI_MODULE_NAME    ("hwregs")
5367754Smsmith
5467754Smsmith
55231844Sjkim#if (!ACPI_REDUCED_HARDWARE)
56231844Sjkim
57193267Sjkim/* Local Prototypes */
58193267Sjkim
59193267Sjkimstatic ACPI_STATUS
60193267SjkimAcpiHwReadMultiple (
61193267Sjkim    UINT32                  *Value,
62193267Sjkim    ACPI_GENERIC_ADDRESS    *RegisterA,
63193267Sjkim    ACPI_GENERIC_ADDRESS    *RegisterB);
64193267Sjkim
65193267Sjkimstatic ACPI_STATUS
66193267SjkimAcpiHwWriteMultiple (
67193267Sjkim    UINT32                  Value,
68193267Sjkim    ACPI_GENERIC_ADDRESS    *RegisterA,
69193267Sjkim    ACPI_GENERIC_ADDRESS    *RegisterB);
70193267Sjkim
71231844Sjkim#endif /* !ACPI_REDUCED_HARDWARE */
72193267Sjkim
73197104Sjkim/******************************************************************************
74197104Sjkim *
75197104Sjkim * FUNCTION:    AcpiHwValidateRegister
76197104Sjkim *
77197104Sjkim * PARAMETERS:  Reg                 - GAS register structure
78197104Sjkim *              MaxBitWidth         - Max BitWidth supported (32 or 64)
79197104Sjkim *              Address             - Pointer to where the gas->address
80197104Sjkim *                                    is returned
81197104Sjkim *
82197104Sjkim * RETURN:      Status
83197104Sjkim *
84197104Sjkim * DESCRIPTION: Validate the contents of a GAS register. Checks the GAS
85197104Sjkim *              pointer, Address, SpaceId, BitWidth, and BitOffset.
86197104Sjkim *
87197104Sjkim ******************************************************************************/
88197104Sjkim
89197104SjkimACPI_STATUS
90197104SjkimAcpiHwValidateRegister (
91197104Sjkim    ACPI_GENERIC_ADDRESS    *Reg,
92197104Sjkim    UINT8                   MaxBitWidth,
93197104Sjkim    UINT64                  *Address)
94197104Sjkim{
95197104Sjkim
96197104Sjkim    /* Must have a valid pointer to a GAS structure */
97197104Sjkim
98197104Sjkim    if (!Reg)
99197104Sjkim    {
100197104Sjkim        return (AE_BAD_PARAMETER);
101197104Sjkim    }
102197104Sjkim
103197104Sjkim    /*
104197104Sjkim     * Copy the target address. This handles possible alignment issues.
105197104Sjkim     * Address must not be null. A null address also indicates an optional
106197104Sjkim     * ACPI register that is not supported, so no error message.
107197104Sjkim     */
108197104Sjkim    ACPI_MOVE_64_TO_64 (Address, &Reg->Address);
109197104Sjkim    if (!(*Address))
110197104Sjkim    {
111197104Sjkim        return (AE_BAD_ADDRESS);
112197104Sjkim    }
113197104Sjkim
114197104Sjkim    /* Validate the SpaceID */
115197104Sjkim
116197104Sjkim    if ((Reg->SpaceId != ACPI_ADR_SPACE_SYSTEM_MEMORY) &&
117197104Sjkim        (Reg->SpaceId != ACPI_ADR_SPACE_SYSTEM_IO))
118197104Sjkim    {
119197104Sjkim        ACPI_ERROR ((AE_INFO,
120197104Sjkim            "Unsupported address space: 0x%X", Reg->SpaceId));
121197104Sjkim        return (AE_SUPPORT);
122197104Sjkim    }
123197104Sjkim
124197104Sjkim    /* Validate the BitWidth */
125197104Sjkim
126197104Sjkim    if ((Reg->BitWidth != 8) &&
127197104Sjkim        (Reg->BitWidth != 16) &&
128197104Sjkim        (Reg->BitWidth != 32) &&
129197104Sjkim        (Reg->BitWidth != MaxBitWidth))
130197104Sjkim    {
131197104Sjkim        ACPI_ERROR ((AE_INFO,
132197104Sjkim            "Unsupported register bit width: 0x%X", Reg->BitWidth));
133197104Sjkim        return (AE_SUPPORT);
134197104Sjkim    }
135197104Sjkim
136197104Sjkim    /* Validate the BitOffset. Just a warning for now. */
137197104Sjkim
138197104Sjkim    if (Reg->BitOffset != 0)
139197104Sjkim    {
140197104Sjkim        ACPI_WARNING ((AE_INFO,
141197104Sjkim            "Unsupported register bit offset: 0x%X", Reg->BitOffset));
142197104Sjkim    }
143197104Sjkim
144197104Sjkim    return (AE_OK);
145197104Sjkim}
146197104Sjkim
147197104Sjkim
148197104Sjkim/******************************************************************************
149197104Sjkim *
150197104Sjkim * FUNCTION:    AcpiHwRead
151197104Sjkim *
152197104Sjkim * PARAMETERS:  Value               - Where the value is returned
153197104Sjkim *              Reg                 - GAS register structure
154197104Sjkim *
155197104Sjkim * RETURN:      Status
156197104Sjkim *
157197104Sjkim * DESCRIPTION: Read from either memory or IO space. This is a 32-bit max
158197104Sjkim *              version of AcpiRead, used internally since the overhead of
159197104Sjkim *              64-bit values is not needed.
160197104Sjkim *
161197104Sjkim * LIMITATIONS: <These limitations also apply to AcpiHwWrite>
162197104Sjkim *      BitWidth must be exactly 8, 16, or 32.
163197104Sjkim *      SpaceID must be SystemMemory or SystemIO.
164197104Sjkim *      BitOffset and AccessWidth are currently ignored, as there has
165197104Sjkim *          not been a need to implement these.
166197104Sjkim *
167197104Sjkim ******************************************************************************/
168197104Sjkim
169197104SjkimACPI_STATUS
170197104SjkimAcpiHwRead (
171197104Sjkim    UINT32                  *Value,
172197104Sjkim    ACPI_GENERIC_ADDRESS    *Reg)
173197104Sjkim{
174197104Sjkim    UINT64                  Address;
175231844Sjkim    UINT64                  Value64;
176197104Sjkim    ACPI_STATUS             Status;
177197104Sjkim
178197104Sjkim
179197104Sjkim    ACPI_FUNCTION_NAME (HwRead);
180197104Sjkim
181197104Sjkim
182197104Sjkim    /* Validate contents of the GAS register */
183197104Sjkim
184197104Sjkim    Status = AcpiHwValidateRegister (Reg, 32, &Address);
185197104Sjkim    if (ACPI_FAILURE (Status))
186197104Sjkim    {
187197104Sjkim        return (Status);
188197104Sjkim    }
189197104Sjkim
190197104Sjkim    /* Initialize entire 32-bit return value to zero */
191197104Sjkim
192197104Sjkim    *Value = 0;
193197104Sjkim
194197104Sjkim    /*
195197104Sjkim     * Two address spaces supported: Memory or IO. PCI_Config is
196197104Sjkim     * not supported here because the GAS structure is insufficient
197197104Sjkim     */
198197104Sjkim    if (Reg->SpaceId == ACPI_ADR_SPACE_SYSTEM_MEMORY)
199197104Sjkim    {
200197104Sjkim        Status = AcpiOsReadMemory ((ACPI_PHYSICAL_ADDRESS)
201231844Sjkim                    Address, &Value64, Reg->BitWidth);
202231844Sjkim
203231844Sjkim        *Value = (UINT32) Value64;
204197104Sjkim    }
205197104Sjkim    else /* ACPI_ADR_SPACE_SYSTEM_IO, validated earlier */
206197104Sjkim    {
207197104Sjkim        Status = AcpiHwReadPort ((ACPI_IO_ADDRESS)
208197104Sjkim                    Address, Value, Reg->BitWidth);
209197104Sjkim    }
210197104Sjkim
211197104Sjkim    ACPI_DEBUG_PRINT ((ACPI_DB_IO,
212197104Sjkim        "Read:  %8.8X width %2d from %8.8X%8.8X (%s)\n",
213197104Sjkim        *Value, Reg->BitWidth, ACPI_FORMAT_UINT64 (Address),
214197104Sjkim        AcpiUtGetRegionName (Reg->SpaceId)));
215197104Sjkim
216197104Sjkim    return (Status);
217197104Sjkim}
218197104Sjkim
219197104Sjkim
220197104Sjkim/******************************************************************************
221197104Sjkim *
222197104Sjkim * FUNCTION:    AcpiHwWrite
223197104Sjkim *
224197104Sjkim * PARAMETERS:  Value               - Value to be written
225197104Sjkim *              Reg                 - GAS register structure
226197104Sjkim *
227197104Sjkim * RETURN:      Status
228197104Sjkim *
229197104Sjkim * DESCRIPTION: Write to either memory or IO space. This is a 32-bit max
230197104Sjkim *              version of AcpiWrite, used internally since the overhead of
231197104Sjkim *              64-bit values is not needed.
232197104Sjkim *
233197104Sjkim ******************************************************************************/
234197104Sjkim
235197104SjkimACPI_STATUS
236197104SjkimAcpiHwWrite (
237197104Sjkim    UINT32                  Value,
238197104Sjkim    ACPI_GENERIC_ADDRESS    *Reg)
239197104Sjkim{
240197104Sjkim    UINT64                  Address;
241197104Sjkim    ACPI_STATUS             Status;
242197104Sjkim
243197104Sjkim
244197104Sjkim    ACPI_FUNCTION_NAME (HwWrite);
245197104Sjkim
246197104Sjkim
247197104Sjkim    /* Validate contents of the GAS register */
248197104Sjkim
249197104Sjkim    Status = AcpiHwValidateRegister (Reg, 32, &Address);
250197104Sjkim    if (ACPI_FAILURE (Status))
251197104Sjkim    {
252197104Sjkim        return (Status);
253197104Sjkim    }
254197104Sjkim
255197104Sjkim    /*
256197104Sjkim     * Two address spaces supported: Memory or IO. PCI_Config is
257197104Sjkim     * not supported here because the GAS structure is insufficient
258197104Sjkim     */
259197104Sjkim    if (Reg->SpaceId == ACPI_ADR_SPACE_SYSTEM_MEMORY)
260197104Sjkim    {
261197104Sjkim        Status = AcpiOsWriteMemory ((ACPI_PHYSICAL_ADDRESS)
262231844Sjkim                    Address, (UINT64) Value, Reg->BitWidth);
263197104Sjkim    }
264197104Sjkim    else /* ACPI_ADR_SPACE_SYSTEM_IO, validated earlier */
265197104Sjkim    {
266197104Sjkim        Status = AcpiHwWritePort ((ACPI_IO_ADDRESS)
267197104Sjkim                    Address, Value, Reg->BitWidth);
268197104Sjkim    }
269197104Sjkim
270197104Sjkim    ACPI_DEBUG_PRINT ((ACPI_DB_IO,
271197104Sjkim        "Wrote: %8.8X width %2d   to %8.8X%8.8X (%s)\n",
272197104Sjkim        Value, Reg->BitWidth, ACPI_FORMAT_UINT64 (Address),
273197104Sjkim        AcpiUtGetRegionName (Reg->SpaceId)));
274197104Sjkim
275197104Sjkim    return (Status);
276197104Sjkim}
277197104Sjkim
278197104Sjkim
279231844Sjkim#if (!ACPI_REDUCED_HARDWARE)
28067754Smsmith/*******************************************************************************
28167754Smsmith *
28267754Smsmith * FUNCTION:    AcpiHwClearAcpiStatus
28367754Smsmith *
284167802Sjkim * PARAMETERS:  None
28567754Smsmith *
286193267Sjkim * RETURN:      Status
28767754Smsmith *
28867754Smsmith * DESCRIPTION: Clears all fixed and general purpose status bits
28967754Smsmith *
29067754Smsmith ******************************************************************************/
29167754Smsmith
29299679SiwasakiACPI_STATUS
293117521SnjlAcpiHwClearAcpiStatus (
294167802Sjkim    void)
29567754Smsmith{
29691116Smsmith    ACPI_STATUS             Status;
297167802Sjkim    ACPI_CPU_FLAGS          LockFlags = 0;
29867754Smsmith
29967754Smsmith
300167802Sjkim    ACPI_FUNCTION_TRACE (HwClearAcpiStatus);
30167754Smsmith
30267754Smsmith
303193267Sjkim    ACPI_DEBUG_PRINT ((ACPI_DB_IO, "About to write %04X to %8.8X%8.8X\n",
30491116Smsmith        ACPI_BITMASK_ALL_FIXED_STATUS,
305193267Sjkim        ACPI_FORMAT_UINT64 (AcpiGbl_XPm1aStatus.Address)));
30667754Smsmith
307167802Sjkim    LockFlags = AcpiOsAcquireLock (AcpiGbl_HardwareLock);
30867754Smsmith
309193267Sjkim    /* Clear the fixed events in PM1 A/B */
310193267Sjkim
311193267Sjkim    Status = AcpiHwRegisterWrite (ACPI_REGISTER_PM1_STATUS,
312151937Sjkim                ACPI_BITMASK_ALL_FIXED_STATUS);
31399679Siwasaki    if (ACPI_FAILURE (Status))
31499679Siwasaki    {
31599679Siwasaki        goto UnlockAndExit;
31699679Siwasaki    }
31767754Smsmith
318114237Snjl    /* Clear the GPE Bits in all GPE registers in all GPE blocks */
31967754Smsmith
320193267Sjkim    Status = AcpiEvWalkGpeList (AcpiHwClearGpeBlock, NULL);
321117521Snjl
322117521SnjlUnlockAndExit:
323167802Sjkim    AcpiOsReleaseLock (AcpiGbl_HardwareLock, LockFlags);
32499679Siwasaki    return_ACPI_STATUS (Status);
32567754Smsmith}
32667754Smsmith
32767754Smsmith
32867754Smsmith/*******************************************************************************
32967754Smsmith *
330231844Sjkim * FUNCTION:    AcpiHwGetBitRegisterInfo
33167754Smsmith *
33299679Siwasaki * PARAMETERS:  RegisterId          - Index of ACPI Register to access
333102550Siwasaki *
334151937Sjkim * RETURN:      The bitmask to be used when accessing the register
33591116Smsmith *
336151937Sjkim * DESCRIPTION: Map RegisterId into a register bitmask.
33791116Smsmith *
33891116Smsmith ******************************************************************************/
33991116Smsmith
34091116SmsmithACPI_BIT_REGISTER_INFO *
34191116SmsmithAcpiHwGetBitRegisterInfo (
34291116Smsmith    UINT32                  RegisterId)
34391116Smsmith{
344167802Sjkim    ACPI_FUNCTION_ENTRY ();
34591116Smsmith
34691116Smsmith
34791116Smsmith    if (RegisterId > ACPI_BITREG_MAX)
34891116Smsmith    {
349204773Sjkim        ACPI_ERROR ((AE_INFO, "Invalid BitRegister ID: 0x%X", RegisterId));
35091116Smsmith        return (NULL);
35191116Smsmith    }
35291116Smsmith
35391116Smsmith    return (&AcpiGbl_BitRegisterInfo[RegisterId]);
35491116Smsmith}
35591116Smsmith
35691116Smsmith
357193267Sjkim/******************************************************************************
35891116Smsmith *
359193267Sjkim * FUNCTION:    AcpiHwWritePm1Control
36091116Smsmith *
361193267Sjkim * PARAMETERS:  Pm1aControl         - Value to be written to PM1A control
362193267Sjkim *              Pm1bControl         - Value to be written to PM1B control
36367754Smsmith *
364138287Smarks * RETURN:      Status
36591116Smsmith *
366193267Sjkim * DESCRIPTION: Write the PM1 A/B control registers. These registers are
367193267Sjkim *              different than than the PM1 A/B status and enable registers
368193267Sjkim *              in that different values can be written to the A/B registers.
369193267Sjkim *              Most notably, the SLP_TYP bits can be different, as per the
370193267Sjkim *              values returned from the _Sx predefined methods.
37191116Smsmith *
37291116Smsmith ******************************************************************************/
37367754Smsmith
37499679SiwasakiACPI_STATUS
375193267SjkimAcpiHwWritePm1Control (
376193267Sjkim    UINT32                  Pm1aControl,
377193267Sjkim    UINT32                  Pm1bControl)
37891116Smsmith{
37999679Siwasaki    ACPI_STATUS             Status;
38067754Smsmith
38167754Smsmith
382193267Sjkim    ACPI_FUNCTION_TRACE (HwWritePm1Control);
38367754Smsmith
38467754Smsmith
385197104Sjkim    Status = AcpiHwWrite (Pm1aControl, &AcpiGbl_FADT.XPm1aControlBlock);
38699679Siwasaki    if (ACPI_FAILURE (Status))
38799679Siwasaki    {
388193267Sjkim        return_ACPI_STATUS (Status);
38999679Siwasaki    }
39067754Smsmith
391193267Sjkim    if (AcpiGbl_FADT.XPm1bControlBlock.Address)
39291116Smsmith    {
393197104Sjkim        Status = AcpiHwWrite (Pm1bControl, &AcpiGbl_FADT.XPm1bControlBlock);
39467754Smsmith    }
39599679Siwasaki    return_ACPI_STATUS (Status);
39667754Smsmith}
39769450Smsmith
39869450Smsmith
39969450Smsmith/******************************************************************************
40069450Smsmith *
40169450Smsmith * FUNCTION:    AcpiHwRegisterRead
40269450Smsmith *
403193267Sjkim * PARAMETERS:  RegisterId          - ACPI Register ID
404151937Sjkim *              ReturnValue         - Where the register value is returned
40569450Smsmith *
406138287Smarks * RETURN:      Status and the value read.
40769450Smsmith *
408167802Sjkim * DESCRIPTION: Read from the specified ACPI register
40969450Smsmith *
41069450Smsmith ******************************************************************************/
41169450Smsmith
41299679SiwasakiACPI_STATUS
41369450SmsmithAcpiHwRegisterRead (
41499679Siwasaki    UINT32                  RegisterId,
41599679Siwasaki    UINT32                  *ReturnValue)
41669450Smsmith{
417193267Sjkim    UINT32                  Value = 0;
41899679Siwasaki    ACPI_STATUS             Status;
41969450Smsmith
42077424Smsmith
421167802Sjkim    ACPI_FUNCTION_TRACE (HwRegisterRead);
42269450Smsmith
42377424Smsmith
42491116Smsmith    switch (RegisterId)
42569450Smsmith    {
426193267Sjkim    case ACPI_REGISTER_PM1_STATUS:           /* PM1 A/B: 16-bit access each */
42769450Smsmith
428193267Sjkim        Status = AcpiHwReadMultiple (&Value,
429193267Sjkim                    &AcpiGbl_XPm1aStatus,
430193267Sjkim                    &AcpiGbl_XPm1bStatus);
43169450Smsmith        break;
43269450Smsmith
433193267Sjkim    case ACPI_REGISTER_PM1_ENABLE:           /* PM1 A/B: 16-bit access each */
43469450Smsmith
435193267Sjkim        Status = AcpiHwReadMultiple (&Value,
436193267Sjkim                    &AcpiGbl_XPm1aEnable,
437193267Sjkim                    &AcpiGbl_XPm1bEnable);
43869450Smsmith        break;
43969450Smsmith
440193267Sjkim    case ACPI_REGISTER_PM1_CONTROL:          /* PM1 A/B: 16-bit access each */
44169450Smsmith
442193267Sjkim        Status = AcpiHwReadMultiple (&Value,
443193267Sjkim                    &AcpiGbl_FADT.XPm1aControlBlock,
444193267Sjkim                    &AcpiGbl_FADT.XPm1bControlBlock);
44599679Siwasaki
446193267Sjkim        /*
447193267Sjkim         * Zero the write-only bits. From the ACPI specification, "Hardware
448193267Sjkim         * Write-Only Bits": "Upon reads to registers with write-only bits,
449193267Sjkim         * software masks out all write-only bits."
450193267Sjkim         */
451193267Sjkim        Value &= ~ACPI_PM1_CONTROL_WRITEONLY_BITS;
45269450Smsmith        break;
45369450Smsmith
45491116Smsmith    case ACPI_REGISTER_PM2_CONTROL:          /* 8-bit access */
45569450Smsmith
456197104Sjkim        Status = AcpiHwRead (&Value, &AcpiGbl_FADT.XPm2ControlBlock);
45769450Smsmith        break;
45869450Smsmith
45991116Smsmith    case ACPI_REGISTER_PM_TIMER:             /* 32-bit access */
46069450Smsmith
461197104Sjkim        Status = AcpiHwRead (&Value, &AcpiGbl_FADT.XPmTimerBlock);
46269450Smsmith        break;
46369450Smsmith
46491116Smsmith    case ACPI_REGISTER_SMI_COMMAND_BLOCK:    /* 8-bit access */
46569450Smsmith
466193267Sjkim        Status = AcpiHwReadPort (AcpiGbl_FADT.SmiCommand, &Value, 8);
46769450Smsmith        break;
46869450Smsmith
469250838Sjkim    default:
470193267Sjkim
471204773Sjkim        ACPI_ERROR ((AE_INFO, "Unknown Register ID: 0x%X",
472151937Sjkim            RegisterId));
47399679Siwasaki        Status = AE_BAD_PARAMETER;
47469450Smsmith        break;
47569450Smsmith    }
47669450Smsmith
47799679Siwasaki    if (ACPI_SUCCESS (Status))
47899679Siwasaki    {
479193267Sjkim        *ReturnValue = Value;
48099679Siwasaki    }
48199679Siwasaki
48299679Siwasaki    return_ACPI_STATUS (Status);
48369450Smsmith}
48469450Smsmith
48569450Smsmith
48669450Smsmith/******************************************************************************
48769450Smsmith *
48869450Smsmith * FUNCTION:    AcpiHwRegisterWrite
48969450Smsmith *
490193267Sjkim * PARAMETERS:  RegisterId          - ACPI Register ID
491138287Smarks *              Value               - The value to write
49269450Smsmith *
493138287Smarks * RETURN:      Status
49469450Smsmith *
495167802Sjkim * DESCRIPTION: Write to the specified ACPI register
49669450Smsmith *
497167802Sjkim * NOTE: In accordance with the ACPI specification, this function automatically
498167802Sjkim * preserves the value of the following bits, meaning that these bits cannot be
499167802Sjkim * changed via this interface:
500167802Sjkim *
501167802Sjkim * PM1_CONTROL[0] = SCI_EN
502167802Sjkim * PM1_CONTROL[9]
503167802Sjkim * PM1_STATUS[11]
504167802Sjkim *
505167802Sjkim * ACPI References:
506167802Sjkim * 1) Hardware Ignored Bits: When software writes to a register with ignored
507167802Sjkim *      bit fields, it preserves the ignored bit fields
508167802Sjkim * 2) SCI_EN: OSPM always preserves this bit position
509167802Sjkim *
51069450Smsmith ******************************************************************************/
51169450Smsmith
51299679SiwasakiACPI_STATUS
51369450SmsmithAcpiHwRegisterWrite (
51469450Smsmith    UINT32                  RegisterId,
51569450Smsmith    UINT32                  Value)
51669450Smsmith{
51799679Siwasaki    ACPI_STATUS             Status;
518167802Sjkim    UINT32                  ReadValue;
51969450Smsmith
52069450Smsmith
521167802Sjkim    ACPI_FUNCTION_TRACE (HwRegisterWrite);
52269450Smsmith
52383174Smsmith
52491116Smsmith    switch (RegisterId)
52569450Smsmith    {
526193267Sjkim    case ACPI_REGISTER_PM1_STATUS:           /* PM1 A/B: 16-bit access each */
527193267Sjkim        /*
528193267Sjkim         * Handle the "ignored" bit in PM1 Status. According to the ACPI
529193267Sjkim         * specification, ignored bits are to be preserved when writing.
530193267Sjkim         * Normally, this would mean a read/modify/write sequence. However,
531193267Sjkim         * preserving a bit in the status register is different. Writing a
532193267Sjkim         * one clears the status, and writing a zero preserves the status.
533193267Sjkim         * Therefore, we must always write zero to the ignored bit.
534193267Sjkim         *
535193267Sjkim         * This behavior is clarified in the ACPI 4.0 specification.
536193267Sjkim         */
537193267Sjkim        Value &= ~ACPI_PM1_STATUS_PRESERVED_BITS;
53869450Smsmith
539193267Sjkim        Status = AcpiHwWriteMultiple (Value,
540193267Sjkim                    &AcpiGbl_XPm1aStatus,
541193267Sjkim                    &AcpiGbl_XPm1bStatus);
54269450Smsmith        break;
54369450Smsmith
544193267Sjkim    case ACPI_REGISTER_PM1_ENABLE:           /* PM1 A/B: 16-bit access each */
54569450Smsmith
546193267Sjkim        Status = AcpiHwWriteMultiple (Value,
547193267Sjkim                    &AcpiGbl_XPm1aEnable,
548193267Sjkim                    &AcpiGbl_XPm1bEnable);
54969450Smsmith        break;
55069450Smsmith
551193267Sjkim    case ACPI_REGISTER_PM1_CONTROL:          /* PM1 A/B: 16-bit access each */
552167802Sjkim        /*
553167802Sjkim         * Perform a read first to preserve certain bits (per ACPI spec)
554167802Sjkim         * Note: This includes SCI_EN, we never want to change this bit
555167802Sjkim         */
556193267Sjkim        Status = AcpiHwReadMultiple (&ReadValue,
557193267Sjkim                    &AcpiGbl_FADT.XPm1aControlBlock,
558193267Sjkim                    &AcpiGbl_FADT.XPm1bControlBlock);
55999679Siwasaki        if (ACPI_FAILURE (Status))
56099679Siwasaki        {
561193267Sjkim            goto Exit;
56299679Siwasaki        }
56399679Siwasaki
564167802Sjkim        /* Insert the bits to be preserved */
565167802Sjkim
566167802Sjkim        ACPI_INSERT_BITS (Value, ACPI_PM1_CONTROL_PRESERVED_BITS, ReadValue);
567167802Sjkim
568167802Sjkim        /* Now we can write the data */
569167802Sjkim
570193267Sjkim        Status = AcpiHwWriteMultiple (Value,
571193267Sjkim                    &AcpiGbl_FADT.XPm1aControlBlock,
572193267Sjkim                    &AcpiGbl_FADT.XPm1bControlBlock);
57371867Smsmith        break;
57469450Smsmith
575193267Sjkim    case ACPI_REGISTER_PM2_CONTROL:          /* 8-bit access */
576193267Sjkim        /*
577193267Sjkim         * For control registers, all reserved bits must be preserved,
578193267Sjkim         * as per the ACPI spec.
579193267Sjkim         */
580197104Sjkim        Status = AcpiHwRead (&ReadValue, &AcpiGbl_FADT.XPm2ControlBlock);
581193267Sjkim        if (ACPI_FAILURE (Status))
582193267Sjkim        {
583193267Sjkim            goto Exit;
584193267Sjkim        }
58569450Smsmith
586193267Sjkim        /* Insert the bits to be preserved */
58769450Smsmith
588193267Sjkim        ACPI_INSERT_BITS (Value, ACPI_PM2_CONTROL_PRESERVED_BITS, ReadValue);
58971867Smsmith
590197104Sjkim        Status = AcpiHwWrite (Value, &AcpiGbl_FADT.XPm2ControlBlock);
59171867Smsmith        break;
59271867Smsmith
59391116Smsmith    case ACPI_REGISTER_PM_TIMER:             /* 32-bit access */
59469450Smsmith
595197104Sjkim        Status = AcpiHwWrite (Value, &AcpiGbl_FADT.XPmTimerBlock);
59669450Smsmith        break;
59769450Smsmith
59891116Smsmith    case ACPI_REGISTER_SMI_COMMAND_BLOCK:    /* 8-bit access */
59969450Smsmith
60091116Smsmith        /* SMI_CMD is currently always in IO space */
60169450Smsmith
602193267Sjkim        Status = AcpiHwWritePort (AcpiGbl_FADT.SmiCommand, Value, 8);
60369450Smsmith        break;
60469450Smsmith
605250838Sjkim    default:
60669450Smsmith
607204773Sjkim        ACPI_ERROR ((AE_INFO, "Unknown Register ID: 0x%X",
608193267Sjkim            RegisterId));
60999679Siwasaki        Status = AE_BAD_PARAMETER;
61069450Smsmith        break;
61169450Smsmith    }
61269450Smsmith
613193267SjkimExit:
61499679Siwasaki    return_ACPI_STATUS (Status);
61569450Smsmith}
61669450Smsmith
61769450Smsmith
61869450Smsmith/******************************************************************************
61969450Smsmith *
620193267Sjkim * FUNCTION:    AcpiHwReadMultiple
62169450Smsmith *
622193267Sjkim * PARAMETERS:  Value               - Where the register value is returned
623193267Sjkim *              RegisterA           - First ACPI register (required)
624193267Sjkim *              RegisterB           - Second ACPI register (optional)
62569450Smsmith *
626117521Snjl * RETURN:      Status
62769450Smsmith *
628193267Sjkim * DESCRIPTION: Read from the specified two-part ACPI register (such as PM1 A/B)
62969450Smsmith *
63069450Smsmith ******************************************************************************/
63169450Smsmith
632193267Sjkimstatic ACPI_STATUS
633193267SjkimAcpiHwReadMultiple (
63499679Siwasaki    UINT32                  *Value,
635193267Sjkim    ACPI_GENERIC_ADDRESS    *RegisterA,
636193267Sjkim    ACPI_GENERIC_ADDRESS    *RegisterB)
63769450Smsmith{
638193267Sjkim    UINT32                  ValueA = 0;
639193267Sjkim    UINT32                  ValueB = 0;
64099679Siwasaki    ACPI_STATUS             Status;
64169450Smsmith
64269450Smsmith
643193267Sjkim    /* The first register is always required */
64483174Smsmith
645197104Sjkim    Status = AcpiHwRead (&ValueA, RegisterA);
646193267Sjkim    if (ACPI_FAILURE (Status))
64769450Smsmith    {
648193267Sjkim        return (Status);
64969450Smsmith    }
650138287Smarks
651193267Sjkim    /* Second register is optional */
652138287Smarks
653193267Sjkim    if (RegisterB->Address)
654138287Smarks    {
655197104Sjkim        Status = AcpiHwRead (&ValueB, RegisterB);
656193267Sjkim        if (ACPI_FAILURE (Status))
657193267Sjkim        {
658193267Sjkim            return (Status);
659193267Sjkim        }
660138287Smarks    }
66169450Smsmith
66269450Smsmith    /*
663193267Sjkim     * OR the two return values together. No shifting or masking is necessary,
664193267Sjkim     * because of how the PM1 registers are defined in the ACPI specification:
665193267Sjkim     *
666193267Sjkim     * "Although the bits can be split between the two register blocks (each
667193267Sjkim     * register block has a unique pointer within the FADT), the bit positions
668193267Sjkim     * are maintained. The register block with unimplemented bits (that is,
669193267Sjkim     * those implemented in the other register block) always returns zeros,
670193267Sjkim     * and writes have no side effects"
67169450Smsmith     */
672193267Sjkim    *Value = (ValueA | ValueB);
673193267Sjkim    return (AE_OK);
67469450Smsmith}
67569450Smsmith
67669450Smsmith
67769450Smsmith/******************************************************************************
67869450Smsmith *
679193267Sjkim * FUNCTION:    AcpiHwWriteMultiple
68069450Smsmith *
681193267Sjkim * PARAMETERS:  Value               - The value to write
682193267Sjkim *              RegisterA           - First ACPI register (required)
683193267Sjkim *              RegisterB           - Second ACPI register (optional)
68469450Smsmith *
685117521Snjl * RETURN:      Status
68669450Smsmith *
687193267Sjkim * DESCRIPTION: Write to the specified two-part ACPI register (such as PM1 A/B)
68869450Smsmith *
68969450Smsmith ******************************************************************************/
69069450Smsmith
691193267Sjkimstatic ACPI_STATUS
692193267SjkimAcpiHwWriteMultiple (
69369450Smsmith    UINT32                  Value,
694193267Sjkim    ACPI_GENERIC_ADDRESS    *RegisterA,
695193267Sjkim    ACPI_GENERIC_ADDRESS    *RegisterB)
69669450Smsmith{
69799679Siwasaki    ACPI_STATUS             Status;
69869450Smsmith
69969450Smsmith
700193267Sjkim    /* The first register is always required */
70183174Smsmith
702197104Sjkim    Status = AcpiHwWrite (Value, RegisterA);
703193267Sjkim    if (ACPI_FAILURE (Status))
70469450Smsmith    {
705193267Sjkim        return (Status);
70669450Smsmith    }
707123315Snjl
70869450Smsmith    /*
709193267Sjkim     * Second register is optional
710193267Sjkim     *
711193267Sjkim     * No bit shifting or clearing is necessary, because of how the PM1
712193267Sjkim     * registers are defined in the ACPI specification:
713193267Sjkim     *
714193267Sjkim     * "Although the bits can be split between the two register blocks (each
715193267Sjkim     * register block has a unique pointer within the FADT), the bit positions
716193267Sjkim     * are maintained. The register block with unimplemented bits (that is,
717193267Sjkim     * those implemented in the other register block) always returns zeros,
718193267Sjkim     * and writes have no side effects"
71969450Smsmith     */
720193267Sjkim    if (RegisterB->Address)
72169450Smsmith    {
722197104Sjkim        Status = AcpiHwWrite (Value, RegisterB);
72369450Smsmith    }
72499679Siwasaki
72599679Siwasaki    return (Status);
72669450Smsmith}
727193267Sjkim
728231844Sjkim#endif /* !ACPI_REDUCED_HARDWARE */
729