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