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