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