xref: /titanic_50/usr/src/uts/intel/io/acpica/hardware/hwregs.c (revision 385cc6b4ad1792caef3f84eb61eed3f27085801f)
1ae115bc7Smrj /*******************************************************************************
2ae115bc7Smrj  *
3ae115bc7Smrj  * Module Name: hwregs - Read/write access functions for the various ACPI
4ae115bc7Smrj  *                       control and status registers.
5ae115bc7Smrj  *
6ae115bc7Smrj  ******************************************************************************/
7ae115bc7Smrj 
826f3cdf0SGordon Ross /*
9*385cc6b4SJerry Jelinek  * Copyright (C) 2000 - 2016, Intel Corp.
10ae115bc7Smrj  * All rights reserved.
11ae115bc7Smrj  *
1226f3cdf0SGordon Ross  * Redistribution and use in source and binary forms, with or without
1326f3cdf0SGordon Ross  * modification, are permitted provided that the following conditions
1426f3cdf0SGordon Ross  * are met:
1526f3cdf0SGordon Ross  * 1. Redistributions of source code must retain the above copyright
1626f3cdf0SGordon Ross  *    notice, this list of conditions, and the following disclaimer,
1726f3cdf0SGordon Ross  *    without modification.
1826f3cdf0SGordon Ross  * 2. Redistributions in binary form must reproduce at minimum a disclaimer
1926f3cdf0SGordon Ross  *    substantially similar to the "NO WARRANTY" disclaimer below
2026f3cdf0SGordon Ross  *    ("Disclaimer") and any redistribution must be conditioned upon
2126f3cdf0SGordon Ross  *    including a substantially similar Disclaimer requirement for further
2226f3cdf0SGordon Ross  *    binary redistribution.
2326f3cdf0SGordon Ross  * 3. Neither the names of the above-listed copyright holders nor the names
2426f3cdf0SGordon Ross  *    of any contributors may be used to endorse or promote products derived
2526f3cdf0SGordon Ross  *    from this software without specific prior written permission.
26ae115bc7Smrj  *
2726f3cdf0SGordon Ross  * Alternatively, this software may be distributed under the terms of the
2826f3cdf0SGordon Ross  * GNU General Public License ("GPL") version 2 as published by the Free
2926f3cdf0SGordon Ross  * Software Foundation.
30ae115bc7Smrj  *
3126f3cdf0SGordon Ross  * NO WARRANTY
3226f3cdf0SGordon Ross  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
3326f3cdf0SGordon Ross  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
3426f3cdf0SGordon Ross  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
3526f3cdf0SGordon Ross  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
3626f3cdf0SGordon Ross  * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
3726f3cdf0SGordon Ross  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
3826f3cdf0SGordon Ross  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
3926f3cdf0SGordon Ross  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
4026f3cdf0SGordon Ross  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
4126f3cdf0SGordon Ross  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
4226f3cdf0SGordon Ross  * POSSIBILITY OF SUCH DAMAGES.
4326f3cdf0SGordon Ross  */
44ae115bc7Smrj 
45ae115bc7Smrj #include "acpi.h"
46aa2aa9a6SDana Myers #include "accommon.h"
47ae115bc7Smrj #include "acevents.h"
48ae115bc7Smrj 
49ae115bc7Smrj #define _COMPONENT          ACPI_HARDWARE
50ae115bc7Smrj         ACPI_MODULE_NAME    ("hwregs")
51ae115bc7Smrj 
52ae115bc7Smrj 
53*385cc6b4SJerry Jelinek #if (!ACPI_REDUCED_HARDWARE)
54*385cc6b4SJerry Jelinek 
55aa2aa9a6SDana Myers /* Local Prototypes */
56aa2aa9a6SDana Myers 
57aa2aa9a6SDana Myers static ACPI_STATUS
58aa2aa9a6SDana Myers AcpiHwReadMultiple (
59aa2aa9a6SDana Myers     UINT32                  *Value,
60aa2aa9a6SDana Myers     ACPI_GENERIC_ADDRESS    *RegisterA,
61aa2aa9a6SDana Myers     ACPI_GENERIC_ADDRESS    *RegisterB);
62aa2aa9a6SDana Myers 
63aa2aa9a6SDana Myers static ACPI_STATUS
64aa2aa9a6SDana Myers AcpiHwWriteMultiple (
65aa2aa9a6SDana Myers     UINT32                  Value,
66aa2aa9a6SDana Myers     ACPI_GENERIC_ADDRESS    *RegisterA,
67aa2aa9a6SDana Myers     ACPI_GENERIC_ADDRESS    *RegisterB);
68aa2aa9a6SDana Myers 
69*385cc6b4SJerry Jelinek #endif /* !ACPI_REDUCED_HARDWARE */
70*385cc6b4SJerry Jelinek 
71aa2aa9a6SDana Myers 
724cf02d40SSaurabh Misra /******************************************************************************
734cf02d40SSaurabh Misra  *
744cf02d40SSaurabh Misra  * FUNCTION:    AcpiHwValidateRegister
754cf02d40SSaurabh Misra  *
764cf02d40SSaurabh Misra  * PARAMETERS:  Reg                 - GAS register structure
774cf02d40SSaurabh Misra  *              MaxBitWidth         - Max BitWidth supported (32 or 64)
784cf02d40SSaurabh Misra  *              Address             - Pointer to where the gas->address
794cf02d40SSaurabh Misra  *                                    is returned
804cf02d40SSaurabh Misra  *
814cf02d40SSaurabh Misra  * RETURN:      Status
824cf02d40SSaurabh Misra  *
834cf02d40SSaurabh Misra  * DESCRIPTION: Validate the contents of a GAS register. Checks the GAS
844cf02d40SSaurabh Misra  *              pointer, Address, SpaceId, BitWidth, and BitOffset.
854cf02d40SSaurabh Misra  *
864cf02d40SSaurabh Misra  ******************************************************************************/
874cf02d40SSaurabh Misra 
884cf02d40SSaurabh Misra ACPI_STATUS
AcpiHwValidateRegister(ACPI_GENERIC_ADDRESS * Reg,UINT8 MaxBitWidth,UINT64 * Address)894cf02d40SSaurabh Misra AcpiHwValidateRegister (
904cf02d40SSaurabh Misra     ACPI_GENERIC_ADDRESS    *Reg,
914cf02d40SSaurabh Misra     UINT8                   MaxBitWidth,
924cf02d40SSaurabh Misra     UINT64                  *Address)
934cf02d40SSaurabh Misra {
944cf02d40SSaurabh Misra 
954cf02d40SSaurabh Misra     /* Must have a valid pointer to a GAS structure */
964cf02d40SSaurabh Misra 
974cf02d40SSaurabh Misra     if (!Reg)
984cf02d40SSaurabh Misra     {
994cf02d40SSaurabh Misra         return (AE_BAD_PARAMETER);
1004cf02d40SSaurabh Misra     }
1014cf02d40SSaurabh Misra 
1024cf02d40SSaurabh Misra     /*
1034cf02d40SSaurabh Misra      * Copy the target address. This handles possible alignment issues.
1044cf02d40SSaurabh Misra      * Address must not be null. A null address also indicates an optional
1054cf02d40SSaurabh Misra      * ACPI register that is not supported, so no error message.
1064cf02d40SSaurabh Misra      */
1074cf02d40SSaurabh Misra     ACPI_MOVE_64_TO_64 (Address, &Reg->Address);
1084cf02d40SSaurabh Misra     if (!(*Address))
1094cf02d40SSaurabh Misra     {
1104cf02d40SSaurabh Misra         return (AE_BAD_ADDRESS);
1114cf02d40SSaurabh Misra     }
1124cf02d40SSaurabh Misra 
1134cf02d40SSaurabh Misra     /* Validate the SpaceID */
1144cf02d40SSaurabh Misra 
1154cf02d40SSaurabh Misra     if ((Reg->SpaceId != ACPI_ADR_SPACE_SYSTEM_MEMORY) &&
1164cf02d40SSaurabh Misra         (Reg->SpaceId != ACPI_ADR_SPACE_SYSTEM_IO))
1174cf02d40SSaurabh Misra     {
1184cf02d40SSaurabh Misra         ACPI_ERROR ((AE_INFO,
1194cf02d40SSaurabh Misra             "Unsupported address space: 0x%X", Reg->SpaceId));
1204cf02d40SSaurabh Misra         return (AE_SUPPORT);
1214cf02d40SSaurabh Misra     }
1224cf02d40SSaurabh Misra 
1234cf02d40SSaurabh Misra     /* Validate the BitWidth */
1244cf02d40SSaurabh Misra 
1254cf02d40SSaurabh Misra     if ((Reg->BitWidth != 8) &&
1264cf02d40SSaurabh Misra         (Reg->BitWidth != 16) &&
1274cf02d40SSaurabh Misra         (Reg->BitWidth != 32) &&
1284cf02d40SSaurabh Misra         (Reg->BitWidth != MaxBitWidth))
1294cf02d40SSaurabh Misra     {
1304cf02d40SSaurabh Misra         ACPI_ERROR ((AE_INFO,
1314cf02d40SSaurabh Misra             "Unsupported register bit width: 0x%X", Reg->BitWidth));
1324cf02d40SSaurabh Misra         return (AE_SUPPORT);
1334cf02d40SSaurabh Misra     }
1344cf02d40SSaurabh Misra 
1354cf02d40SSaurabh Misra     /* Validate the BitOffset. Just a warning for now. */
1364cf02d40SSaurabh Misra 
1374cf02d40SSaurabh Misra     if (Reg->BitOffset != 0)
1384cf02d40SSaurabh Misra     {
1394cf02d40SSaurabh Misra         ACPI_WARNING ((AE_INFO,
1404cf02d40SSaurabh Misra             "Unsupported register bit offset: 0x%X", Reg->BitOffset));
1414cf02d40SSaurabh Misra     }
1424cf02d40SSaurabh Misra 
1434cf02d40SSaurabh Misra     return (AE_OK);
1444cf02d40SSaurabh Misra }
1454cf02d40SSaurabh Misra 
1464cf02d40SSaurabh Misra 
1474cf02d40SSaurabh Misra /******************************************************************************
1484cf02d40SSaurabh Misra  *
14957190917SDana Myers  * FUNCTION:    AcpiHwRead
15057190917SDana Myers  *
15157190917SDana Myers  * PARAMETERS:  Value               - Where the value is returned
15257190917SDana Myers  *              Reg                 - GAS register structure
15357190917SDana Myers  *
15457190917SDana Myers  * RETURN:      Status
15557190917SDana Myers  *
15657190917SDana Myers  * DESCRIPTION: Read from either memory or IO space. This is a 32-bit max
15757190917SDana Myers  *              version of AcpiRead, used internally since the overhead of
15857190917SDana Myers  *              64-bit values is not needed.
15957190917SDana Myers  *
16057190917SDana Myers  * LIMITATIONS: <These limitations also apply to AcpiHwWrite>
16157190917SDana Myers  *      BitWidth must be exactly 8, 16, or 32.
16257190917SDana Myers  *      SpaceID must be SystemMemory or SystemIO.
16357190917SDana Myers  *      BitOffset and AccessWidth are currently ignored, as there has
16457190917SDana Myers  *          not been a need to implement these.
16557190917SDana Myers  *
16657190917SDana Myers  ******************************************************************************/
16757190917SDana Myers 
16857190917SDana Myers ACPI_STATUS
AcpiHwRead(UINT32 * Value,ACPI_GENERIC_ADDRESS * Reg)16957190917SDana Myers AcpiHwRead (
17057190917SDana Myers     UINT32                  *Value,
17157190917SDana Myers     ACPI_GENERIC_ADDRESS    *Reg)
17257190917SDana Myers {
17357190917SDana Myers     UINT64                  Address;
174*385cc6b4SJerry Jelinek     UINT64                  Value64;
17557190917SDana Myers     ACPI_STATUS             Status;
17657190917SDana Myers 
17757190917SDana Myers 
17857190917SDana Myers     ACPI_FUNCTION_NAME (HwRead);
17957190917SDana Myers 
18057190917SDana Myers 
18157190917SDana Myers     /* Validate contents of the GAS register */
18257190917SDana Myers 
18357190917SDana Myers     Status = AcpiHwValidateRegister (Reg, 32, &Address);
18457190917SDana Myers     if (ACPI_FAILURE (Status))
18557190917SDana Myers     {
18657190917SDana Myers         return (Status);
18757190917SDana Myers     }
18857190917SDana Myers 
18957190917SDana Myers     /* Initialize entire 32-bit return value to zero */
19057190917SDana Myers 
19157190917SDana Myers     *Value = 0;
19257190917SDana Myers 
19357190917SDana Myers     /*
19457190917SDana Myers      * Two address spaces supported: Memory or IO. PCI_Config is
19557190917SDana Myers      * not supported here because the GAS structure is insufficient
19657190917SDana Myers      */
19757190917SDana Myers     if (Reg->SpaceId == ACPI_ADR_SPACE_SYSTEM_MEMORY)
19857190917SDana Myers     {
19957190917SDana Myers         Status = AcpiOsReadMemory ((ACPI_PHYSICAL_ADDRESS)
200*385cc6b4SJerry Jelinek             Address, &Value64, Reg->BitWidth);
201*385cc6b4SJerry Jelinek 
202*385cc6b4SJerry Jelinek         *Value = (UINT32) Value64;
20357190917SDana Myers     }
20457190917SDana Myers     else /* ACPI_ADR_SPACE_SYSTEM_IO, validated earlier */
20557190917SDana Myers     {
20657190917SDana Myers         Status = AcpiHwReadPort ((ACPI_IO_ADDRESS)
20757190917SDana Myers             Address, Value, Reg->BitWidth);
20857190917SDana Myers     }
20957190917SDana Myers 
21057190917SDana Myers     ACPI_DEBUG_PRINT ((ACPI_DB_IO,
21157190917SDana Myers         "Read:  %8.8X width %2d from %8.8X%8.8X (%s)\n",
21257190917SDana Myers         *Value, Reg->BitWidth, ACPI_FORMAT_UINT64 (Address),
21357190917SDana Myers         AcpiUtGetRegionName (Reg->SpaceId)));
21457190917SDana Myers 
21557190917SDana Myers     return (Status);
21657190917SDana Myers }
21757190917SDana Myers 
21857190917SDana Myers 
21957190917SDana Myers /******************************************************************************
22057190917SDana Myers  *
2214cf02d40SSaurabh Misra  * FUNCTION:    AcpiHwWrite
2224cf02d40SSaurabh Misra  *
2234cf02d40SSaurabh Misra  * PARAMETERS:  Value               - Value to be written
2244cf02d40SSaurabh Misra  *              Reg                 - GAS register structure
2254cf02d40SSaurabh Misra  *
2264cf02d40SSaurabh Misra  * RETURN:      Status
2274cf02d40SSaurabh Misra  *
2284cf02d40SSaurabh Misra  * DESCRIPTION: Write to either memory or IO space. This is a 32-bit max
2294cf02d40SSaurabh Misra  *              version of AcpiWrite, used internally since the overhead of
2304cf02d40SSaurabh Misra  *              64-bit values is not needed.
2314cf02d40SSaurabh Misra  *
2324cf02d40SSaurabh Misra  ******************************************************************************/
2334cf02d40SSaurabh Misra 
2344cf02d40SSaurabh Misra ACPI_STATUS
AcpiHwWrite(UINT32 Value,ACPI_GENERIC_ADDRESS * Reg)2354cf02d40SSaurabh Misra AcpiHwWrite (
2364cf02d40SSaurabh Misra     UINT32                  Value,
2374cf02d40SSaurabh Misra     ACPI_GENERIC_ADDRESS    *Reg)
2384cf02d40SSaurabh Misra {
2394cf02d40SSaurabh Misra     UINT64                  Address;
2404cf02d40SSaurabh Misra     ACPI_STATUS             Status;
2414cf02d40SSaurabh Misra 
2424cf02d40SSaurabh Misra 
2434cf02d40SSaurabh Misra     ACPI_FUNCTION_NAME (HwWrite);
2444cf02d40SSaurabh Misra 
2454cf02d40SSaurabh Misra 
2464cf02d40SSaurabh Misra     /* Validate contents of the GAS register */
2474cf02d40SSaurabh Misra 
2484cf02d40SSaurabh Misra     Status = AcpiHwValidateRegister (Reg, 32, &Address);
2494cf02d40SSaurabh Misra     if (ACPI_FAILURE (Status))
2504cf02d40SSaurabh Misra     {
2514cf02d40SSaurabh Misra         return (Status);
2524cf02d40SSaurabh Misra     }
2534cf02d40SSaurabh Misra 
2544cf02d40SSaurabh Misra     /*
2554cf02d40SSaurabh Misra      * Two address spaces supported: Memory or IO. PCI_Config is
2564cf02d40SSaurabh Misra      * not supported here because the GAS structure is insufficient
2574cf02d40SSaurabh Misra      */
2584cf02d40SSaurabh Misra     if (Reg->SpaceId == ACPI_ADR_SPACE_SYSTEM_MEMORY)
2594cf02d40SSaurabh Misra     {
2604cf02d40SSaurabh Misra         Status = AcpiOsWriteMemory ((ACPI_PHYSICAL_ADDRESS)
261*385cc6b4SJerry Jelinek             Address, (UINT64) Value, Reg->BitWidth);
2624cf02d40SSaurabh Misra     }
2634cf02d40SSaurabh Misra     else /* ACPI_ADR_SPACE_SYSTEM_IO, validated earlier */
2644cf02d40SSaurabh Misra     {
2654cf02d40SSaurabh Misra         Status = AcpiHwWritePort ((ACPI_IO_ADDRESS)
2664cf02d40SSaurabh Misra             Address, Value, Reg->BitWidth);
2674cf02d40SSaurabh Misra     }
2684cf02d40SSaurabh Misra 
2694cf02d40SSaurabh Misra     ACPI_DEBUG_PRINT ((ACPI_DB_IO,
2704cf02d40SSaurabh Misra         "Wrote: %8.8X width %2d   to %8.8X%8.8X (%s)\n",
2714cf02d40SSaurabh Misra         Value, Reg->BitWidth, ACPI_FORMAT_UINT64 (Address),
2724cf02d40SSaurabh Misra         AcpiUtGetRegionName (Reg->SpaceId)));
2734cf02d40SSaurabh Misra 
2744cf02d40SSaurabh Misra     return (Status);
2754cf02d40SSaurabh Misra }
2764cf02d40SSaurabh Misra 
2774cf02d40SSaurabh Misra 
278*385cc6b4SJerry Jelinek #if (!ACPI_REDUCED_HARDWARE)
279ae115bc7Smrj /*******************************************************************************
280ae115bc7Smrj  *
281ae115bc7Smrj  * FUNCTION:    AcpiHwClearAcpiStatus
282ae115bc7Smrj  *
283db2bae30SDana Myers  * PARAMETERS:  None
284ae115bc7Smrj  *
285aa2aa9a6SDana Myers  * RETURN:      Status
286ae115bc7Smrj  *
287ae115bc7Smrj  * DESCRIPTION: Clears all fixed and general purpose status bits
288ae115bc7Smrj  *
289ae115bc7Smrj  ******************************************************************************/
290ae115bc7Smrj 
291ae115bc7Smrj ACPI_STATUS
AcpiHwClearAcpiStatus(void)292ae115bc7Smrj AcpiHwClearAcpiStatus (
293db2bae30SDana Myers     void)
294ae115bc7Smrj {
295ae115bc7Smrj     ACPI_STATUS             Status;
296ae115bc7Smrj     ACPI_CPU_FLAGS          LockFlags = 0;
297ae115bc7Smrj 
298ae115bc7Smrj 
299ae115bc7Smrj     ACPI_FUNCTION_TRACE (HwClearAcpiStatus);
300ae115bc7Smrj 
301ae115bc7Smrj 
302aa2aa9a6SDana Myers     ACPI_DEBUG_PRINT ((ACPI_DB_IO, "About to write %04X to %8.8X%8.8X\n",
303ae115bc7Smrj         ACPI_BITMASK_ALL_FIXED_STATUS,
304aa2aa9a6SDana Myers         ACPI_FORMAT_UINT64 (AcpiGbl_XPm1aStatus.Address)));
305ae115bc7Smrj 
306ae115bc7Smrj     LockFlags = AcpiOsAcquireLock (AcpiGbl_HardwareLock);
307ae115bc7Smrj 
308aa2aa9a6SDana Myers     /* Clear the fixed events in PM1 A/B */
309aa2aa9a6SDana Myers 
310db2bae30SDana Myers     Status = AcpiHwRegisterWrite (ACPI_REGISTER_PM1_STATUS,
311ae115bc7Smrj         ACPI_BITMASK_ALL_FIXED_STATUS);
312*385cc6b4SJerry Jelinek 
313*385cc6b4SJerry Jelinek     AcpiOsReleaseLock (AcpiGbl_HardwareLock, LockFlags);
314*385cc6b4SJerry Jelinek 
315ae115bc7Smrj     if (ACPI_FAILURE (Status))
316ae115bc7Smrj     {
317*385cc6b4SJerry Jelinek         goto Exit;
318ae115bc7Smrj     }
319ae115bc7Smrj 
320ae115bc7Smrj     /* Clear the GPE Bits in all GPE registers in all GPE blocks */
321ae115bc7Smrj 
322aa2aa9a6SDana Myers     Status = AcpiEvWalkGpeList (AcpiHwClearGpeBlock, NULL);
323ae115bc7Smrj 
324*385cc6b4SJerry Jelinek Exit:
325ae115bc7Smrj     return_ACPI_STATUS (Status);
326ae115bc7Smrj }
327ae115bc7Smrj 
328ae115bc7Smrj 
329ae115bc7Smrj /*******************************************************************************
330ae115bc7Smrj  *
331*385cc6b4SJerry Jelinek  * FUNCTION:    AcpiHwGetBitRegisterInfo
332ae115bc7Smrj  *
333ae115bc7Smrj  * PARAMETERS:  RegisterId          - Index of ACPI Register to access
334ae115bc7Smrj  *
335ae115bc7Smrj  * RETURN:      The bitmask to be used when accessing the register
336ae115bc7Smrj  *
337ae115bc7Smrj  * DESCRIPTION: Map RegisterId into a register bitmask.
338ae115bc7Smrj  *
339ae115bc7Smrj  ******************************************************************************/
340ae115bc7Smrj 
341ae115bc7Smrj ACPI_BIT_REGISTER_INFO *
AcpiHwGetBitRegisterInfo(UINT32 RegisterId)342ae115bc7Smrj AcpiHwGetBitRegisterInfo (
343ae115bc7Smrj     UINT32                  RegisterId)
344ae115bc7Smrj {
345ae115bc7Smrj     ACPI_FUNCTION_ENTRY ();
346ae115bc7Smrj 
347ae115bc7Smrj 
348ae115bc7Smrj     if (RegisterId > ACPI_BITREG_MAX)
349ae115bc7Smrj     {
35026f3cdf0SGordon Ross         ACPI_ERROR ((AE_INFO, "Invalid BitRegister ID: 0x%X", RegisterId));
351ae115bc7Smrj         return (NULL);
352ae115bc7Smrj     }
353ae115bc7Smrj 
354ae115bc7Smrj     return (&AcpiGbl_BitRegisterInfo[RegisterId]);
355ae115bc7Smrj }
356ae115bc7Smrj 
357ae115bc7Smrj 
358aa2aa9a6SDana Myers /******************************************************************************
359ae115bc7Smrj  *
360aa2aa9a6SDana Myers  * FUNCTION:    AcpiHwWritePm1Control
361ae115bc7Smrj  *
362aa2aa9a6SDana Myers  * PARAMETERS:  Pm1aControl         - Value to be written to PM1A control
363aa2aa9a6SDana Myers  *              Pm1bControl         - Value to be written to PM1B control
364ae115bc7Smrj  *
365ae115bc7Smrj  * RETURN:      Status
366ae115bc7Smrj  *
367aa2aa9a6SDana Myers  * DESCRIPTION: Write the PM1 A/B control registers. These registers are
368aa2aa9a6SDana Myers  *              different than than the PM1 A/B status and enable registers
369aa2aa9a6SDana Myers  *              in that different values can be written to the A/B registers.
370aa2aa9a6SDana Myers  *              Most notably, the SLP_TYP bits can be different, as per the
371aa2aa9a6SDana Myers  *              values returned from the _Sx predefined methods.
372ae115bc7Smrj  *
373ae115bc7Smrj  ******************************************************************************/
374ae115bc7Smrj 
375ae115bc7Smrj ACPI_STATUS
AcpiHwWritePm1Control(UINT32 Pm1aControl,UINT32 Pm1bControl)376aa2aa9a6SDana Myers AcpiHwWritePm1Control (
377aa2aa9a6SDana Myers     UINT32                  Pm1aControl,
378aa2aa9a6SDana Myers     UINT32                  Pm1bControl)
379ae115bc7Smrj {
380ae115bc7Smrj     ACPI_STATUS             Status;
381ae115bc7Smrj 
382ae115bc7Smrj 
383aa2aa9a6SDana Myers     ACPI_FUNCTION_TRACE (HwWritePm1Control);
384ae115bc7Smrj 
385ae115bc7Smrj 
38657190917SDana Myers     Status = AcpiHwWrite (Pm1aControl, &AcpiGbl_FADT.XPm1aControlBlock);
387ae115bc7Smrj     if (ACPI_FAILURE (Status))
388ae115bc7Smrj     {
389ae115bc7Smrj         return_ACPI_STATUS (Status);
390ae115bc7Smrj     }
391ae115bc7Smrj 
392aa2aa9a6SDana Myers     if (AcpiGbl_FADT.XPm1bControlBlock.Address)
393aa2aa9a6SDana Myers     {
39457190917SDana Myers         Status = AcpiHwWrite (Pm1bControl, &AcpiGbl_FADT.XPm1bControlBlock);
395aa2aa9a6SDana Myers     }
396aa2aa9a6SDana Myers     return_ACPI_STATUS (Status);
397aa2aa9a6SDana Myers }
398ae115bc7Smrj 
399ae115bc7Smrj 
400ae115bc7Smrj /******************************************************************************
401ae115bc7Smrj  *
402ae115bc7Smrj  * FUNCTION:    AcpiHwRegisterRead
403ae115bc7Smrj  *
404db2bae30SDana Myers  * PARAMETERS:  RegisterId          - ACPI Register ID
405ae115bc7Smrj  *              ReturnValue         - Where the register value is returned
406ae115bc7Smrj  *
407ae115bc7Smrj  * RETURN:      Status and the value read.
408ae115bc7Smrj  *
409ae115bc7Smrj  * DESCRIPTION: Read from the specified ACPI register
410ae115bc7Smrj  *
411ae115bc7Smrj  ******************************************************************************/
412ae115bc7Smrj 
413ae115bc7Smrj ACPI_STATUS
AcpiHwRegisterRead(UINT32 RegisterId,UINT32 * ReturnValue)414ae115bc7Smrj AcpiHwRegisterRead (
415ae115bc7Smrj     UINT32                  RegisterId,
416ae115bc7Smrj     UINT32                  *ReturnValue)
417ae115bc7Smrj {
418aa2aa9a6SDana Myers     UINT32                  Value = 0;
419ae115bc7Smrj     ACPI_STATUS             Status;
420ae115bc7Smrj 
421ae115bc7Smrj 
422ae115bc7Smrj     ACPI_FUNCTION_TRACE (HwRegisterRead);
423ae115bc7Smrj 
424ae115bc7Smrj 
425ae115bc7Smrj     switch (RegisterId)
426ae115bc7Smrj     {
427aa2aa9a6SDana Myers     case ACPI_REGISTER_PM1_STATUS:           /* PM1 A/B: 16-bit access each */
428ae115bc7Smrj 
429aa2aa9a6SDana Myers         Status = AcpiHwReadMultiple (&Value,
430aa2aa9a6SDana Myers             &AcpiGbl_XPm1aStatus,
431aa2aa9a6SDana Myers             &AcpiGbl_XPm1bStatus);
432ae115bc7Smrj         break;
433ae115bc7Smrj 
434aa2aa9a6SDana Myers     case ACPI_REGISTER_PM1_ENABLE:           /* PM1 A/B: 16-bit access each */
435ae115bc7Smrj 
436aa2aa9a6SDana Myers         Status = AcpiHwReadMultiple (&Value,
437aa2aa9a6SDana Myers             &AcpiGbl_XPm1aEnable,
438aa2aa9a6SDana Myers             &AcpiGbl_XPm1bEnable);
439ae115bc7Smrj         break;
440ae115bc7Smrj 
441aa2aa9a6SDana Myers     case ACPI_REGISTER_PM1_CONTROL:          /* PM1 A/B: 16-bit access each */
442ae115bc7Smrj 
443aa2aa9a6SDana Myers         Status = AcpiHwReadMultiple (&Value,
444aa2aa9a6SDana Myers             &AcpiGbl_FADT.XPm1aControlBlock,
445aa2aa9a6SDana Myers             &AcpiGbl_FADT.XPm1bControlBlock);
446ae115bc7Smrj 
447aa2aa9a6SDana Myers         /*
448aa2aa9a6SDana Myers          * Zero the write-only bits. From the ACPI specification, "Hardware
449aa2aa9a6SDana Myers          * Write-Only Bits": "Upon reads to registers with write-only bits,
450aa2aa9a6SDana Myers          * software masks out all write-only bits."
451aa2aa9a6SDana Myers          */
452aa2aa9a6SDana Myers         Value &= ~ACPI_PM1_CONTROL_WRITEONLY_BITS;
453ae115bc7Smrj         break;
454ae115bc7Smrj 
455ae115bc7Smrj     case ACPI_REGISTER_PM2_CONTROL:          /* 8-bit access */
456ae115bc7Smrj 
45757190917SDana Myers         Status = AcpiHwRead (&Value, &AcpiGbl_FADT.XPm2ControlBlock);
458ae115bc7Smrj         break;
459ae115bc7Smrj 
460ae115bc7Smrj     case ACPI_REGISTER_PM_TIMER:             /* 32-bit access */
461ae115bc7Smrj 
46257190917SDana Myers         Status = AcpiHwRead (&Value, &AcpiGbl_FADT.XPmTimerBlock);
463ae115bc7Smrj         break;
464ae115bc7Smrj 
465ae115bc7Smrj     case ACPI_REGISTER_SMI_COMMAND_BLOCK:    /* 8-bit access */
466ae115bc7Smrj 
467aa2aa9a6SDana Myers         Status = AcpiHwReadPort (AcpiGbl_FADT.SmiCommand, &Value, 8);
468ae115bc7Smrj         break;
469ae115bc7Smrj 
470ae115bc7Smrj     default:
471*385cc6b4SJerry Jelinek 
47226f3cdf0SGordon Ross         ACPI_ERROR ((AE_INFO, "Unknown Register ID: 0x%X",
473ae115bc7Smrj             RegisterId));
474ae115bc7Smrj         Status = AE_BAD_PARAMETER;
475ae115bc7Smrj         break;
476ae115bc7Smrj     }
477ae115bc7Smrj 
478ae115bc7Smrj     if (ACPI_SUCCESS (Status))
479ae115bc7Smrj     {
480aa2aa9a6SDana Myers         *ReturnValue = Value;
481ae115bc7Smrj     }
482ae115bc7Smrj 
483ae115bc7Smrj     return_ACPI_STATUS (Status);
484ae115bc7Smrj }
485ae115bc7Smrj 
486ae115bc7Smrj 
487ae115bc7Smrj /******************************************************************************
488ae115bc7Smrj  *
489ae115bc7Smrj  * FUNCTION:    AcpiHwRegisterWrite
490ae115bc7Smrj  *
491db2bae30SDana Myers  * PARAMETERS:  RegisterId          - ACPI Register ID
492ae115bc7Smrj  *              Value               - The value to write
493ae115bc7Smrj  *
494ae115bc7Smrj  * RETURN:      Status
495ae115bc7Smrj  *
496ae115bc7Smrj  * DESCRIPTION: Write to the specified ACPI register
497ae115bc7Smrj  *
498ae115bc7Smrj  * NOTE: In accordance with the ACPI specification, this function automatically
499ae115bc7Smrj  * preserves the value of the following bits, meaning that these bits cannot be
500ae115bc7Smrj  * changed via this interface:
501ae115bc7Smrj  *
502ae115bc7Smrj  * PM1_CONTROL[0] = SCI_EN
503ae115bc7Smrj  * PM1_CONTROL[9]
504ae115bc7Smrj  * PM1_STATUS[11]
505ae115bc7Smrj  *
506ae115bc7Smrj  * ACPI References:
507ae115bc7Smrj  * 1) Hardware Ignored Bits: When software writes to a register with ignored
508ae115bc7Smrj  *      bit fields, it preserves the ignored bit fields
509ae115bc7Smrj  * 2) SCI_EN: OSPM always preserves this bit position
510ae115bc7Smrj  *
511ae115bc7Smrj  ******************************************************************************/
512ae115bc7Smrj 
513ae115bc7Smrj ACPI_STATUS
AcpiHwRegisterWrite(UINT32 RegisterId,UINT32 Value)514ae115bc7Smrj AcpiHwRegisterWrite (
515ae115bc7Smrj     UINT32                  RegisterId,
516ae115bc7Smrj     UINT32                  Value)
517ae115bc7Smrj {
518ae115bc7Smrj     ACPI_STATUS             Status;
519ae115bc7Smrj     UINT32                  ReadValue;
520ae115bc7Smrj 
521ae115bc7Smrj 
522ae115bc7Smrj     ACPI_FUNCTION_TRACE (HwRegisterWrite);
523ae115bc7Smrj 
524ae115bc7Smrj 
525ae115bc7Smrj     switch (RegisterId)
526ae115bc7Smrj     {
527aa2aa9a6SDana Myers     case ACPI_REGISTER_PM1_STATUS:           /* PM1 A/B: 16-bit access each */
528aa2aa9a6SDana Myers         /*
529aa2aa9a6SDana Myers          * Handle the "ignored" bit in PM1 Status. According to the ACPI
530aa2aa9a6SDana Myers          * specification, ignored bits are to be preserved when writing.
531aa2aa9a6SDana Myers          * Normally, this would mean a read/modify/write sequence. However,
532aa2aa9a6SDana Myers          * preserving a bit in the status register is different. Writing a
533aa2aa9a6SDana Myers          * one clears the status, and writing a zero preserves the status.
534aa2aa9a6SDana Myers          * Therefore, we must always write zero to the ignored bit.
535aa2aa9a6SDana Myers          *
536aa2aa9a6SDana Myers          * This behavior is clarified in the ACPI 4.0 specification.
537aa2aa9a6SDana Myers          */
538aa2aa9a6SDana Myers         Value &= ~ACPI_PM1_STATUS_PRESERVED_BITS;
539ae115bc7Smrj 
540aa2aa9a6SDana Myers         Status = AcpiHwWriteMultiple (Value,
541aa2aa9a6SDana Myers             &AcpiGbl_XPm1aStatus,
542aa2aa9a6SDana Myers             &AcpiGbl_XPm1bStatus);
543ae115bc7Smrj         break;
544ae115bc7Smrj 
545aa2aa9a6SDana Myers     case ACPI_REGISTER_PM1_ENABLE:           /* PM1 A/B: 16-bit access each */
546ae115bc7Smrj 
547aa2aa9a6SDana Myers         Status = AcpiHwWriteMultiple (Value,
548aa2aa9a6SDana Myers             &AcpiGbl_XPm1aEnable,
549aa2aa9a6SDana Myers             &AcpiGbl_XPm1bEnable);
550ae115bc7Smrj         break;
551ae115bc7Smrj 
552aa2aa9a6SDana Myers     case ACPI_REGISTER_PM1_CONTROL:          /* PM1 A/B: 16-bit access each */
553ae115bc7Smrj         /*
554ae115bc7Smrj          * Perform a read first to preserve certain bits (per ACPI spec)
555ae115bc7Smrj          * Note: This includes SCI_EN, we never want to change this bit
556ae115bc7Smrj          */
557aa2aa9a6SDana Myers         Status = AcpiHwReadMultiple (&ReadValue,
558aa2aa9a6SDana Myers             &AcpiGbl_FADT.XPm1aControlBlock,
559aa2aa9a6SDana Myers             &AcpiGbl_FADT.XPm1bControlBlock);
560ae115bc7Smrj         if (ACPI_FAILURE (Status))
561ae115bc7Smrj         {
562db2bae30SDana Myers             goto Exit;
563ae115bc7Smrj         }
564ae115bc7Smrj 
565ae115bc7Smrj         /* Insert the bits to be preserved */
566ae115bc7Smrj 
567ae115bc7Smrj         ACPI_INSERT_BITS (Value, ACPI_PM1_CONTROL_PRESERVED_BITS, ReadValue);
568ae115bc7Smrj 
569ae115bc7Smrj         /* Now we can write the data */
570ae115bc7Smrj 
571aa2aa9a6SDana Myers         Status = AcpiHwWriteMultiple (Value,
572aa2aa9a6SDana Myers             &AcpiGbl_FADT.XPm1aControlBlock,
573aa2aa9a6SDana Myers             &AcpiGbl_FADT.XPm1bControlBlock);
574ae115bc7Smrj         break;
575ae115bc7Smrj 
576ae115bc7Smrj     case ACPI_REGISTER_PM2_CONTROL:          /* 8-bit access */
577aa2aa9a6SDana Myers         /*
578aa2aa9a6SDana Myers          * For control registers, all reserved bits must be preserved,
579aa2aa9a6SDana Myers          * as per the ACPI spec.
580aa2aa9a6SDana Myers          */
58157190917SDana Myers         Status = AcpiHwRead (&ReadValue, &AcpiGbl_FADT.XPm2ControlBlock);
582aa2aa9a6SDana Myers         if (ACPI_FAILURE (Status))
583aa2aa9a6SDana Myers         {
584aa2aa9a6SDana Myers             goto Exit;
585aa2aa9a6SDana Myers         }
586aa2aa9a6SDana Myers 
587aa2aa9a6SDana Myers         /* Insert the bits to be preserved */
588aa2aa9a6SDana Myers 
589aa2aa9a6SDana Myers         ACPI_INSERT_BITS (Value, ACPI_PM2_CONTROL_PRESERVED_BITS, ReadValue);
590aa2aa9a6SDana Myers 
59157190917SDana Myers         Status = AcpiHwWrite (Value, &AcpiGbl_FADT.XPm2ControlBlock);
592ae115bc7Smrj         break;
593ae115bc7Smrj 
594ae115bc7Smrj     case ACPI_REGISTER_PM_TIMER:             /* 32-bit access */
595ae115bc7Smrj 
59657190917SDana Myers         Status = AcpiHwWrite (Value, &AcpiGbl_FADT.XPmTimerBlock);
597ae115bc7Smrj         break;
598ae115bc7Smrj 
599ae115bc7Smrj     case ACPI_REGISTER_SMI_COMMAND_BLOCK:    /* 8-bit access */
600ae115bc7Smrj 
601ae115bc7Smrj         /* SMI_CMD is currently always in IO space */
602ae115bc7Smrj 
603aa2aa9a6SDana Myers         Status = AcpiHwWritePort (AcpiGbl_FADT.SmiCommand, Value, 8);
604ae115bc7Smrj         break;
605ae115bc7Smrj 
606ae115bc7Smrj     default:
607*385cc6b4SJerry Jelinek 
60826f3cdf0SGordon Ross         ACPI_ERROR ((AE_INFO, "Unknown Register ID: 0x%X",
609aa2aa9a6SDana Myers             RegisterId));
610ae115bc7Smrj         Status = AE_BAD_PARAMETER;
611ae115bc7Smrj         break;
612ae115bc7Smrj     }
613ae115bc7Smrj 
614db2bae30SDana Myers Exit:
615ae115bc7Smrj     return_ACPI_STATUS (Status);
616ae115bc7Smrj }
617ae115bc7Smrj 
618ae115bc7Smrj 
619ae115bc7Smrj /******************************************************************************
620ae115bc7Smrj  *
621aa2aa9a6SDana Myers  * FUNCTION:    AcpiHwReadMultiple
622ae115bc7Smrj  *
623aa2aa9a6SDana Myers  * PARAMETERS:  Value               - Where the register value is returned
624aa2aa9a6SDana Myers  *              RegisterA           - First ACPI register (required)
625aa2aa9a6SDana Myers  *              RegisterB           - Second ACPI register (optional)
626ae115bc7Smrj  *
627ae115bc7Smrj  * RETURN:      Status
628ae115bc7Smrj  *
629aa2aa9a6SDana Myers  * DESCRIPTION: Read from the specified two-part ACPI register (such as PM1 A/B)
630ae115bc7Smrj  *
631ae115bc7Smrj  ******************************************************************************/
632ae115bc7Smrj 
633aa2aa9a6SDana Myers static ACPI_STATUS
AcpiHwReadMultiple(UINT32 * Value,ACPI_GENERIC_ADDRESS * RegisterA,ACPI_GENERIC_ADDRESS * RegisterB)634aa2aa9a6SDana Myers AcpiHwReadMultiple (
635ae115bc7Smrj     UINT32                  *Value,
636aa2aa9a6SDana Myers     ACPI_GENERIC_ADDRESS    *RegisterA,
637aa2aa9a6SDana Myers     ACPI_GENERIC_ADDRESS    *RegisterB)
638ae115bc7Smrj {
639aa2aa9a6SDana Myers     UINT32                  ValueA = 0;
640aa2aa9a6SDana Myers     UINT32                  ValueB = 0;
641ae115bc7Smrj     ACPI_STATUS             Status;
642ae115bc7Smrj 
643ae115bc7Smrj 
644aa2aa9a6SDana Myers     /* The first register is always required */
645ae115bc7Smrj 
64657190917SDana Myers     Status = AcpiHwRead (&ValueA, RegisterA);
647aa2aa9a6SDana Myers     if (ACPI_FAILURE (Status))
648ae115bc7Smrj     {
649ae115bc7Smrj         return (Status);
650ae115bc7Smrj     }
651ae115bc7Smrj 
652aa2aa9a6SDana Myers     /* Second register is optional */
653aa2aa9a6SDana Myers 
654aa2aa9a6SDana Myers     if (RegisterB->Address)
655aa2aa9a6SDana Myers     {
65657190917SDana Myers         Status = AcpiHwRead (&ValueB, RegisterB);
657aa2aa9a6SDana Myers         if (ACPI_FAILURE (Status))
658aa2aa9a6SDana Myers         {
659aa2aa9a6SDana Myers             return (Status);
660aa2aa9a6SDana Myers         }
661aa2aa9a6SDana Myers     }
662aa2aa9a6SDana Myers 
663aa2aa9a6SDana Myers     /*
664aa2aa9a6SDana Myers      * OR the two return values together. No shifting or masking is necessary,
665aa2aa9a6SDana Myers      * because of how the PM1 registers are defined in the ACPI specification:
666aa2aa9a6SDana Myers      *
667aa2aa9a6SDana Myers      * "Although the bits can be split between the two register blocks (each
668aa2aa9a6SDana Myers      * register block has a unique pointer within the FADT), the bit positions
669aa2aa9a6SDana Myers      * are maintained. The register block with unimplemented bits (that is,
670aa2aa9a6SDana Myers      * those implemented in the other register block) always returns zeros,
671aa2aa9a6SDana Myers      * and writes have no side effects"
672aa2aa9a6SDana Myers      */
673aa2aa9a6SDana Myers     *Value = (ValueA | ValueB);
674aa2aa9a6SDana Myers     return (AE_OK);
675aa2aa9a6SDana Myers }
676aa2aa9a6SDana Myers 
677ae115bc7Smrj 
678ae115bc7Smrj /******************************************************************************
679ae115bc7Smrj  *
680aa2aa9a6SDana Myers  * FUNCTION:    AcpiHwWriteMultiple
681ae115bc7Smrj  *
682aa2aa9a6SDana Myers  * PARAMETERS:  Value               - The value to write
683aa2aa9a6SDana Myers  *              RegisterA           - First ACPI register (required)
684aa2aa9a6SDana Myers  *              RegisterB           - Second ACPI register (optional)
685ae115bc7Smrj  *
686ae115bc7Smrj  * RETURN:      Status
687ae115bc7Smrj  *
688aa2aa9a6SDana Myers  * DESCRIPTION: Write to the specified two-part ACPI register (such as PM1 A/B)
689ae115bc7Smrj  *
690ae115bc7Smrj  ******************************************************************************/
691ae115bc7Smrj 
692aa2aa9a6SDana Myers static ACPI_STATUS
AcpiHwWriteMultiple(UINT32 Value,ACPI_GENERIC_ADDRESS * RegisterA,ACPI_GENERIC_ADDRESS * RegisterB)693aa2aa9a6SDana Myers AcpiHwWriteMultiple (
694ae115bc7Smrj     UINT32                  Value,
695aa2aa9a6SDana Myers     ACPI_GENERIC_ADDRESS    *RegisterA,
696aa2aa9a6SDana Myers     ACPI_GENERIC_ADDRESS    *RegisterB)
697ae115bc7Smrj {
698ae115bc7Smrj     ACPI_STATUS             Status;
699ae115bc7Smrj 
700ae115bc7Smrj 
701aa2aa9a6SDana Myers     /* The first register is always required */
702ae115bc7Smrj 
70357190917SDana Myers     Status = AcpiHwWrite (Value, RegisterA);
704aa2aa9a6SDana Myers     if (ACPI_FAILURE (Status))
705ae115bc7Smrj     {
706aa2aa9a6SDana Myers         return (Status);
707ae115bc7Smrj     }
708ae115bc7Smrj 
709ae115bc7Smrj     /*
710aa2aa9a6SDana Myers      * Second register is optional
711aa2aa9a6SDana Myers      *
712aa2aa9a6SDana Myers      * No bit shifting or clearing is necessary, because of how the PM1
713aa2aa9a6SDana Myers      * registers are defined in the ACPI specification:
714aa2aa9a6SDana Myers      *
715aa2aa9a6SDana Myers      * "Although the bits can be split between the two register blocks (each
716aa2aa9a6SDana Myers      * register block has a unique pointer within the FADT), the bit positions
717aa2aa9a6SDana Myers      * are maintained. The register block with unimplemented bits (that is,
718aa2aa9a6SDana Myers      * those implemented in the other register block) always returns zeros,
719aa2aa9a6SDana Myers      * and writes have no side effects"
720ae115bc7Smrj      */
721aa2aa9a6SDana Myers     if (RegisterB->Address)
722ae115bc7Smrj     {
72357190917SDana Myers         Status = AcpiHwWrite (Value, RegisterB);
724ae115bc7Smrj     }
725ae115bc7Smrj 
726ae115bc7Smrj     return (Status);
727ae115bc7Smrj }
728aa2aa9a6SDana Myers 
729*385cc6b4SJerry Jelinek #endif /* !ACPI_REDUCED_HARDWARE */
730