167754Smsmith/*******************************************************************************
267754Smsmith *
367754Smsmith * Module Name: hwregs - Read/write access functions for the various ACPI
467754Smsmith *                       control and status registers.
567754Smsmith *
667754Smsmith ******************************************************************************/
767754Smsmith
8217365Sjkim/*
9306536Sjkim * Copyright (C) 2000 - 2016, 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
45193341Sjkim#include <contrib/dev/acpica/include/acpi.h>
46193341Sjkim#include <contrib/dev/acpica/include/accommon.h>
47193341Sjkim#include <contrib/dev/acpica/include/acevents.h>
4867754Smsmith
4977424Smsmith#define _COMPONENT          ACPI_HARDWARE
5091116Smsmith        ACPI_MODULE_NAME    ("hwregs")
5167754Smsmith
5267754Smsmith
53231844Sjkim#if (!ACPI_REDUCED_HARDWARE)
54231844Sjkim
55193267Sjkim/* Local Prototypes */
56193267Sjkim
57193267Sjkimstatic ACPI_STATUS
58193267SjkimAcpiHwReadMultiple (
59193267Sjkim    UINT32                  *Value,
60193267Sjkim    ACPI_GENERIC_ADDRESS    *RegisterA,
61193267Sjkim    ACPI_GENERIC_ADDRESS    *RegisterB);
62193267Sjkim
63193267Sjkimstatic ACPI_STATUS
64193267SjkimAcpiHwWriteMultiple (
65193267Sjkim    UINT32                  Value,
66193267Sjkim    ACPI_GENERIC_ADDRESS    *RegisterA,
67193267Sjkim    ACPI_GENERIC_ADDRESS    *RegisterB);
68193267Sjkim
69231844Sjkim#endif /* !ACPI_REDUCED_HARDWARE */
70193267Sjkim
71306536Sjkim
72197104Sjkim/******************************************************************************
73197104Sjkim *
74197104Sjkim * FUNCTION:    AcpiHwValidateRegister
75197104Sjkim *
76197104Sjkim * PARAMETERS:  Reg                 - GAS register structure
77197104Sjkim *              MaxBitWidth         - Max BitWidth supported (32 or 64)
78197104Sjkim *              Address             - Pointer to where the gas->address
79197104Sjkim *                                    is returned
80197104Sjkim *
81197104Sjkim * RETURN:      Status
82197104Sjkim *
83197104Sjkim * DESCRIPTION: Validate the contents of a GAS register. Checks the GAS
84197104Sjkim *              pointer, Address, SpaceId, BitWidth, and BitOffset.
85197104Sjkim *
86197104Sjkim ******************************************************************************/
87197104Sjkim
88197104SjkimACPI_STATUS
89197104SjkimAcpiHwValidateRegister (
90197104Sjkim    ACPI_GENERIC_ADDRESS    *Reg,
91197104Sjkim    UINT8                   MaxBitWidth,
92197104Sjkim    UINT64                  *Address)
93197104Sjkim{
94197104Sjkim
95197104Sjkim    /* Must have a valid pointer to a GAS structure */
96197104Sjkim
97197104Sjkim    if (!Reg)
98197104Sjkim    {
99197104Sjkim        return (AE_BAD_PARAMETER);
100197104Sjkim    }
101197104Sjkim
102197104Sjkim    /*
103197104Sjkim     * Copy the target address. This handles possible alignment issues.
104197104Sjkim     * Address must not be null. A null address also indicates an optional
105197104Sjkim     * ACPI register that is not supported, so no error message.
106197104Sjkim     */
107197104Sjkim    ACPI_MOVE_64_TO_64 (Address, &Reg->Address);
108197104Sjkim    if (!(*Address))
109197104Sjkim    {
110197104Sjkim        return (AE_BAD_ADDRESS);
111197104Sjkim    }
112197104Sjkim
113197104Sjkim    /* Validate the SpaceID */
114197104Sjkim
115197104Sjkim    if ((Reg->SpaceId != ACPI_ADR_SPACE_SYSTEM_MEMORY) &&
116197104Sjkim        (Reg->SpaceId != ACPI_ADR_SPACE_SYSTEM_IO))
117197104Sjkim    {
118197104Sjkim        ACPI_ERROR ((AE_INFO,
119197104Sjkim            "Unsupported address space: 0x%X", Reg->SpaceId));
120197104Sjkim        return (AE_SUPPORT);
121197104Sjkim    }
122197104Sjkim
123197104Sjkim    /* Validate the BitWidth */
124197104Sjkim
125197104Sjkim    if ((Reg->BitWidth != 8) &&
126197104Sjkim        (Reg->BitWidth != 16) &&
127197104Sjkim        (Reg->BitWidth != 32) &&
128197104Sjkim        (Reg->BitWidth != MaxBitWidth))
129197104Sjkim    {
130197104Sjkim        ACPI_ERROR ((AE_INFO,
131197104Sjkim            "Unsupported register bit width: 0x%X", Reg->BitWidth));
132197104Sjkim        return (AE_SUPPORT);
133197104Sjkim    }
134197104Sjkim
135197104Sjkim    /* Validate the BitOffset. Just a warning for now. */
136197104Sjkim
137197104Sjkim    if (Reg->BitOffset != 0)
138197104Sjkim    {
139197104Sjkim        ACPI_WARNING ((AE_INFO,
140197104Sjkim            "Unsupported register bit offset: 0x%X", Reg->BitOffset));
141197104Sjkim    }
142197104Sjkim
143197104Sjkim    return (AE_OK);
144197104Sjkim}
145197104Sjkim
146197104Sjkim
147197104Sjkim/******************************************************************************
148197104Sjkim *
149197104Sjkim * FUNCTION:    AcpiHwRead
150197104Sjkim *
151197104Sjkim * PARAMETERS:  Value               - Where the value is returned
152197104Sjkim *              Reg                 - GAS register structure
153197104Sjkim *
154197104Sjkim * RETURN:      Status
155197104Sjkim *
156197104Sjkim * DESCRIPTION: Read from either memory or IO space. This is a 32-bit max
157197104Sjkim *              version of AcpiRead, used internally since the overhead of
158197104Sjkim *              64-bit values is not needed.
159197104Sjkim *
160197104Sjkim * LIMITATIONS: <These limitations also apply to AcpiHwWrite>
161197104Sjkim *      BitWidth must be exactly 8, 16, or 32.
162197104Sjkim *      SpaceID must be SystemMemory or SystemIO.
163197104Sjkim *      BitOffset and AccessWidth are currently ignored, as there has
164197104Sjkim *          not been a need to implement these.
165197104Sjkim *
166197104Sjkim ******************************************************************************/
167197104Sjkim
168197104SjkimACPI_STATUS
169197104SjkimAcpiHwRead (
170197104Sjkim    UINT32                  *Value,
171197104Sjkim    ACPI_GENERIC_ADDRESS    *Reg)
172197104Sjkim{
173197104Sjkim    UINT64                  Address;
174231844Sjkim    UINT64                  Value64;
175197104Sjkim    ACPI_STATUS             Status;
176197104Sjkim
177197104Sjkim
178197104Sjkim    ACPI_FUNCTION_NAME (HwRead);
179197104Sjkim
180197104Sjkim
181197104Sjkim    /* Validate contents of the GAS register */
182197104Sjkim
183197104Sjkim    Status = AcpiHwValidateRegister (Reg, 32, &Address);
184197104Sjkim    if (ACPI_FAILURE (Status))
185197104Sjkim    {
186197104Sjkim        return (Status);
187197104Sjkim    }
188197104Sjkim
189197104Sjkim    /* Initialize entire 32-bit return value to zero */
190197104Sjkim
191197104Sjkim    *Value = 0;
192197104Sjkim
193197104Sjkim    /*
194197104Sjkim     * Two address spaces supported: Memory or IO. PCI_Config is
195197104Sjkim     * not supported here because the GAS structure is insufficient
196197104Sjkim     */
197197104Sjkim    if (Reg->SpaceId == ACPI_ADR_SPACE_SYSTEM_MEMORY)
198197104Sjkim    {
199197104Sjkim        Status = AcpiOsReadMemory ((ACPI_PHYSICAL_ADDRESS)
200306536Sjkim            Address, &Value64, Reg->BitWidth);
201231844Sjkim
202231844Sjkim        *Value = (UINT32) Value64;
203197104Sjkim    }
204197104Sjkim    else /* ACPI_ADR_SPACE_SYSTEM_IO, validated earlier */
205197104Sjkim    {
206197104Sjkim        Status = AcpiHwReadPort ((ACPI_IO_ADDRESS)
207306536Sjkim            Address, Value, Reg->BitWidth);
208197104Sjkim    }
209197104Sjkim
210197104Sjkim    ACPI_DEBUG_PRINT ((ACPI_DB_IO,
211197104Sjkim        "Read:  %8.8X width %2d from %8.8X%8.8X (%s)\n",
212197104Sjkim        *Value, Reg->BitWidth, ACPI_FORMAT_UINT64 (Address),
213197104Sjkim        AcpiUtGetRegionName (Reg->SpaceId)));
214197104Sjkim
215197104Sjkim    return (Status);
216197104Sjkim}
217197104Sjkim
218197104Sjkim
219197104Sjkim/******************************************************************************
220197104Sjkim *
221197104Sjkim * FUNCTION:    AcpiHwWrite
222197104Sjkim *
223197104Sjkim * PARAMETERS:  Value               - Value to be written
224197104Sjkim *              Reg                 - GAS register structure
225197104Sjkim *
226197104Sjkim * RETURN:      Status
227197104Sjkim *
228197104Sjkim * DESCRIPTION: Write to either memory or IO space. This is a 32-bit max
229197104Sjkim *              version of AcpiWrite, used internally since the overhead of
230197104Sjkim *              64-bit values is not needed.
231197104Sjkim *
232197104Sjkim ******************************************************************************/
233197104Sjkim
234197104SjkimACPI_STATUS
235197104SjkimAcpiHwWrite (
236197104Sjkim    UINT32                  Value,
237197104Sjkim    ACPI_GENERIC_ADDRESS    *Reg)
238197104Sjkim{
239197104Sjkim    UINT64                  Address;
240197104Sjkim    ACPI_STATUS             Status;
241197104Sjkim
242197104Sjkim
243197104Sjkim    ACPI_FUNCTION_NAME (HwWrite);
244197104Sjkim
245197104Sjkim
246197104Sjkim    /* Validate contents of the GAS register */
247197104Sjkim
248197104Sjkim    Status = AcpiHwValidateRegister (Reg, 32, &Address);
249197104Sjkim    if (ACPI_FAILURE (Status))
250197104Sjkim    {
251197104Sjkim        return (Status);
252197104Sjkim    }
253197104Sjkim
254197104Sjkim    /*
255197104Sjkim     * Two address spaces supported: Memory or IO. PCI_Config is
256197104Sjkim     * not supported here because the GAS structure is insufficient
257197104Sjkim     */
258197104Sjkim    if (Reg->SpaceId == ACPI_ADR_SPACE_SYSTEM_MEMORY)
259197104Sjkim    {
260197104Sjkim        Status = AcpiOsWriteMemory ((ACPI_PHYSICAL_ADDRESS)
261306536Sjkim            Address, (UINT64) Value, Reg->BitWidth);
262197104Sjkim    }
263197104Sjkim    else /* ACPI_ADR_SPACE_SYSTEM_IO, validated earlier */
264197104Sjkim    {
265197104Sjkim        Status = AcpiHwWritePort ((ACPI_IO_ADDRESS)
266306536Sjkim            Address, Value, Reg->BitWidth);
267197104Sjkim    }
268197104Sjkim
269197104Sjkim    ACPI_DEBUG_PRINT ((ACPI_DB_IO,
270197104Sjkim        "Wrote: %8.8X width %2d   to %8.8X%8.8X (%s)\n",
271197104Sjkim        Value, Reg->BitWidth, ACPI_FORMAT_UINT64 (Address),
272197104Sjkim        AcpiUtGetRegionName (Reg->SpaceId)));
273197104Sjkim
274197104Sjkim    return (Status);
275197104Sjkim}
276197104Sjkim
277197104Sjkim
278231844Sjkim#if (!ACPI_REDUCED_HARDWARE)
27967754Smsmith/*******************************************************************************
28067754Smsmith *
28167754Smsmith * FUNCTION:    AcpiHwClearAcpiStatus
28267754Smsmith *
283167802Sjkim * PARAMETERS:  None
28467754Smsmith *
285193267Sjkim * RETURN:      Status
28667754Smsmith *
28767754Smsmith * DESCRIPTION: Clears all fixed and general purpose status bits
28867754Smsmith *
28967754Smsmith ******************************************************************************/
29067754Smsmith
29199679SiwasakiACPI_STATUS
292117521SnjlAcpiHwClearAcpiStatus (
293167802Sjkim    void)
29467754Smsmith{
29591116Smsmith    ACPI_STATUS             Status;
296167802Sjkim    ACPI_CPU_FLAGS          LockFlags = 0;
29767754Smsmith
29867754Smsmith
299167802Sjkim    ACPI_FUNCTION_TRACE (HwClearAcpiStatus);
30067754Smsmith
30167754Smsmith
302193267Sjkim    ACPI_DEBUG_PRINT ((ACPI_DB_IO, "About to write %04X to %8.8X%8.8X\n",
30391116Smsmith        ACPI_BITMASK_ALL_FIXED_STATUS,
304193267Sjkim        ACPI_FORMAT_UINT64 (AcpiGbl_XPm1aStatus.Address)));
30567754Smsmith
306167802Sjkim    LockFlags = AcpiOsAcquireLock (AcpiGbl_HardwareLock);
30767754Smsmith
308193267Sjkim    /* Clear the fixed events in PM1 A/B */
309193267Sjkim
310193267Sjkim    Status = AcpiHwRegisterWrite (ACPI_REGISTER_PM1_STATUS,
311306536Sjkim        ACPI_BITMASK_ALL_FIXED_STATUS);
312281075Sdim
313281075Sdim    AcpiOsReleaseLock (AcpiGbl_HardwareLock, LockFlags);
314281075Sdim
31599679Siwasaki    if (ACPI_FAILURE (Status))
31699679Siwasaki    {
317281075Sdim        goto Exit;
31899679Siwasaki    }
31967754Smsmith
320114237Snjl    /* Clear the GPE Bits in all GPE registers in all GPE blocks */
32167754Smsmith
322193267Sjkim    Status = AcpiEvWalkGpeList (AcpiHwClearGpeBlock, NULL);
323117521Snjl
324281075SdimExit:
32599679Siwasaki    return_ACPI_STATUS (Status);
32667754Smsmith}
32767754Smsmith
32867754Smsmith
32967754Smsmith/*******************************************************************************
33067754Smsmith *
331231844Sjkim * FUNCTION:    AcpiHwGetBitRegisterInfo
33267754Smsmith *
33399679Siwasaki * PARAMETERS:  RegisterId          - Index of ACPI Register to access
334102550Siwasaki *
335151937Sjkim * RETURN:      The bitmask to be used when accessing the register
33691116Smsmith *
337151937Sjkim * DESCRIPTION: Map RegisterId into a register bitmask.
33891116Smsmith *
33991116Smsmith ******************************************************************************/
34091116Smsmith
34191116SmsmithACPI_BIT_REGISTER_INFO *
34291116SmsmithAcpiHwGetBitRegisterInfo (
34391116Smsmith    UINT32                  RegisterId)
34491116Smsmith{
345167802Sjkim    ACPI_FUNCTION_ENTRY ();
34691116Smsmith
34791116Smsmith
34891116Smsmith    if (RegisterId > ACPI_BITREG_MAX)
34991116Smsmith    {
350204773Sjkim        ACPI_ERROR ((AE_INFO, "Invalid BitRegister ID: 0x%X", RegisterId));
35191116Smsmith        return (NULL);
35291116Smsmith    }
35391116Smsmith
35491116Smsmith    return (&AcpiGbl_BitRegisterInfo[RegisterId]);
35591116Smsmith}
35691116Smsmith
35791116Smsmith
358193267Sjkim/******************************************************************************
35991116Smsmith *
360193267Sjkim * FUNCTION:    AcpiHwWritePm1Control
36191116Smsmith *
362193267Sjkim * PARAMETERS:  Pm1aControl         - Value to be written to PM1A control
363193267Sjkim *              Pm1bControl         - Value to be written to PM1B control
36467754Smsmith *
365138287Smarks * RETURN:      Status
36691116Smsmith *
367193267Sjkim * DESCRIPTION: Write the PM1 A/B control registers. These registers are
368193267Sjkim *              different than than the PM1 A/B status and enable registers
369193267Sjkim *              in that different values can be written to the A/B registers.
370193267Sjkim *              Most notably, the SLP_TYP bits can be different, as per the
371193267Sjkim *              values returned from the _Sx predefined methods.
37291116Smsmith *
37391116Smsmith ******************************************************************************/
37467754Smsmith
37599679SiwasakiACPI_STATUS
376193267SjkimAcpiHwWritePm1Control (
377193267Sjkim    UINT32                  Pm1aControl,
378193267Sjkim    UINT32                  Pm1bControl)
37991116Smsmith{
38099679Siwasaki    ACPI_STATUS             Status;
38167754Smsmith
38267754Smsmith
383193267Sjkim    ACPI_FUNCTION_TRACE (HwWritePm1Control);
38467754Smsmith
38567754Smsmith
386197104Sjkim    Status = AcpiHwWrite (Pm1aControl, &AcpiGbl_FADT.XPm1aControlBlock);
38799679Siwasaki    if (ACPI_FAILURE (Status))
38899679Siwasaki    {
389193267Sjkim        return_ACPI_STATUS (Status);
39099679Siwasaki    }
39167754Smsmith
392193267Sjkim    if (AcpiGbl_FADT.XPm1bControlBlock.Address)
39391116Smsmith    {
394197104Sjkim        Status = AcpiHwWrite (Pm1bControl, &AcpiGbl_FADT.XPm1bControlBlock);
39567754Smsmith    }
39699679Siwasaki    return_ACPI_STATUS (Status);
39767754Smsmith}
39869450Smsmith
39969450Smsmith
40069450Smsmith/******************************************************************************
40169450Smsmith *
40269450Smsmith * FUNCTION:    AcpiHwRegisterRead
40369450Smsmith *
404193267Sjkim * PARAMETERS:  RegisterId          - ACPI Register ID
405151937Sjkim *              ReturnValue         - Where the register value is returned
40669450Smsmith *
407138287Smarks * RETURN:      Status and the value read.
40869450Smsmith *
409167802Sjkim * DESCRIPTION: Read from the specified ACPI register
41069450Smsmith *
41169450Smsmith ******************************************************************************/
41269450Smsmith
41399679SiwasakiACPI_STATUS
41469450SmsmithAcpiHwRegisterRead (
41599679Siwasaki    UINT32                  RegisterId,
41699679Siwasaki    UINT32                  *ReturnValue)
41769450Smsmith{
418193267Sjkim    UINT32                  Value = 0;
41999679Siwasaki    ACPI_STATUS             Status;
42069450Smsmith
42177424Smsmith
422167802Sjkim    ACPI_FUNCTION_TRACE (HwRegisterRead);
42369450Smsmith
42477424Smsmith
42591116Smsmith    switch (RegisterId)
42669450Smsmith    {
427193267Sjkim    case ACPI_REGISTER_PM1_STATUS:           /* PM1 A/B: 16-bit access each */
42869450Smsmith
429193267Sjkim        Status = AcpiHwReadMultiple (&Value,
430306536Sjkim            &AcpiGbl_XPm1aStatus,
431306536Sjkim            &AcpiGbl_XPm1bStatus);
43269450Smsmith        break;
43369450Smsmith
434193267Sjkim    case ACPI_REGISTER_PM1_ENABLE:           /* PM1 A/B: 16-bit access each */
43569450Smsmith
436193267Sjkim        Status = AcpiHwReadMultiple (&Value,
437306536Sjkim            &AcpiGbl_XPm1aEnable,
438306536Sjkim            &AcpiGbl_XPm1bEnable);
43969450Smsmith        break;
44069450Smsmith
441193267Sjkim    case ACPI_REGISTER_PM1_CONTROL:          /* PM1 A/B: 16-bit access each */
44269450Smsmith
443193267Sjkim        Status = AcpiHwReadMultiple (&Value,
444306536Sjkim            &AcpiGbl_FADT.XPm1aControlBlock,
445306536Sjkim            &AcpiGbl_FADT.XPm1bControlBlock);
44699679Siwasaki
447193267Sjkim        /*
448193267Sjkim         * Zero the write-only bits. From the ACPI specification, "Hardware
449193267Sjkim         * Write-Only Bits": "Upon reads to registers with write-only bits,
450193267Sjkim         * software masks out all write-only bits."
451193267Sjkim         */
452193267Sjkim        Value &= ~ACPI_PM1_CONTROL_WRITEONLY_BITS;
45369450Smsmith        break;
45469450Smsmith
45591116Smsmith    case ACPI_REGISTER_PM2_CONTROL:          /* 8-bit access */
45669450Smsmith
457197104Sjkim        Status = AcpiHwRead (&Value, &AcpiGbl_FADT.XPm2ControlBlock);
45869450Smsmith        break;
45969450Smsmith
46091116Smsmith    case ACPI_REGISTER_PM_TIMER:             /* 32-bit access */
46169450Smsmith
462197104Sjkim        Status = AcpiHwRead (&Value, &AcpiGbl_FADT.XPmTimerBlock);
46369450Smsmith        break;
46469450Smsmith
46591116Smsmith    case ACPI_REGISTER_SMI_COMMAND_BLOCK:    /* 8-bit access */
46669450Smsmith
467193267Sjkim        Status = AcpiHwReadPort (AcpiGbl_FADT.SmiCommand, &Value, 8);
46869450Smsmith        break;
46969450Smsmith
470250838Sjkim    default:
471193267Sjkim
472204773Sjkim        ACPI_ERROR ((AE_INFO, "Unknown Register ID: 0x%X",
473151937Sjkim            RegisterId));
47499679Siwasaki        Status = AE_BAD_PARAMETER;
47569450Smsmith        break;
47669450Smsmith    }
47769450Smsmith
47899679Siwasaki    if (ACPI_SUCCESS (Status))
47999679Siwasaki    {
480193267Sjkim        *ReturnValue = Value;
48199679Siwasaki    }
48299679Siwasaki
48399679Siwasaki    return_ACPI_STATUS (Status);
48469450Smsmith}
48569450Smsmith
48669450Smsmith
48769450Smsmith/******************************************************************************
48869450Smsmith *
48969450Smsmith * FUNCTION:    AcpiHwRegisterWrite
49069450Smsmith *
491193267Sjkim * PARAMETERS:  RegisterId          - ACPI Register ID
492138287Smarks *              Value               - The value to write
49369450Smsmith *
494138287Smarks * RETURN:      Status
49569450Smsmith *
496167802Sjkim * DESCRIPTION: Write to the specified ACPI register
49769450Smsmith *
498167802Sjkim * NOTE: In accordance with the ACPI specification, this function automatically
499167802Sjkim * preserves the value of the following bits, meaning that these bits cannot be
500167802Sjkim * changed via this interface:
501167802Sjkim *
502167802Sjkim * PM1_CONTROL[0] = SCI_EN
503167802Sjkim * PM1_CONTROL[9]
504167802Sjkim * PM1_STATUS[11]
505167802Sjkim *
506167802Sjkim * ACPI References:
507167802Sjkim * 1) Hardware Ignored Bits: When software writes to a register with ignored
508167802Sjkim *      bit fields, it preserves the ignored bit fields
509167802Sjkim * 2) SCI_EN: OSPM always preserves this bit position
510167802Sjkim *
51169450Smsmith ******************************************************************************/
51269450Smsmith
51399679SiwasakiACPI_STATUS
51469450SmsmithAcpiHwRegisterWrite (
51569450Smsmith    UINT32                  RegisterId,
51669450Smsmith    UINT32                  Value)
51769450Smsmith{
51899679Siwasaki    ACPI_STATUS             Status;
519167802Sjkim    UINT32                  ReadValue;
52069450Smsmith
52169450Smsmith
522167802Sjkim    ACPI_FUNCTION_TRACE (HwRegisterWrite);
52369450Smsmith
52483174Smsmith
52591116Smsmith    switch (RegisterId)
52669450Smsmith    {
527193267Sjkim    case ACPI_REGISTER_PM1_STATUS:           /* PM1 A/B: 16-bit access each */
528193267Sjkim        /*
529193267Sjkim         * Handle the "ignored" bit in PM1 Status. According to the ACPI
530193267Sjkim         * specification, ignored bits are to be preserved when writing.
531193267Sjkim         * Normally, this would mean a read/modify/write sequence. However,
532193267Sjkim         * preserving a bit in the status register is different. Writing a
533193267Sjkim         * one clears the status, and writing a zero preserves the status.
534193267Sjkim         * Therefore, we must always write zero to the ignored bit.
535193267Sjkim         *
536193267Sjkim         * This behavior is clarified in the ACPI 4.0 specification.
537193267Sjkim         */
538193267Sjkim        Value &= ~ACPI_PM1_STATUS_PRESERVED_BITS;
53969450Smsmith
540193267Sjkim        Status = AcpiHwWriteMultiple (Value,
541306536Sjkim            &AcpiGbl_XPm1aStatus,
542306536Sjkim            &AcpiGbl_XPm1bStatus);
54369450Smsmith        break;
54469450Smsmith
545193267Sjkim    case ACPI_REGISTER_PM1_ENABLE:           /* PM1 A/B: 16-bit access each */
54669450Smsmith
547193267Sjkim        Status = AcpiHwWriteMultiple (Value,
548306536Sjkim            &AcpiGbl_XPm1aEnable,
549306536Sjkim            &AcpiGbl_XPm1bEnable);
55069450Smsmith        break;
55169450Smsmith
552193267Sjkim    case ACPI_REGISTER_PM1_CONTROL:          /* PM1 A/B: 16-bit access each */
553167802Sjkim        /*
554167802Sjkim         * Perform a read first to preserve certain bits (per ACPI spec)
555167802Sjkim         * Note: This includes SCI_EN, we never want to change this bit
556167802Sjkim         */
557193267Sjkim        Status = AcpiHwReadMultiple (&ReadValue,
558306536Sjkim            &AcpiGbl_FADT.XPm1aControlBlock,
559306536Sjkim            &AcpiGbl_FADT.XPm1bControlBlock);
56099679Siwasaki        if (ACPI_FAILURE (Status))
56199679Siwasaki        {
562193267Sjkim            goto Exit;
56399679Siwasaki        }
56499679Siwasaki
565167802Sjkim        /* Insert the bits to be preserved */
566167802Sjkim
567167802Sjkim        ACPI_INSERT_BITS (Value, ACPI_PM1_CONTROL_PRESERVED_BITS, ReadValue);
568167802Sjkim
569167802Sjkim        /* Now we can write the data */
570167802Sjkim
571193267Sjkim        Status = AcpiHwWriteMultiple (Value,
572306536Sjkim            &AcpiGbl_FADT.XPm1aControlBlock,
573306536Sjkim            &AcpiGbl_FADT.XPm1bControlBlock);
57471867Smsmith        break;
57569450Smsmith
576193267Sjkim    case ACPI_REGISTER_PM2_CONTROL:          /* 8-bit access */
577193267Sjkim        /*
578193267Sjkim         * For control registers, all reserved bits must be preserved,
579193267Sjkim         * as per the ACPI spec.
580193267Sjkim         */
581197104Sjkim        Status = AcpiHwRead (&ReadValue, &AcpiGbl_FADT.XPm2ControlBlock);
582193267Sjkim        if (ACPI_FAILURE (Status))
583193267Sjkim        {
584193267Sjkim            goto Exit;
585193267Sjkim        }
58669450Smsmith
587193267Sjkim        /* Insert the bits to be preserved */
58869450Smsmith
589193267Sjkim        ACPI_INSERT_BITS (Value, ACPI_PM2_CONTROL_PRESERVED_BITS, ReadValue);
59071867Smsmith
591197104Sjkim        Status = AcpiHwWrite (Value, &AcpiGbl_FADT.XPm2ControlBlock);
59271867Smsmith        break;
59371867Smsmith
59491116Smsmith    case ACPI_REGISTER_PM_TIMER:             /* 32-bit access */
59569450Smsmith
596197104Sjkim        Status = AcpiHwWrite (Value, &AcpiGbl_FADT.XPmTimerBlock);
59769450Smsmith        break;
59869450Smsmith
59991116Smsmith    case ACPI_REGISTER_SMI_COMMAND_BLOCK:    /* 8-bit access */
60069450Smsmith
60191116Smsmith        /* SMI_CMD is currently always in IO space */
60269450Smsmith
603193267Sjkim        Status = AcpiHwWritePort (AcpiGbl_FADT.SmiCommand, Value, 8);
60469450Smsmith        break;
60569450Smsmith
606250838Sjkim    default:
60769450Smsmith
608204773Sjkim        ACPI_ERROR ((AE_INFO, "Unknown Register ID: 0x%X",
609193267Sjkim            RegisterId));
61099679Siwasaki        Status = AE_BAD_PARAMETER;
61169450Smsmith        break;
61269450Smsmith    }
61369450Smsmith
614193267SjkimExit:
61599679Siwasaki    return_ACPI_STATUS (Status);
61669450Smsmith}
61769450Smsmith
61869450Smsmith
61969450Smsmith/******************************************************************************
62069450Smsmith *
621193267Sjkim * FUNCTION:    AcpiHwReadMultiple
62269450Smsmith *
623193267Sjkim * PARAMETERS:  Value               - Where the register value is returned
624193267Sjkim *              RegisterA           - First ACPI register (required)
625193267Sjkim *              RegisterB           - Second ACPI register (optional)
62669450Smsmith *
627117521Snjl * RETURN:      Status
62869450Smsmith *
629193267Sjkim * DESCRIPTION: Read from the specified two-part ACPI register (such as PM1 A/B)
63069450Smsmith *
63169450Smsmith ******************************************************************************/
63269450Smsmith
633193267Sjkimstatic ACPI_STATUS
634193267SjkimAcpiHwReadMultiple (
63599679Siwasaki    UINT32                  *Value,
636193267Sjkim    ACPI_GENERIC_ADDRESS    *RegisterA,
637193267Sjkim    ACPI_GENERIC_ADDRESS    *RegisterB)
63869450Smsmith{
639193267Sjkim    UINT32                  ValueA = 0;
640193267Sjkim    UINT32                  ValueB = 0;
64199679Siwasaki    ACPI_STATUS             Status;
64269450Smsmith
64369450Smsmith
644193267Sjkim    /* The first register is always required */
64583174Smsmith
646197104Sjkim    Status = AcpiHwRead (&ValueA, RegisterA);
647193267Sjkim    if (ACPI_FAILURE (Status))
64869450Smsmith    {
649193267Sjkim        return (Status);
65069450Smsmith    }
651138287Smarks
652193267Sjkim    /* Second register is optional */
653138287Smarks
654193267Sjkim    if (RegisterB->Address)
655138287Smarks    {
656197104Sjkim        Status = AcpiHwRead (&ValueB, RegisterB);
657193267Sjkim        if (ACPI_FAILURE (Status))
658193267Sjkim        {
659193267Sjkim            return (Status);
660193267Sjkim        }
661138287Smarks    }
66269450Smsmith
66369450Smsmith    /*
664193267Sjkim     * OR the two return values together. No shifting or masking is necessary,
665193267Sjkim     * because of how the PM1 registers are defined in the ACPI specification:
666193267Sjkim     *
667193267Sjkim     * "Although the bits can be split between the two register blocks (each
668193267Sjkim     * register block has a unique pointer within the FADT), the bit positions
669193267Sjkim     * are maintained. The register block with unimplemented bits (that is,
670193267Sjkim     * those implemented in the other register block) always returns zeros,
671193267Sjkim     * and writes have no side effects"
67269450Smsmith     */
673193267Sjkim    *Value = (ValueA | ValueB);
674193267Sjkim    return (AE_OK);
67569450Smsmith}
67669450Smsmith
67769450Smsmith
67869450Smsmith/******************************************************************************
67969450Smsmith *
680193267Sjkim * FUNCTION:    AcpiHwWriteMultiple
68169450Smsmith *
682193267Sjkim * PARAMETERS:  Value               - The value to write
683193267Sjkim *              RegisterA           - First ACPI register (required)
684193267Sjkim *              RegisterB           - Second ACPI register (optional)
68569450Smsmith *
686117521Snjl * RETURN:      Status
68769450Smsmith *
688193267Sjkim * DESCRIPTION: Write to the specified two-part ACPI register (such as PM1 A/B)
68969450Smsmith *
69069450Smsmith ******************************************************************************/
69169450Smsmith
692193267Sjkimstatic ACPI_STATUS
693193267SjkimAcpiHwWriteMultiple (
69469450Smsmith    UINT32                  Value,
695193267Sjkim    ACPI_GENERIC_ADDRESS    *RegisterA,
696193267Sjkim    ACPI_GENERIC_ADDRESS    *RegisterB)
69769450Smsmith{
69899679Siwasaki    ACPI_STATUS             Status;
69969450Smsmith
70069450Smsmith
701193267Sjkim    /* The first register is always required */
70283174Smsmith
703197104Sjkim    Status = AcpiHwWrite (Value, RegisterA);
704193267Sjkim    if (ACPI_FAILURE (Status))
70569450Smsmith    {
706193267Sjkim        return (Status);
70769450Smsmith    }
708123315Snjl
70969450Smsmith    /*
710193267Sjkim     * Second register is optional
711193267Sjkim     *
712193267Sjkim     * No bit shifting or clearing is necessary, because of how the PM1
713193267Sjkim     * registers are defined in the ACPI specification:
714193267Sjkim     *
715193267Sjkim     * "Although the bits can be split between the two register blocks (each
716193267Sjkim     * register block has a unique pointer within the FADT), the bit positions
717193267Sjkim     * are maintained. The register block with unimplemented bits (that is,
718193267Sjkim     * those implemented in the other register block) always returns zeros,
719193267Sjkim     * and writes have no side effects"
72069450Smsmith     */
721193267Sjkim    if (RegisterB->Address)
72269450Smsmith    {
723197104Sjkim        Status = AcpiHwWrite (Value, RegisterB);
72469450Smsmith    }
72599679Siwasaki
72699679Siwasaki    return (Status);
72769450Smsmith}
728193267Sjkim
729231844Sjkim#endif /* !ACPI_REDUCED_HARDWARE */
730