167754Smsmith/******************************************************************************* 267754Smsmith * 367754Smsmith * Module Name: hwregs - Read/write access functions for the various ACPI 467754Smsmith * control and status registers. 567754Smsmith * 667754Smsmith ******************************************************************************/ 767754Smsmith 8217365Sjkim/* 9245582Sjkim * Copyright (C) 2000 - 2013, Intel Corp. 1070243Smsmith * All rights reserved. 1167754Smsmith * 12217365Sjkim * Redistribution and use in source and binary forms, with or without 13217365Sjkim * modification, are permitted provided that the following conditions 14217365Sjkim * are met: 15217365Sjkim * 1. Redistributions of source code must retain the above copyright 16217365Sjkim * notice, this list of conditions, and the following disclaimer, 17217365Sjkim * without modification. 18217365Sjkim * 2. Redistributions in binary form must reproduce at minimum a disclaimer 19217365Sjkim * substantially similar to the "NO WARRANTY" disclaimer below 20217365Sjkim * ("Disclaimer") and any redistribution must be conditioned upon 21217365Sjkim * including a substantially similar Disclaimer requirement for further 22217365Sjkim * binary redistribution. 23217365Sjkim * 3. Neither the names of the above-listed copyright holders nor the names 24217365Sjkim * of any contributors may be used to endorse or promote products derived 25217365Sjkim * from this software without specific prior written permission. 2667754Smsmith * 27217365Sjkim * Alternatively, this software may be distributed under the terms of the 28217365Sjkim * GNU General Public License ("GPL") version 2 as published by the Free 29217365Sjkim * Software Foundation. 3067754Smsmith * 31217365Sjkim * NO WARRANTY 32217365Sjkim * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 33217365Sjkim * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 34217365Sjkim * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR 35217365Sjkim * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 36217365Sjkim * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 37217365Sjkim * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 38217365Sjkim * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 39217365Sjkim * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 40217365Sjkim * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 41217365Sjkim * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 42217365Sjkim * POSSIBILITY OF SUCH DAMAGES. 43217365Sjkim */ 4467754Smsmith 4567754Smsmith#define __HWREGS_C__ 4667754Smsmith 47193341Sjkim#include <contrib/dev/acpica/include/acpi.h> 48193341Sjkim#include <contrib/dev/acpica/include/accommon.h> 49193341Sjkim#include <contrib/dev/acpica/include/acevents.h> 5067754Smsmith 5177424Smsmith#define _COMPONENT ACPI_HARDWARE 5291116Smsmith ACPI_MODULE_NAME ("hwregs") 5367754Smsmith 5467754Smsmith 55231844Sjkim#if (!ACPI_REDUCED_HARDWARE) 56231844Sjkim 57193267Sjkim/* Local Prototypes */ 58193267Sjkim 59193267Sjkimstatic ACPI_STATUS 60193267SjkimAcpiHwReadMultiple ( 61193267Sjkim UINT32 *Value, 62193267Sjkim ACPI_GENERIC_ADDRESS *RegisterA, 63193267Sjkim ACPI_GENERIC_ADDRESS *RegisterB); 64193267Sjkim 65193267Sjkimstatic ACPI_STATUS 66193267SjkimAcpiHwWriteMultiple ( 67193267Sjkim UINT32 Value, 68193267Sjkim ACPI_GENERIC_ADDRESS *RegisterA, 69193267Sjkim ACPI_GENERIC_ADDRESS *RegisterB); 70193267Sjkim 71231844Sjkim#endif /* !ACPI_REDUCED_HARDWARE */ 72193267Sjkim 73197104Sjkim/****************************************************************************** 74197104Sjkim * 75197104Sjkim * FUNCTION: AcpiHwValidateRegister 76197104Sjkim * 77197104Sjkim * PARAMETERS: Reg - GAS register structure 78197104Sjkim * MaxBitWidth - Max BitWidth supported (32 or 64) 79197104Sjkim * Address - Pointer to where the gas->address 80197104Sjkim * is returned 81197104Sjkim * 82197104Sjkim * RETURN: Status 83197104Sjkim * 84197104Sjkim * DESCRIPTION: Validate the contents of a GAS register. Checks the GAS 85197104Sjkim * pointer, Address, SpaceId, BitWidth, and BitOffset. 86197104Sjkim * 87197104Sjkim ******************************************************************************/ 88197104Sjkim 89197104SjkimACPI_STATUS 90197104SjkimAcpiHwValidateRegister ( 91197104Sjkim ACPI_GENERIC_ADDRESS *Reg, 92197104Sjkim UINT8 MaxBitWidth, 93197104Sjkim UINT64 *Address) 94197104Sjkim{ 95197104Sjkim 96197104Sjkim /* Must have a valid pointer to a GAS structure */ 97197104Sjkim 98197104Sjkim if (!Reg) 99197104Sjkim { 100197104Sjkim return (AE_BAD_PARAMETER); 101197104Sjkim } 102197104Sjkim 103197104Sjkim /* 104197104Sjkim * Copy the target address. This handles possible alignment issues. 105197104Sjkim * Address must not be null. A null address also indicates an optional 106197104Sjkim * ACPI register that is not supported, so no error message. 107197104Sjkim */ 108197104Sjkim ACPI_MOVE_64_TO_64 (Address, &Reg->Address); 109197104Sjkim if (!(*Address)) 110197104Sjkim { 111197104Sjkim return (AE_BAD_ADDRESS); 112197104Sjkim } 113197104Sjkim 114197104Sjkim /* Validate the SpaceID */ 115197104Sjkim 116197104Sjkim if ((Reg->SpaceId != ACPI_ADR_SPACE_SYSTEM_MEMORY) && 117197104Sjkim (Reg->SpaceId != ACPI_ADR_SPACE_SYSTEM_IO)) 118197104Sjkim { 119197104Sjkim ACPI_ERROR ((AE_INFO, 120197104Sjkim "Unsupported address space: 0x%X", Reg->SpaceId)); 121197104Sjkim return (AE_SUPPORT); 122197104Sjkim } 123197104Sjkim 124197104Sjkim /* Validate the BitWidth */ 125197104Sjkim 126197104Sjkim if ((Reg->BitWidth != 8) && 127197104Sjkim (Reg->BitWidth != 16) && 128197104Sjkim (Reg->BitWidth != 32) && 129197104Sjkim (Reg->BitWidth != MaxBitWidth)) 130197104Sjkim { 131197104Sjkim ACPI_ERROR ((AE_INFO, 132197104Sjkim "Unsupported register bit width: 0x%X", Reg->BitWidth)); 133197104Sjkim return (AE_SUPPORT); 134197104Sjkim } 135197104Sjkim 136197104Sjkim /* Validate the BitOffset. Just a warning for now. */ 137197104Sjkim 138197104Sjkim if (Reg->BitOffset != 0) 139197104Sjkim { 140197104Sjkim ACPI_WARNING ((AE_INFO, 141197104Sjkim "Unsupported register bit offset: 0x%X", Reg->BitOffset)); 142197104Sjkim } 143197104Sjkim 144197104Sjkim return (AE_OK); 145197104Sjkim} 146197104Sjkim 147197104Sjkim 148197104Sjkim/****************************************************************************** 149197104Sjkim * 150197104Sjkim * FUNCTION: AcpiHwRead 151197104Sjkim * 152197104Sjkim * PARAMETERS: Value - Where the value is returned 153197104Sjkim * Reg - GAS register structure 154197104Sjkim * 155197104Sjkim * RETURN: Status 156197104Sjkim * 157197104Sjkim * DESCRIPTION: Read from either memory or IO space. This is a 32-bit max 158197104Sjkim * version of AcpiRead, used internally since the overhead of 159197104Sjkim * 64-bit values is not needed. 160197104Sjkim * 161197104Sjkim * LIMITATIONS: <These limitations also apply to AcpiHwWrite> 162197104Sjkim * BitWidth must be exactly 8, 16, or 32. 163197104Sjkim * SpaceID must be SystemMemory or SystemIO. 164197104Sjkim * BitOffset and AccessWidth are currently ignored, as there has 165197104Sjkim * not been a need to implement these. 166197104Sjkim * 167197104Sjkim ******************************************************************************/ 168197104Sjkim 169197104SjkimACPI_STATUS 170197104SjkimAcpiHwRead ( 171197104Sjkim UINT32 *Value, 172197104Sjkim ACPI_GENERIC_ADDRESS *Reg) 173197104Sjkim{ 174197104Sjkim UINT64 Address; 175231844Sjkim UINT64 Value64; 176197104Sjkim ACPI_STATUS Status; 177197104Sjkim 178197104Sjkim 179197104Sjkim ACPI_FUNCTION_NAME (HwRead); 180197104Sjkim 181197104Sjkim 182197104Sjkim /* Validate contents of the GAS register */ 183197104Sjkim 184197104Sjkim Status = AcpiHwValidateRegister (Reg, 32, &Address); 185197104Sjkim if (ACPI_FAILURE (Status)) 186197104Sjkim { 187197104Sjkim return (Status); 188197104Sjkim } 189197104Sjkim 190197104Sjkim /* Initialize entire 32-bit return value to zero */ 191197104Sjkim 192197104Sjkim *Value = 0; 193197104Sjkim 194197104Sjkim /* 195197104Sjkim * Two address spaces supported: Memory or IO. PCI_Config is 196197104Sjkim * not supported here because the GAS structure is insufficient 197197104Sjkim */ 198197104Sjkim if (Reg->SpaceId == ACPI_ADR_SPACE_SYSTEM_MEMORY) 199197104Sjkim { 200197104Sjkim Status = AcpiOsReadMemory ((ACPI_PHYSICAL_ADDRESS) 201231844Sjkim Address, &Value64, Reg->BitWidth); 202231844Sjkim 203231844Sjkim *Value = (UINT32) Value64; 204197104Sjkim } 205197104Sjkim else /* ACPI_ADR_SPACE_SYSTEM_IO, validated earlier */ 206197104Sjkim { 207197104Sjkim Status = AcpiHwReadPort ((ACPI_IO_ADDRESS) 208197104Sjkim Address, Value, Reg->BitWidth); 209197104Sjkim } 210197104Sjkim 211197104Sjkim ACPI_DEBUG_PRINT ((ACPI_DB_IO, 212197104Sjkim "Read: %8.8X width %2d from %8.8X%8.8X (%s)\n", 213197104Sjkim *Value, Reg->BitWidth, ACPI_FORMAT_UINT64 (Address), 214197104Sjkim AcpiUtGetRegionName (Reg->SpaceId))); 215197104Sjkim 216197104Sjkim return (Status); 217197104Sjkim} 218197104Sjkim 219197104Sjkim 220197104Sjkim/****************************************************************************** 221197104Sjkim * 222197104Sjkim * FUNCTION: AcpiHwWrite 223197104Sjkim * 224197104Sjkim * PARAMETERS: Value - Value to be written 225197104Sjkim * Reg - GAS register structure 226197104Sjkim * 227197104Sjkim * RETURN: Status 228197104Sjkim * 229197104Sjkim * DESCRIPTION: Write to either memory or IO space. This is a 32-bit max 230197104Sjkim * version of AcpiWrite, used internally since the overhead of 231197104Sjkim * 64-bit values is not needed. 232197104Sjkim * 233197104Sjkim ******************************************************************************/ 234197104Sjkim 235197104SjkimACPI_STATUS 236197104SjkimAcpiHwWrite ( 237197104Sjkim UINT32 Value, 238197104Sjkim ACPI_GENERIC_ADDRESS *Reg) 239197104Sjkim{ 240197104Sjkim UINT64 Address; 241197104Sjkim ACPI_STATUS Status; 242197104Sjkim 243197104Sjkim 244197104Sjkim ACPI_FUNCTION_NAME (HwWrite); 245197104Sjkim 246197104Sjkim 247197104Sjkim /* Validate contents of the GAS register */ 248197104Sjkim 249197104Sjkim Status = AcpiHwValidateRegister (Reg, 32, &Address); 250197104Sjkim if (ACPI_FAILURE (Status)) 251197104Sjkim { 252197104Sjkim return (Status); 253197104Sjkim } 254197104Sjkim 255197104Sjkim /* 256197104Sjkim * Two address spaces supported: Memory or IO. PCI_Config is 257197104Sjkim * not supported here because the GAS structure is insufficient 258197104Sjkim */ 259197104Sjkim if (Reg->SpaceId == ACPI_ADR_SPACE_SYSTEM_MEMORY) 260197104Sjkim { 261197104Sjkim Status = AcpiOsWriteMemory ((ACPI_PHYSICAL_ADDRESS) 262231844Sjkim Address, (UINT64) Value, Reg->BitWidth); 263197104Sjkim } 264197104Sjkim else /* ACPI_ADR_SPACE_SYSTEM_IO, validated earlier */ 265197104Sjkim { 266197104Sjkim Status = AcpiHwWritePort ((ACPI_IO_ADDRESS) 267197104Sjkim Address, Value, Reg->BitWidth); 268197104Sjkim } 269197104Sjkim 270197104Sjkim ACPI_DEBUG_PRINT ((ACPI_DB_IO, 271197104Sjkim "Wrote: %8.8X width %2d to %8.8X%8.8X (%s)\n", 272197104Sjkim Value, Reg->BitWidth, ACPI_FORMAT_UINT64 (Address), 273197104Sjkim AcpiUtGetRegionName (Reg->SpaceId))); 274197104Sjkim 275197104Sjkim return (Status); 276197104Sjkim} 277197104Sjkim 278197104Sjkim 279231844Sjkim#if (!ACPI_REDUCED_HARDWARE) 28067754Smsmith/******************************************************************************* 28167754Smsmith * 28267754Smsmith * FUNCTION: AcpiHwClearAcpiStatus 28367754Smsmith * 284167802Sjkim * PARAMETERS: None 28567754Smsmith * 286193267Sjkim * RETURN: Status 28767754Smsmith * 28867754Smsmith * DESCRIPTION: Clears all fixed and general purpose status bits 28967754Smsmith * 29067754Smsmith ******************************************************************************/ 29167754Smsmith 29299679SiwasakiACPI_STATUS 293117521SnjlAcpiHwClearAcpiStatus ( 294167802Sjkim void) 29567754Smsmith{ 29691116Smsmith ACPI_STATUS Status; 297167802Sjkim ACPI_CPU_FLAGS LockFlags = 0; 29867754Smsmith 29967754Smsmith 300167802Sjkim ACPI_FUNCTION_TRACE (HwClearAcpiStatus); 30167754Smsmith 30267754Smsmith 303193267Sjkim ACPI_DEBUG_PRINT ((ACPI_DB_IO, "About to write %04X to %8.8X%8.8X\n", 30491116Smsmith ACPI_BITMASK_ALL_FIXED_STATUS, 305193267Sjkim ACPI_FORMAT_UINT64 (AcpiGbl_XPm1aStatus.Address))); 30667754Smsmith 307167802Sjkim LockFlags = AcpiOsAcquireLock (AcpiGbl_HardwareLock); 30867754Smsmith 309193267Sjkim /* Clear the fixed events in PM1 A/B */ 310193267Sjkim 311193267Sjkim Status = AcpiHwRegisterWrite (ACPI_REGISTER_PM1_STATUS, 312151937Sjkim ACPI_BITMASK_ALL_FIXED_STATUS); 31399679Siwasaki if (ACPI_FAILURE (Status)) 31499679Siwasaki { 31599679Siwasaki goto UnlockAndExit; 31699679Siwasaki } 31767754Smsmith 318114237Snjl /* Clear the GPE Bits in all GPE registers in all GPE blocks */ 31967754Smsmith 320193267Sjkim Status = AcpiEvWalkGpeList (AcpiHwClearGpeBlock, NULL); 321117521Snjl 322117521SnjlUnlockAndExit: 323167802Sjkim AcpiOsReleaseLock (AcpiGbl_HardwareLock, LockFlags); 32499679Siwasaki return_ACPI_STATUS (Status); 32567754Smsmith} 32667754Smsmith 32767754Smsmith 32867754Smsmith/******************************************************************************* 32967754Smsmith * 330231844Sjkim * FUNCTION: AcpiHwGetBitRegisterInfo 33167754Smsmith * 33299679Siwasaki * PARAMETERS: RegisterId - Index of ACPI Register to access 333102550Siwasaki * 334151937Sjkim * RETURN: The bitmask to be used when accessing the register 33591116Smsmith * 336151937Sjkim * DESCRIPTION: Map RegisterId into a register bitmask. 33791116Smsmith * 33891116Smsmith ******************************************************************************/ 33991116Smsmith 34091116SmsmithACPI_BIT_REGISTER_INFO * 34191116SmsmithAcpiHwGetBitRegisterInfo ( 34291116Smsmith UINT32 RegisterId) 34391116Smsmith{ 344167802Sjkim ACPI_FUNCTION_ENTRY (); 34591116Smsmith 34691116Smsmith 34791116Smsmith if (RegisterId > ACPI_BITREG_MAX) 34891116Smsmith { 349204773Sjkim ACPI_ERROR ((AE_INFO, "Invalid BitRegister ID: 0x%X", RegisterId)); 35091116Smsmith return (NULL); 35191116Smsmith } 35291116Smsmith 35391116Smsmith return (&AcpiGbl_BitRegisterInfo[RegisterId]); 35491116Smsmith} 35591116Smsmith 35691116Smsmith 357193267Sjkim/****************************************************************************** 35891116Smsmith * 359193267Sjkim * FUNCTION: AcpiHwWritePm1Control 36091116Smsmith * 361193267Sjkim * PARAMETERS: Pm1aControl - Value to be written to PM1A control 362193267Sjkim * Pm1bControl - Value to be written to PM1B control 36367754Smsmith * 364138287Smarks * RETURN: Status 36591116Smsmith * 366193267Sjkim * DESCRIPTION: Write the PM1 A/B control registers. These registers are 367193267Sjkim * different than than the PM1 A/B status and enable registers 368193267Sjkim * in that different values can be written to the A/B registers. 369193267Sjkim * Most notably, the SLP_TYP bits can be different, as per the 370193267Sjkim * values returned from the _Sx predefined methods. 37191116Smsmith * 37291116Smsmith ******************************************************************************/ 37367754Smsmith 37499679SiwasakiACPI_STATUS 375193267SjkimAcpiHwWritePm1Control ( 376193267Sjkim UINT32 Pm1aControl, 377193267Sjkim UINT32 Pm1bControl) 37891116Smsmith{ 37999679Siwasaki ACPI_STATUS Status; 38067754Smsmith 38167754Smsmith 382193267Sjkim ACPI_FUNCTION_TRACE (HwWritePm1Control); 38367754Smsmith 38467754Smsmith 385197104Sjkim Status = AcpiHwWrite (Pm1aControl, &AcpiGbl_FADT.XPm1aControlBlock); 38699679Siwasaki if (ACPI_FAILURE (Status)) 38799679Siwasaki { 388193267Sjkim return_ACPI_STATUS (Status); 38999679Siwasaki } 39067754Smsmith 391193267Sjkim if (AcpiGbl_FADT.XPm1bControlBlock.Address) 39291116Smsmith { 393197104Sjkim Status = AcpiHwWrite (Pm1bControl, &AcpiGbl_FADT.XPm1bControlBlock); 39467754Smsmith } 39599679Siwasaki return_ACPI_STATUS (Status); 39667754Smsmith} 39769450Smsmith 39869450Smsmith 39969450Smsmith/****************************************************************************** 40069450Smsmith * 40169450Smsmith * FUNCTION: AcpiHwRegisterRead 40269450Smsmith * 403193267Sjkim * PARAMETERS: RegisterId - ACPI Register ID 404151937Sjkim * ReturnValue - Where the register value is returned 40569450Smsmith * 406138287Smarks * RETURN: Status and the value read. 40769450Smsmith * 408167802Sjkim * DESCRIPTION: Read from the specified ACPI register 40969450Smsmith * 41069450Smsmith ******************************************************************************/ 41169450Smsmith 41299679SiwasakiACPI_STATUS 41369450SmsmithAcpiHwRegisterRead ( 41499679Siwasaki UINT32 RegisterId, 41599679Siwasaki UINT32 *ReturnValue) 41669450Smsmith{ 417193267Sjkim UINT32 Value = 0; 41899679Siwasaki ACPI_STATUS Status; 41969450Smsmith 42077424Smsmith 421167802Sjkim ACPI_FUNCTION_TRACE (HwRegisterRead); 42269450Smsmith 42377424Smsmith 42491116Smsmith switch (RegisterId) 42569450Smsmith { 426193267Sjkim case ACPI_REGISTER_PM1_STATUS: /* PM1 A/B: 16-bit access each */ 42769450Smsmith 428193267Sjkim Status = AcpiHwReadMultiple (&Value, 429193267Sjkim &AcpiGbl_XPm1aStatus, 430193267Sjkim &AcpiGbl_XPm1bStatus); 43169450Smsmith break; 43269450Smsmith 433193267Sjkim case ACPI_REGISTER_PM1_ENABLE: /* PM1 A/B: 16-bit access each */ 43469450Smsmith 435193267Sjkim Status = AcpiHwReadMultiple (&Value, 436193267Sjkim &AcpiGbl_XPm1aEnable, 437193267Sjkim &AcpiGbl_XPm1bEnable); 43869450Smsmith break; 43969450Smsmith 440193267Sjkim case ACPI_REGISTER_PM1_CONTROL: /* PM1 A/B: 16-bit access each */ 44169450Smsmith 442193267Sjkim Status = AcpiHwReadMultiple (&Value, 443193267Sjkim &AcpiGbl_FADT.XPm1aControlBlock, 444193267Sjkim &AcpiGbl_FADT.XPm1bControlBlock); 44599679Siwasaki 446193267Sjkim /* 447193267Sjkim * Zero the write-only bits. From the ACPI specification, "Hardware 448193267Sjkim * Write-Only Bits": "Upon reads to registers with write-only bits, 449193267Sjkim * software masks out all write-only bits." 450193267Sjkim */ 451193267Sjkim Value &= ~ACPI_PM1_CONTROL_WRITEONLY_BITS; 45269450Smsmith break; 45369450Smsmith 45491116Smsmith case ACPI_REGISTER_PM2_CONTROL: /* 8-bit access */ 45569450Smsmith 456197104Sjkim Status = AcpiHwRead (&Value, &AcpiGbl_FADT.XPm2ControlBlock); 45769450Smsmith break; 45869450Smsmith 45991116Smsmith case ACPI_REGISTER_PM_TIMER: /* 32-bit access */ 46069450Smsmith 461197104Sjkim Status = AcpiHwRead (&Value, &AcpiGbl_FADT.XPmTimerBlock); 46269450Smsmith break; 46369450Smsmith 46491116Smsmith case ACPI_REGISTER_SMI_COMMAND_BLOCK: /* 8-bit access */ 46569450Smsmith 466193267Sjkim Status = AcpiHwReadPort (AcpiGbl_FADT.SmiCommand, &Value, 8); 46769450Smsmith break; 46869450Smsmith 469250838Sjkim default: 470193267Sjkim 471204773Sjkim ACPI_ERROR ((AE_INFO, "Unknown Register ID: 0x%X", 472151937Sjkim RegisterId)); 47399679Siwasaki Status = AE_BAD_PARAMETER; 47469450Smsmith break; 47569450Smsmith } 47669450Smsmith 47799679Siwasaki if (ACPI_SUCCESS (Status)) 47899679Siwasaki { 479193267Sjkim *ReturnValue = Value; 48099679Siwasaki } 48199679Siwasaki 48299679Siwasaki return_ACPI_STATUS (Status); 48369450Smsmith} 48469450Smsmith 48569450Smsmith 48669450Smsmith/****************************************************************************** 48769450Smsmith * 48869450Smsmith * FUNCTION: AcpiHwRegisterWrite 48969450Smsmith * 490193267Sjkim * PARAMETERS: RegisterId - ACPI Register ID 491138287Smarks * Value - The value to write 49269450Smsmith * 493138287Smarks * RETURN: Status 49469450Smsmith * 495167802Sjkim * DESCRIPTION: Write to the specified ACPI register 49669450Smsmith * 497167802Sjkim * NOTE: In accordance with the ACPI specification, this function automatically 498167802Sjkim * preserves the value of the following bits, meaning that these bits cannot be 499167802Sjkim * changed via this interface: 500167802Sjkim * 501167802Sjkim * PM1_CONTROL[0] = SCI_EN 502167802Sjkim * PM1_CONTROL[9] 503167802Sjkim * PM1_STATUS[11] 504167802Sjkim * 505167802Sjkim * ACPI References: 506167802Sjkim * 1) Hardware Ignored Bits: When software writes to a register with ignored 507167802Sjkim * bit fields, it preserves the ignored bit fields 508167802Sjkim * 2) SCI_EN: OSPM always preserves this bit position 509167802Sjkim * 51069450Smsmith ******************************************************************************/ 51169450Smsmith 51299679SiwasakiACPI_STATUS 51369450SmsmithAcpiHwRegisterWrite ( 51469450Smsmith UINT32 RegisterId, 51569450Smsmith UINT32 Value) 51669450Smsmith{ 51799679Siwasaki ACPI_STATUS Status; 518167802Sjkim UINT32 ReadValue; 51969450Smsmith 52069450Smsmith 521167802Sjkim ACPI_FUNCTION_TRACE (HwRegisterWrite); 52269450Smsmith 52383174Smsmith 52491116Smsmith switch (RegisterId) 52569450Smsmith { 526193267Sjkim case ACPI_REGISTER_PM1_STATUS: /* PM1 A/B: 16-bit access each */ 527193267Sjkim /* 528193267Sjkim * Handle the "ignored" bit in PM1 Status. According to the ACPI 529193267Sjkim * specification, ignored bits are to be preserved when writing. 530193267Sjkim * Normally, this would mean a read/modify/write sequence. However, 531193267Sjkim * preserving a bit in the status register is different. Writing a 532193267Sjkim * one clears the status, and writing a zero preserves the status. 533193267Sjkim * Therefore, we must always write zero to the ignored bit. 534193267Sjkim * 535193267Sjkim * This behavior is clarified in the ACPI 4.0 specification. 536193267Sjkim */ 537193267Sjkim Value &= ~ACPI_PM1_STATUS_PRESERVED_BITS; 53869450Smsmith 539193267Sjkim Status = AcpiHwWriteMultiple (Value, 540193267Sjkim &AcpiGbl_XPm1aStatus, 541193267Sjkim &AcpiGbl_XPm1bStatus); 54269450Smsmith break; 54369450Smsmith 544193267Sjkim case ACPI_REGISTER_PM1_ENABLE: /* PM1 A/B: 16-bit access each */ 54569450Smsmith 546193267Sjkim Status = AcpiHwWriteMultiple (Value, 547193267Sjkim &AcpiGbl_XPm1aEnable, 548193267Sjkim &AcpiGbl_XPm1bEnable); 54969450Smsmith break; 55069450Smsmith 551193267Sjkim case ACPI_REGISTER_PM1_CONTROL: /* PM1 A/B: 16-bit access each */ 552167802Sjkim /* 553167802Sjkim * Perform a read first to preserve certain bits (per ACPI spec) 554167802Sjkim * Note: This includes SCI_EN, we never want to change this bit 555167802Sjkim */ 556193267Sjkim Status = AcpiHwReadMultiple (&ReadValue, 557193267Sjkim &AcpiGbl_FADT.XPm1aControlBlock, 558193267Sjkim &AcpiGbl_FADT.XPm1bControlBlock); 55999679Siwasaki if (ACPI_FAILURE (Status)) 56099679Siwasaki { 561193267Sjkim goto Exit; 56299679Siwasaki } 56399679Siwasaki 564167802Sjkim /* Insert the bits to be preserved */ 565167802Sjkim 566167802Sjkim ACPI_INSERT_BITS (Value, ACPI_PM1_CONTROL_PRESERVED_BITS, ReadValue); 567167802Sjkim 568167802Sjkim /* Now we can write the data */ 569167802Sjkim 570193267Sjkim Status = AcpiHwWriteMultiple (Value, 571193267Sjkim &AcpiGbl_FADT.XPm1aControlBlock, 572193267Sjkim &AcpiGbl_FADT.XPm1bControlBlock); 57371867Smsmith break; 57469450Smsmith 575193267Sjkim case ACPI_REGISTER_PM2_CONTROL: /* 8-bit access */ 576193267Sjkim /* 577193267Sjkim * For control registers, all reserved bits must be preserved, 578193267Sjkim * as per the ACPI spec. 579193267Sjkim */ 580197104Sjkim Status = AcpiHwRead (&ReadValue, &AcpiGbl_FADT.XPm2ControlBlock); 581193267Sjkim if (ACPI_FAILURE (Status)) 582193267Sjkim { 583193267Sjkim goto Exit; 584193267Sjkim } 58569450Smsmith 586193267Sjkim /* Insert the bits to be preserved */ 58769450Smsmith 588193267Sjkim ACPI_INSERT_BITS (Value, ACPI_PM2_CONTROL_PRESERVED_BITS, ReadValue); 58971867Smsmith 590197104Sjkim Status = AcpiHwWrite (Value, &AcpiGbl_FADT.XPm2ControlBlock); 59171867Smsmith break; 59271867Smsmith 59391116Smsmith case ACPI_REGISTER_PM_TIMER: /* 32-bit access */ 59469450Smsmith 595197104Sjkim Status = AcpiHwWrite (Value, &AcpiGbl_FADT.XPmTimerBlock); 59669450Smsmith break; 59769450Smsmith 59891116Smsmith case ACPI_REGISTER_SMI_COMMAND_BLOCK: /* 8-bit access */ 59969450Smsmith 60091116Smsmith /* SMI_CMD is currently always in IO space */ 60169450Smsmith 602193267Sjkim Status = AcpiHwWritePort (AcpiGbl_FADT.SmiCommand, Value, 8); 60369450Smsmith break; 60469450Smsmith 605250838Sjkim default: 60669450Smsmith 607204773Sjkim ACPI_ERROR ((AE_INFO, "Unknown Register ID: 0x%X", 608193267Sjkim RegisterId)); 60999679Siwasaki Status = AE_BAD_PARAMETER; 61069450Smsmith break; 61169450Smsmith } 61269450Smsmith 613193267SjkimExit: 61499679Siwasaki return_ACPI_STATUS (Status); 61569450Smsmith} 61669450Smsmith 61769450Smsmith 61869450Smsmith/****************************************************************************** 61969450Smsmith * 620193267Sjkim * FUNCTION: AcpiHwReadMultiple 62169450Smsmith * 622193267Sjkim * PARAMETERS: Value - Where the register value is returned 623193267Sjkim * RegisterA - First ACPI register (required) 624193267Sjkim * RegisterB - Second ACPI register (optional) 62569450Smsmith * 626117521Snjl * RETURN: Status 62769450Smsmith * 628193267Sjkim * DESCRIPTION: Read from the specified two-part ACPI register (such as PM1 A/B) 62969450Smsmith * 63069450Smsmith ******************************************************************************/ 63169450Smsmith 632193267Sjkimstatic ACPI_STATUS 633193267SjkimAcpiHwReadMultiple ( 63499679Siwasaki UINT32 *Value, 635193267Sjkim ACPI_GENERIC_ADDRESS *RegisterA, 636193267Sjkim ACPI_GENERIC_ADDRESS *RegisterB) 63769450Smsmith{ 638193267Sjkim UINT32 ValueA = 0; 639193267Sjkim UINT32 ValueB = 0; 64099679Siwasaki ACPI_STATUS Status; 64169450Smsmith 64269450Smsmith 643193267Sjkim /* The first register is always required */ 64483174Smsmith 645197104Sjkim Status = AcpiHwRead (&ValueA, RegisterA); 646193267Sjkim if (ACPI_FAILURE (Status)) 64769450Smsmith { 648193267Sjkim return (Status); 64969450Smsmith } 650138287Smarks 651193267Sjkim /* Second register is optional */ 652138287Smarks 653193267Sjkim if (RegisterB->Address) 654138287Smarks { 655197104Sjkim Status = AcpiHwRead (&ValueB, RegisterB); 656193267Sjkim if (ACPI_FAILURE (Status)) 657193267Sjkim { 658193267Sjkim return (Status); 659193267Sjkim } 660138287Smarks } 66169450Smsmith 66269450Smsmith /* 663193267Sjkim * OR the two return values together. No shifting or masking is necessary, 664193267Sjkim * because of how the PM1 registers are defined in the ACPI specification: 665193267Sjkim * 666193267Sjkim * "Although the bits can be split between the two register blocks (each 667193267Sjkim * register block has a unique pointer within the FADT), the bit positions 668193267Sjkim * are maintained. The register block with unimplemented bits (that is, 669193267Sjkim * those implemented in the other register block) always returns zeros, 670193267Sjkim * and writes have no side effects" 67169450Smsmith */ 672193267Sjkim *Value = (ValueA | ValueB); 673193267Sjkim return (AE_OK); 67469450Smsmith} 67569450Smsmith 67669450Smsmith 67769450Smsmith/****************************************************************************** 67869450Smsmith * 679193267Sjkim * FUNCTION: AcpiHwWriteMultiple 68069450Smsmith * 681193267Sjkim * PARAMETERS: Value - The value to write 682193267Sjkim * RegisterA - First ACPI register (required) 683193267Sjkim * RegisterB - Second ACPI register (optional) 68469450Smsmith * 685117521Snjl * RETURN: Status 68669450Smsmith * 687193267Sjkim * DESCRIPTION: Write to the specified two-part ACPI register (such as PM1 A/B) 68869450Smsmith * 68969450Smsmith ******************************************************************************/ 69069450Smsmith 691193267Sjkimstatic ACPI_STATUS 692193267SjkimAcpiHwWriteMultiple ( 69369450Smsmith UINT32 Value, 694193267Sjkim ACPI_GENERIC_ADDRESS *RegisterA, 695193267Sjkim ACPI_GENERIC_ADDRESS *RegisterB) 69669450Smsmith{ 69799679Siwasaki ACPI_STATUS Status; 69869450Smsmith 69969450Smsmith 700193267Sjkim /* The first register is always required */ 70183174Smsmith 702197104Sjkim Status = AcpiHwWrite (Value, RegisterA); 703193267Sjkim if (ACPI_FAILURE (Status)) 70469450Smsmith { 705193267Sjkim return (Status); 70669450Smsmith } 707123315Snjl 70869450Smsmith /* 709193267Sjkim * Second register is optional 710193267Sjkim * 711193267Sjkim * No bit shifting or clearing is necessary, because of how the PM1 712193267Sjkim * registers are defined in the ACPI specification: 713193267Sjkim * 714193267Sjkim * "Although the bits can be split between the two register blocks (each 715193267Sjkim * register block has a unique pointer within the FADT), the bit positions 716193267Sjkim * are maintained. The register block with unimplemented bits (that is, 717193267Sjkim * those implemented in the other register block) always returns zeros, 718193267Sjkim * and writes have no side effects" 71969450Smsmith */ 720193267Sjkim if (RegisterB->Address) 72169450Smsmith { 722197104Sjkim Status = AcpiHwWrite (Value, RegisterB); 72369450Smsmith } 72499679Siwasaki 72599679Siwasaki return (Status); 72669450Smsmith} 727193267Sjkim 728231844Sjkim#endif /* !ACPI_REDUCED_HARDWARE */ 729