167754Smsmith/******************************************************************************* 267754Smsmith * 367754Smsmith * Module Name: hwregs - Read/write access functions for the various ACPI 467754Smsmith * control and status registers. 567754Smsmith * 667754Smsmith ******************************************************************************/ 767754Smsmith 8217365Sjkim/* 9281075Sdim * Copyright (C) 2000 - 2015, 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 45193341Sjkim#include <contrib/dev/acpica/include/acpi.h> 46193341Sjkim#include <contrib/dev/acpica/include/accommon.h> 47193341Sjkim#include <contrib/dev/acpica/include/acevents.h> 4867754Smsmith 4977424Smsmith#define _COMPONENT ACPI_HARDWARE 5091116Smsmith ACPI_MODULE_NAME ("hwregs") 5167754Smsmith 5267754Smsmith 53231844Sjkim#if (!ACPI_REDUCED_HARDWARE) 54231844Sjkim 55193267Sjkim/* Local Prototypes */ 56193267Sjkim 57193267Sjkimstatic ACPI_STATUS 58193267SjkimAcpiHwReadMultiple ( 59193267Sjkim UINT32 *Value, 60193267Sjkim ACPI_GENERIC_ADDRESS *RegisterA, 61193267Sjkim ACPI_GENERIC_ADDRESS *RegisterB); 62193267Sjkim 63193267Sjkimstatic ACPI_STATUS 64193267SjkimAcpiHwWriteMultiple ( 65193267Sjkim UINT32 Value, 66193267Sjkim ACPI_GENERIC_ADDRESS *RegisterA, 67193267Sjkim ACPI_GENERIC_ADDRESS *RegisterB); 68193267Sjkim 69231844Sjkim#endif /* !ACPI_REDUCED_HARDWARE */ 70193267Sjkim 71197104Sjkim/****************************************************************************** 72197104Sjkim * 73197104Sjkim * FUNCTION: AcpiHwValidateRegister 74197104Sjkim * 75197104Sjkim * PARAMETERS: Reg - GAS register structure 76197104Sjkim * MaxBitWidth - Max BitWidth supported (32 or 64) 77197104Sjkim * Address - Pointer to where the gas->address 78197104Sjkim * is returned 79197104Sjkim * 80197104Sjkim * RETURN: Status 81197104Sjkim * 82197104Sjkim * DESCRIPTION: Validate the contents of a GAS register. Checks the GAS 83197104Sjkim * pointer, Address, SpaceId, BitWidth, and BitOffset. 84197104Sjkim * 85197104Sjkim ******************************************************************************/ 86197104Sjkim 87197104SjkimACPI_STATUS 88197104SjkimAcpiHwValidateRegister ( 89197104Sjkim ACPI_GENERIC_ADDRESS *Reg, 90197104Sjkim UINT8 MaxBitWidth, 91197104Sjkim UINT64 *Address) 92197104Sjkim{ 93197104Sjkim 94197104Sjkim /* Must have a valid pointer to a GAS structure */ 95197104Sjkim 96197104Sjkim if (!Reg) 97197104Sjkim { 98197104Sjkim return (AE_BAD_PARAMETER); 99197104Sjkim } 100197104Sjkim 101197104Sjkim /* 102197104Sjkim * Copy the target address. This handles possible alignment issues. 103197104Sjkim * Address must not be null. A null address also indicates an optional 104197104Sjkim * ACPI register that is not supported, so no error message. 105197104Sjkim */ 106197104Sjkim ACPI_MOVE_64_TO_64 (Address, &Reg->Address); 107197104Sjkim if (!(*Address)) 108197104Sjkim { 109197104Sjkim return (AE_BAD_ADDRESS); 110197104Sjkim } 111197104Sjkim 112197104Sjkim /* Validate the SpaceID */ 113197104Sjkim 114197104Sjkim if ((Reg->SpaceId != ACPI_ADR_SPACE_SYSTEM_MEMORY) && 115197104Sjkim (Reg->SpaceId != ACPI_ADR_SPACE_SYSTEM_IO)) 116197104Sjkim { 117197104Sjkim ACPI_ERROR ((AE_INFO, 118197104Sjkim "Unsupported address space: 0x%X", Reg->SpaceId)); 119197104Sjkim return (AE_SUPPORT); 120197104Sjkim } 121197104Sjkim 122197104Sjkim /* Validate the BitWidth */ 123197104Sjkim 124197104Sjkim if ((Reg->BitWidth != 8) && 125197104Sjkim (Reg->BitWidth != 16) && 126197104Sjkim (Reg->BitWidth != 32) && 127197104Sjkim (Reg->BitWidth != MaxBitWidth)) 128197104Sjkim { 129197104Sjkim ACPI_ERROR ((AE_INFO, 130197104Sjkim "Unsupported register bit width: 0x%X", Reg->BitWidth)); 131197104Sjkim return (AE_SUPPORT); 132197104Sjkim } 133197104Sjkim 134197104Sjkim /* Validate the BitOffset. Just a warning for now. */ 135197104Sjkim 136197104Sjkim if (Reg->BitOffset != 0) 137197104Sjkim { 138197104Sjkim ACPI_WARNING ((AE_INFO, 139197104Sjkim "Unsupported register bit offset: 0x%X", Reg->BitOffset)); 140197104Sjkim } 141197104Sjkim 142197104Sjkim return (AE_OK); 143197104Sjkim} 144197104Sjkim 145197104Sjkim 146197104Sjkim/****************************************************************************** 147197104Sjkim * 148197104Sjkim * FUNCTION: AcpiHwRead 149197104Sjkim * 150197104Sjkim * PARAMETERS: Value - Where the value is returned 151197104Sjkim * Reg - GAS register structure 152197104Sjkim * 153197104Sjkim * RETURN: Status 154197104Sjkim * 155197104Sjkim * DESCRIPTION: Read from either memory or IO space. This is a 32-bit max 156197104Sjkim * version of AcpiRead, used internally since the overhead of 157197104Sjkim * 64-bit values is not needed. 158197104Sjkim * 159197104Sjkim * LIMITATIONS: <These limitations also apply to AcpiHwWrite> 160197104Sjkim * BitWidth must be exactly 8, 16, or 32. 161197104Sjkim * SpaceID must be SystemMemory or SystemIO. 162197104Sjkim * BitOffset and AccessWidth are currently ignored, as there has 163197104Sjkim * not been a need to implement these. 164197104Sjkim * 165197104Sjkim ******************************************************************************/ 166197104Sjkim 167197104SjkimACPI_STATUS 168197104SjkimAcpiHwRead ( 169197104Sjkim UINT32 *Value, 170197104Sjkim ACPI_GENERIC_ADDRESS *Reg) 171197104Sjkim{ 172197104Sjkim UINT64 Address; 173231844Sjkim UINT64 Value64; 174197104Sjkim ACPI_STATUS Status; 175197104Sjkim 176197104Sjkim 177197104Sjkim ACPI_FUNCTION_NAME (HwRead); 178197104Sjkim 179197104Sjkim 180197104Sjkim /* Validate contents of the GAS register */ 181197104Sjkim 182197104Sjkim Status = AcpiHwValidateRegister (Reg, 32, &Address); 183197104Sjkim if (ACPI_FAILURE (Status)) 184197104Sjkim { 185197104Sjkim return (Status); 186197104Sjkim } 187197104Sjkim 188197104Sjkim /* Initialize entire 32-bit return value to zero */ 189197104Sjkim 190197104Sjkim *Value = 0; 191197104Sjkim 192197104Sjkim /* 193197104Sjkim * Two address spaces supported: Memory or IO. PCI_Config is 194197104Sjkim * not supported here because the GAS structure is insufficient 195197104Sjkim */ 196197104Sjkim if (Reg->SpaceId == ACPI_ADR_SPACE_SYSTEM_MEMORY) 197197104Sjkim { 198197104Sjkim Status = AcpiOsReadMemory ((ACPI_PHYSICAL_ADDRESS) 199231844Sjkim Address, &Value64, Reg->BitWidth); 200231844Sjkim 201231844Sjkim *Value = (UINT32) Value64; 202197104Sjkim } 203197104Sjkim else /* ACPI_ADR_SPACE_SYSTEM_IO, validated earlier */ 204197104Sjkim { 205197104Sjkim Status = AcpiHwReadPort ((ACPI_IO_ADDRESS) 206197104Sjkim Address, Value, Reg->BitWidth); 207197104Sjkim } 208197104Sjkim 209197104Sjkim ACPI_DEBUG_PRINT ((ACPI_DB_IO, 210197104Sjkim "Read: %8.8X width %2d from %8.8X%8.8X (%s)\n", 211197104Sjkim *Value, Reg->BitWidth, ACPI_FORMAT_UINT64 (Address), 212197104Sjkim AcpiUtGetRegionName (Reg->SpaceId))); 213197104Sjkim 214197104Sjkim return (Status); 215197104Sjkim} 216197104Sjkim 217197104Sjkim 218197104Sjkim/****************************************************************************** 219197104Sjkim * 220197104Sjkim * FUNCTION: AcpiHwWrite 221197104Sjkim * 222197104Sjkim * PARAMETERS: Value - Value to be written 223197104Sjkim * Reg - GAS register structure 224197104Sjkim * 225197104Sjkim * RETURN: Status 226197104Sjkim * 227197104Sjkim * DESCRIPTION: Write to either memory or IO space. This is a 32-bit max 228197104Sjkim * version of AcpiWrite, used internally since the overhead of 229197104Sjkim * 64-bit values is not needed. 230197104Sjkim * 231197104Sjkim ******************************************************************************/ 232197104Sjkim 233197104SjkimACPI_STATUS 234197104SjkimAcpiHwWrite ( 235197104Sjkim UINT32 Value, 236197104Sjkim ACPI_GENERIC_ADDRESS *Reg) 237197104Sjkim{ 238197104Sjkim UINT64 Address; 239197104Sjkim ACPI_STATUS Status; 240197104Sjkim 241197104Sjkim 242197104Sjkim ACPI_FUNCTION_NAME (HwWrite); 243197104Sjkim 244197104Sjkim 245197104Sjkim /* Validate contents of the GAS register */ 246197104Sjkim 247197104Sjkim Status = AcpiHwValidateRegister (Reg, 32, &Address); 248197104Sjkim if (ACPI_FAILURE (Status)) 249197104Sjkim { 250197104Sjkim return (Status); 251197104Sjkim } 252197104Sjkim 253197104Sjkim /* 254197104Sjkim * Two address spaces supported: Memory or IO. PCI_Config is 255197104Sjkim * not supported here because the GAS structure is insufficient 256197104Sjkim */ 257197104Sjkim if (Reg->SpaceId == ACPI_ADR_SPACE_SYSTEM_MEMORY) 258197104Sjkim { 259197104Sjkim Status = AcpiOsWriteMemory ((ACPI_PHYSICAL_ADDRESS) 260231844Sjkim Address, (UINT64) Value, Reg->BitWidth); 261197104Sjkim } 262197104Sjkim else /* ACPI_ADR_SPACE_SYSTEM_IO, validated earlier */ 263197104Sjkim { 264197104Sjkim Status = AcpiHwWritePort ((ACPI_IO_ADDRESS) 265197104Sjkim Address, Value, Reg->BitWidth); 266197104Sjkim } 267197104Sjkim 268197104Sjkim ACPI_DEBUG_PRINT ((ACPI_DB_IO, 269197104Sjkim "Wrote: %8.8X width %2d to %8.8X%8.8X (%s)\n", 270197104Sjkim Value, Reg->BitWidth, ACPI_FORMAT_UINT64 (Address), 271197104Sjkim AcpiUtGetRegionName (Reg->SpaceId))); 272197104Sjkim 273197104Sjkim return (Status); 274197104Sjkim} 275197104Sjkim 276197104Sjkim 277231844Sjkim#if (!ACPI_REDUCED_HARDWARE) 27867754Smsmith/******************************************************************************* 27967754Smsmith * 28067754Smsmith * FUNCTION: AcpiHwClearAcpiStatus 28167754Smsmith * 282167802Sjkim * PARAMETERS: None 28367754Smsmith * 284193267Sjkim * RETURN: Status 28567754Smsmith * 28667754Smsmith * DESCRIPTION: Clears all fixed and general purpose status bits 28767754Smsmith * 28867754Smsmith ******************************************************************************/ 28967754Smsmith 29099679SiwasakiACPI_STATUS 291117521SnjlAcpiHwClearAcpiStatus ( 292167802Sjkim void) 29367754Smsmith{ 29491116Smsmith ACPI_STATUS Status; 295167802Sjkim ACPI_CPU_FLAGS LockFlags = 0; 29667754Smsmith 29767754Smsmith 298167802Sjkim ACPI_FUNCTION_TRACE (HwClearAcpiStatus); 29967754Smsmith 30067754Smsmith 301193267Sjkim ACPI_DEBUG_PRINT ((ACPI_DB_IO, "About to write %04X to %8.8X%8.8X\n", 30291116Smsmith ACPI_BITMASK_ALL_FIXED_STATUS, 303193267Sjkim ACPI_FORMAT_UINT64 (AcpiGbl_XPm1aStatus.Address))); 30467754Smsmith 305167802Sjkim LockFlags = AcpiOsAcquireLock (AcpiGbl_HardwareLock); 30667754Smsmith 307193267Sjkim /* Clear the fixed events in PM1 A/B */ 308193267Sjkim 309193267Sjkim Status = AcpiHwRegisterWrite (ACPI_REGISTER_PM1_STATUS, 310151937Sjkim ACPI_BITMASK_ALL_FIXED_STATUS); 311281075Sdim 312281075Sdim AcpiOsReleaseLock (AcpiGbl_HardwareLock, LockFlags); 313281075Sdim 31499679Siwasaki if (ACPI_FAILURE (Status)) 31599679Siwasaki { 316281075Sdim goto Exit; 31799679Siwasaki } 31867754Smsmith 319114237Snjl /* Clear the GPE Bits in all GPE registers in all GPE blocks */ 32067754Smsmith 321193267Sjkim Status = AcpiEvWalkGpeList (AcpiHwClearGpeBlock, NULL); 322117521Snjl 323281075SdimExit: 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