167754Smsmith/******************************************************************************* 267754Smsmith * 367754Smsmith * Module Name: hwregs - Read/write access functions for the various ACPI 467754Smsmith * control and status registers. 567754Smsmith * 667754Smsmith ******************************************************************************/ 767754Smsmith 8217365Sjkim/* 9306536Sjkim * Copyright (C) 2000 - 2016, 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 71306536Sjkim 72197104Sjkim/****************************************************************************** 73197104Sjkim * 74197104Sjkim * FUNCTION: AcpiHwValidateRegister 75197104Sjkim * 76197104Sjkim * PARAMETERS: Reg - GAS register structure 77197104Sjkim * MaxBitWidth - Max BitWidth supported (32 or 64) 78197104Sjkim * Address - Pointer to where the gas->address 79197104Sjkim * is returned 80197104Sjkim * 81197104Sjkim * RETURN: Status 82197104Sjkim * 83197104Sjkim * DESCRIPTION: Validate the contents of a GAS register. Checks the GAS 84197104Sjkim * pointer, Address, SpaceId, BitWidth, and BitOffset. 85197104Sjkim * 86197104Sjkim ******************************************************************************/ 87197104Sjkim 88197104SjkimACPI_STATUS 89197104SjkimAcpiHwValidateRegister ( 90197104Sjkim ACPI_GENERIC_ADDRESS *Reg, 91197104Sjkim UINT8 MaxBitWidth, 92197104Sjkim UINT64 *Address) 93197104Sjkim{ 94197104Sjkim 95197104Sjkim /* Must have a valid pointer to a GAS structure */ 96197104Sjkim 97197104Sjkim if (!Reg) 98197104Sjkim { 99197104Sjkim return (AE_BAD_PARAMETER); 100197104Sjkim } 101197104Sjkim 102197104Sjkim /* 103197104Sjkim * Copy the target address. This handles possible alignment issues. 104197104Sjkim * Address must not be null. A null address also indicates an optional 105197104Sjkim * ACPI register that is not supported, so no error message. 106197104Sjkim */ 107197104Sjkim ACPI_MOVE_64_TO_64 (Address, &Reg->Address); 108197104Sjkim if (!(*Address)) 109197104Sjkim { 110197104Sjkim return (AE_BAD_ADDRESS); 111197104Sjkim } 112197104Sjkim 113197104Sjkim /* Validate the SpaceID */ 114197104Sjkim 115197104Sjkim if ((Reg->SpaceId != ACPI_ADR_SPACE_SYSTEM_MEMORY) && 116197104Sjkim (Reg->SpaceId != ACPI_ADR_SPACE_SYSTEM_IO)) 117197104Sjkim { 118197104Sjkim ACPI_ERROR ((AE_INFO, 119197104Sjkim "Unsupported address space: 0x%X", Reg->SpaceId)); 120197104Sjkim return (AE_SUPPORT); 121197104Sjkim } 122197104Sjkim 123197104Sjkim /* Validate the BitWidth */ 124197104Sjkim 125197104Sjkim if ((Reg->BitWidth != 8) && 126197104Sjkim (Reg->BitWidth != 16) && 127197104Sjkim (Reg->BitWidth != 32) && 128197104Sjkim (Reg->BitWidth != MaxBitWidth)) 129197104Sjkim { 130197104Sjkim ACPI_ERROR ((AE_INFO, 131197104Sjkim "Unsupported register bit width: 0x%X", Reg->BitWidth)); 132197104Sjkim return (AE_SUPPORT); 133197104Sjkim } 134197104Sjkim 135197104Sjkim /* Validate the BitOffset. Just a warning for now. */ 136197104Sjkim 137197104Sjkim if (Reg->BitOffset != 0) 138197104Sjkim { 139197104Sjkim ACPI_WARNING ((AE_INFO, 140197104Sjkim "Unsupported register bit offset: 0x%X", Reg->BitOffset)); 141197104Sjkim } 142197104Sjkim 143197104Sjkim return (AE_OK); 144197104Sjkim} 145197104Sjkim 146197104Sjkim 147197104Sjkim/****************************************************************************** 148197104Sjkim * 149197104Sjkim * FUNCTION: AcpiHwRead 150197104Sjkim * 151197104Sjkim * PARAMETERS: Value - Where the value is returned 152197104Sjkim * Reg - GAS register structure 153197104Sjkim * 154197104Sjkim * RETURN: Status 155197104Sjkim * 156197104Sjkim * DESCRIPTION: Read from either memory or IO space. This is a 32-bit max 157197104Sjkim * version of AcpiRead, used internally since the overhead of 158197104Sjkim * 64-bit values is not needed. 159197104Sjkim * 160197104Sjkim * LIMITATIONS: <These limitations also apply to AcpiHwWrite> 161197104Sjkim * BitWidth must be exactly 8, 16, or 32. 162197104Sjkim * SpaceID must be SystemMemory or SystemIO. 163197104Sjkim * BitOffset and AccessWidth are currently ignored, as there has 164197104Sjkim * not been a need to implement these. 165197104Sjkim * 166197104Sjkim ******************************************************************************/ 167197104Sjkim 168197104SjkimACPI_STATUS 169197104SjkimAcpiHwRead ( 170197104Sjkim UINT32 *Value, 171197104Sjkim ACPI_GENERIC_ADDRESS *Reg) 172197104Sjkim{ 173197104Sjkim UINT64 Address; 174231844Sjkim UINT64 Value64; 175197104Sjkim ACPI_STATUS Status; 176197104Sjkim 177197104Sjkim 178197104Sjkim ACPI_FUNCTION_NAME (HwRead); 179197104Sjkim 180197104Sjkim 181197104Sjkim /* Validate contents of the GAS register */ 182197104Sjkim 183197104Sjkim Status = AcpiHwValidateRegister (Reg, 32, &Address); 184197104Sjkim if (ACPI_FAILURE (Status)) 185197104Sjkim { 186197104Sjkim return (Status); 187197104Sjkim } 188197104Sjkim 189197104Sjkim /* Initialize entire 32-bit return value to zero */ 190197104Sjkim 191197104Sjkim *Value = 0; 192197104Sjkim 193197104Sjkim /* 194197104Sjkim * Two address spaces supported: Memory or IO. PCI_Config is 195197104Sjkim * not supported here because the GAS structure is insufficient 196197104Sjkim */ 197197104Sjkim if (Reg->SpaceId == ACPI_ADR_SPACE_SYSTEM_MEMORY) 198197104Sjkim { 199197104Sjkim Status = AcpiOsReadMemory ((ACPI_PHYSICAL_ADDRESS) 200306536Sjkim Address, &Value64, Reg->BitWidth); 201231844Sjkim 202231844Sjkim *Value = (UINT32) Value64; 203197104Sjkim } 204197104Sjkim else /* ACPI_ADR_SPACE_SYSTEM_IO, validated earlier */ 205197104Sjkim { 206197104Sjkim Status = AcpiHwReadPort ((ACPI_IO_ADDRESS) 207306536Sjkim Address, Value, Reg->BitWidth); 208197104Sjkim } 209197104Sjkim 210197104Sjkim ACPI_DEBUG_PRINT ((ACPI_DB_IO, 211197104Sjkim "Read: %8.8X width %2d from %8.8X%8.8X (%s)\n", 212197104Sjkim *Value, Reg->BitWidth, ACPI_FORMAT_UINT64 (Address), 213197104Sjkim AcpiUtGetRegionName (Reg->SpaceId))); 214197104Sjkim 215197104Sjkim return (Status); 216197104Sjkim} 217197104Sjkim 218197104Sjkim 219197104Sjkim/****************************************************************************** 220197104Sjkim * 221197104Sjkim * FUNCTION: AcpiHwWrite 222197104Sjkim * 223197104Sjkim * PARAMETERS: Value - Value to be written 224197104Sjkim * Reg - GAS register structure 225197104Sjkim * 226197104Sjkim * RETURN: Status 227197104Sjkim * 228197104Sjkim * DESCRIPTION: Write to either memory or IO space. This is a 32-bit max 229197104Sjkim * version of AcpiWrite, used internally since the overhead of 230197104Sjkim * 64-bit values is not needed. 231197104Sjkim * 232197104Sjkim ******************************************************************************/ 233197104Sjkim 234197104SjkimACPI_STATUS 235197104SjkimAcpiHwWrite ( 236197104Sjkim UINT32 Value, 237197104Sjkim ACPI_GENERIC_ADDRESS *Reg) 238197104Sjkim{ 239197104Sjkim UINT64 Address; 240197104Sjkim ACPI_STATUS Status; 241197104Sjkim 242197104Sjkim 243197104Sjkim ACPI_FUNCTION_NAME (HwWrite); 244197104Sjkim 245197104Sjkim 246197104Sjkim /* Validate contents of the GAS register */ 247197104Sjkim 248197104Sjkim Status = AcpiHwValidateRegister (Reg, 32, &Address); 249197104Sjkim if (ACPI_FAILURE (Status)) 250197104Sjkim { 251197104Sjkim return (Status); 252197104Sjkim } 253197104Sjkim 254197104Sjkim /* 255197104Sjkim * Two address spaces supported: Memory or IO. PCI_Config is 256197104Sjkim * not supported here because the GAS structure is insufficient 257197104Sjkim */ 258197104Sjkim if (Reg->SpaceId == ACPI_ADR_SPACE_SYSTEM_MEMORY) 259197104Sjkim { 260197104Sjkim Status = AcpiOsWriteMemory ((ACPI_PHYSICAL_ADDRESS) 261306536Sjkim Address, (UINT64) Value, Reg->BitWidth); 262197104Sjkim } 263197104Sjkim else /* ACPI_ADR_SPACE_SYSTEM_IO, validated earlier */ 264197104Sjkim { 265197104Sjkim Status = AcpiHwWritePort ((ACPI_IO_ADDRESS) 266306536Sjkim Address, Value, Reg->BitWidth); 267197104Sjkim } 268197104Sjkim 269197104Sjkim ACPI_DEBUG_PRINT ((ACPI_DB_IO, 270197104Sjkim "Wrote: %8.8X width %2d to %8.8X%8.8X (%s)\n", 271197104Sjkim Value, Reg->BitWidth, ACPI_FORMAT_UINT64 (Address), 272197104Sjkim AcpiUtGetRegionName (Reg->SpaceId))); 273197104Sjkim 274197104Sjkim return (Status); 275197104Sjkim} 276197104Sjkim 277197104Sjkim 278231844Sjkim#if (!ACPI_REDUCED_HARDWARE) 27967754Smsmith/******************************************************************************* 28067754Smsmith * 28167754Smsmith * FUNCTION: AcpiHwClearAcpiStatus 28267754Smsmith * 283167802Sjkim * PARAMETERS: None 28467754Smsmith * 285193267Sjkim * RETURN: Status 28667754Smsmith * 28767754Smsmith * DESCRIPTION: Clears all fixed and general purpose status bits 28867754Smsmith * 28967754Smsmith ******************************************************************************/ 29067754Smsmith 29199679SiwasakiACPI_STATUS 292117521SnjlAcpiHwClearAcpiStatus ( 293167802Sjkim void) 29467754Smsmith{ 29591116Smsmith ACPI_STATUS Status; 296167802Sjkim ACPI_CPU_FLAGS LockFlags = 0; 29767754Smsmith 29867754Smsmith 299167802Sjkim ACPI_FUNCTION_TRACE (HwClearAcpiStatus); 30067754Smsmith 30167754Smsmith 302193267Sjkim ACPI_DEBUG_PRINT ((ACPI_DB_IO, "About to write %04X to %8.8X%8.8X\n", 30391116Smsmith ACPI_BITMASK_ALL_FIXED_STATUS, 304193267Sjkim ACPI_FORMAT_UINT64 (AcpiGbl_XPm1aStatus.Address))); 30567754Smsmith 306167802Sjkim LockFlags = AcpiOsAcquireLock (AcpiGbl_HardwareLock); 30767754Smsmith 308193267Sjkim /* Clear the fixed events in PM1 A/B */ 309193267Sjkim 310193267Sjkim Status = AcpiHwRegisterWrite (ACPI_REGISTER_PM1_STATUS, 311306536Sjkim ACPI_BITMASK_ALL_FIXED_STATUS); 312281075Sdim 313281075Sdim AcpiOsReleaseLock (AcpiGbl_HardwareLock, LockFlags); 314281075Sdim 31599679Siwasaki if (ACPI_FAILURE (Status)) 31699679Siwasaki { 317281075Sdim goto Exit; 31899679Siwasaki } 31967754Smsmith 320114237Snjl /* Clear the GPE Bits in all GPE registers in all GPE blocks */ 32167754Smsmith 322193267Sjkim Status = AcpiEvWalkGpeList (AcpiHwClearGpeBlock, NULL); 323117521Snjl 324281075SdimExit: 32599679Siwasaki return_ACPI_STATUS (Status); 32667754Smsmith} 32767754Smsmith 32867754Smsmith 32967754Smsmith/******************************************************************************* 33067754Smsmith * 331231844Sjkim * FUNCTION: AcpiHwGetBitRegisterInfo 33267754Smsmith * 33399679Siwasaki * PARAMETERS: RegisterId - Index of ACPI Register to access 334102550Siwasaki * 335151937Sjkim * RETURN: The bitmask to be used when accessing the register 33691116Smsmith * 337151937Sjkim * DESCRIPTION: Map RegisterId into a register bitmask. 33891116Smsmith * 33991116Smsmith ******************************************************************************/ 34091116Smsmith 34191116SmsmithACPI_BIT_REGISTER_INFO * 34291116SmsmithAcpiHwGetBitRegisterInfo ( 34391116Smsmith UINT32 RegisterId) 34491116Smsmith{ 345167802Sjkim ACPI_FUNCTION_ENTRY (); 34691116Smsmith 34791116Smsmith 34891116Smsmith if (RegisterId > ACPI_BITREG_MAX) 34991116Smsmith { 350204773Sjkim ACPI_ERROR ((AE_INFO, "Invalid BitRegister ID: 0x%X", RegisterId)); 35191116Smsmith return (NULL); 35291116Smsmith } 35391116Smsmith 35491116Smsmith return (&AcpiGbl_BitRegisterInfo[RegisterId]); 35591116Smsmith} 35691116Smsmith 35791116Smsmith 358193267Sjkim/****************************************************************************** 35991116Smsmith * 360193267Sjkim * FUNCTION: AcpiHwWritePm1Control 36191116Smsmith * 362193267Sjkim * PARAMETERS: Pm1aControl - Value to be written to PM1A control 363193267Sjkim * Pm1bControl - Value to be written to PM1B control 36467754Smsmith * 365138287Smarks * RETURN: Status 36691116Smsmith * 367193267Sjkim * DESCRIPTION: Write the PM1 A/B control registers. These registers are 368193267Sjkim * different than than the PM1 A/B status and enable registers 369193267Sjkim * in that different values can be written to the A/B registers. 370193267Sjkim * Most notably, the SLP_TYP bits can be different, as per the 371193267Sjkim * values returned from the _Sx predefined methods. 37291116Smsmith * 37391116Smsmith ******************************************************************************/ 37467754Smsmith 37599679SiwasakiACPI_STATUS 376193267SjkimAcpiHwWritePm1Control ( 377193267Sjkim UINT32 Pm1aControl, 378193267Sjkim UINT32 Pm1bControl) 37991116Smsmith{ 38099679Siwasaki ACPI_STATUS Status; 38167754Smsmith 38267754Smsmith 383193267Sjkim ACPI_FUNCTION_TRACE (HwWritePm1Control); 38467754Smsmith 38567754Smsmith 386197104Sjkim Status = AcpiHwWrite (Pm1aControl, &AcpiGbl_FADT.XPm1aControlBlock); 38799679Siwasaki if (ACPI_FAILURE (Status)) 38899679Siwasaki { 389193267Sjkim return_ACPI_STATUS (Status); 39099679Siwasaki } 39167754Smsmith 392193267Sjkim if (AcpiGbl_FADT.XPm1bControlBlock.Address) 39391116Smsmith { 394197104Sjkim Status = AcpiHwWrite (Pm1bControl, &AcpiGbl_FADT.XPm1bControlBlock); 39567754Smsmith } 39699679Siwasaki return_ACPI_STATUS (Status); 39767754Smsmith} 39869450Smsmith 39969450Smsmith 40069450Smsmith/****************************************************************************** 40169450Smsmith * 40269450Smsmith * FUNCTION: AcpiHwRegisterRead 40369450Smsmith * 404193267Sjkim * PARAMETERS: RegisterId - ACPI Register ID 405151937Sjkim * ReturnValue - Where the register value is returned 40669450Smsmith * 407138287Smarks * RETURN: Status and the value read. 40869450Smsmith * 409167802Sjkim * DESCRIPTION: Read from the specified ACPI register 41069450Smsmith * 41169450Smsmith ******************************************************************************/ 41269450Smsmith 41399679SiwasakiACPI_STATUS 41469450SmsmithAcpiHwRegisterRead ( 41599679Siwasaki UINT32 RegisterId, 41699679Siwasaki UINT32 *ReturnValue) 41769450Smsmith{ 418193267Sjkim UINT32 Value = 0; 41999679Siwasaki ACPI_STATUS Status; 42069450Smsmith 42177424Smsmith 422167802Sjkim ACPI_FUNCTION_TRACE (HwRegisterRead); 42369450Smsmith 42477424Smsmith 42591116Smsmith switch (RegisterId) 42669450Smsmith { 427193267Sjkim case ACPI_REGISTER_PM1_STATUS: /* PM1 A/B: 16-bit access each */ 42869450Smsmith 429193267Sjkim Status = AcpiHwReadMultiple (&Value, 430306536Sjkim &AcpiGbl_XPm1aStatus, 431306536Sjkim &AcpiGbl_XPm1bStatus); 43269450Smsmith break; 43369450Smsmith 434193267Sjkim case ACPI_REGISTER_PM1_ENABLE: /* PM1 A/B: 16-bit access each */ 43569450Smsmith 436193267Sjkim Status = AcpiHwReadMultiple (&Value, 437306536Sjkim &AcpiGbl_XPm1aEnable, 438306536Sjkim &AcpiGbl_XPm1bEnable); 43969450Smsmith break; 44069450Smsmith 441193267Sjkim case ACPI_REGISTER_PM1_CONTROL: /* PM1 A/B: 16-bit access each */ 44269450Smsmith 443193267Sjkim Status = AcpiHwReadMultiple (&Value, 444306536Sjkim &AcpiGbl_FADT.XPm1aControlBlock, 445306536Sjkim &AcpiGbl_FADT.XPm1bControlBlock); 44699679Siwasaki 447193267Sjkim /* 448193267Sjkim * Zero the write-only bits. From the ACPI specification, "Hardware 449193267Sjkim * Write-Only Bits": "Upon reads to registers with write-only bits, 450193267Sjkim * software masks out all write-only bits." 451193267Sjkim */ 452193267Sjkim Value &= ~ACPI_PM1_CONTROL_WRITEONLY_BITS; 45369450Smsmith break; 45469450Smsmith 45591116Smsmith case ACPI_REGISTER_PM2_CONTROL: /* 8-bit access */ 45669450Smsmith 457197104Sjkim Status = AcpiHwRead (&Value, &AcpiGbl_FADT.XPm2ControlBlock); 45869450Smsmith break; 45969450Smsmith 46091116Smsmith case ACPI_REGISTER_PM_TIMER: /* 32-bit access */ 46169450Smsmith 462197104Sjkim Status = AcpiHwRead (&Value, &AcpiGbl_FADT.XPmTimerBlock); 46369450Smsmith break; 46469450Smsmith 46591116Smsmith case ACPI_REGISTER_SMI_COMMAND_BLOCK: /* 8-bit access */ 46669450Smsmith 467193267Sjkim Status = AcpiHwReadPort (AcpiGbl_FADT.SmiCommand, &Value, 8); 46869450Smsmith break; 46969450Smsmith 470250838Sjkim default: 471193267Sjkim 472204773Sjkim ACPI_ERROR ((AE_INFO, "Unknown Register ID: 0x%X", 473151937Sjkim RegisterId)); 47499679Siwasaki Status = AE_BAD_PARAMETER; 47569450Smsmith break; 47669450Smsmith } 47769450Smsmith 47899679Siwasaki if (ACPI_SUCCESS (Status)) 47999679Siwasaki { 480193267Sjkim *ReturnValue = Value; 48199679Siwasaki } 48299679Siwasaki 48399679Siwasaki return_ACPI_STATUS (Status); 48469450Smsmith} 48569450Smsmith 48669450Smsmith 48769450Smsmith/****************************************************************************** 48869450Smsmith * 48969450Smsmith * FUNCTION: AcpiHwRegisterWrite 49069450Smsmith * 491193267Sjkim * PARAMETERS: RegisterId - ACPI Register ID 492138287Smarks * Value - The value to write 49369450Smsmith * 494138287Smarks * RETURN: Status 49569450Smsmith * 496167802Sjkim * DESCRIPTION: Write to the specified ACPI register 49769450Smsmith * 498167802Sjkim * NOTE: In accordance with the ACPI specification, this function automatically 499167802Sjkim * preserves the value of the following bits, meaning that these bits cannot be 500167802Sjkim * changed via this interface: 501167802Sjkim * 502167802Sjkim * PM1_CONTROL[0] = SCI_EN 503167802Sjkim * PM1_CONTROL[9] 504167802Sjkim * PM1_STATUS[11] 505167802Sjkim * 506167802Sjkim * ACPI References: 507167802Sjkim * 1) Hardware Ignored Bits: When software writes to a register with ignored 508167802Sjkim * bit fields, it preserves the ignored bit fields 509167802Sjkim * 2) SCI_EN: OSPM always preserves this bit position 510167802Sjkim * 51169450Smsmith ******************************************************************************/ 51269450Smsmith 51399679SiwasakiACPI_STATUS 51469450SmsmithAcpiHwRegisterWrite ( 51569450Smsmith UINT32 RegisterId, 51669450Smsmith UINT32 Value) 51769450Smsmith{ 51899679Siwasaki ACPI_STATUS Status; 519167802Sjkim UINT32 ReadValue; 52069450Smsmith 52169450Smsmith 522167802Sjkim ACPI_FUNCTION_TRACE (HwRegisterWrite); 52369450Smsmith 52483174Smsmith 52591116Smsmith switch (RegisterId) 52669450Smsmith { 527193267Sjkim case ACPI_REGISTER_PM1_STATUS: /* PM1 A/B: 16-bit access each */ 528193267Sjkim /* 529193267Sjkim * Handle the "ignored" bit in PM1 Status. According to the ACPI 530193267Sjkim * specification, ignored bits are to be preserved when writing. 531193267Sjkim * Normally, this would mean a read/modify/write sequence. However, 532193267Sjkim * preserving a bit in the status register is different. Writing a 533193267Sjkim * one clears the status, and writing a zero preserves the status. 534193267Sjkim * Therefore, we must always write zero to the ignored bit. 535193267Sjkim * 536193267Sjkim * This behavior is clarified in the ACPI 4.0 specification. 537193267Sjkim */ 538193267Sjkim Value &= ~ACPI_PM1_STATUS_PRESERVED_BITS; 53969450Smsmith 540193267Sjkim Status = AcpiHwWriteMultiple (Value, 541306536Sjkim &AcpiGbl_XPm1aStatus, 542306536Sjkim &AcpiGbl_XPm1bStatus); 54369450Smsmith break; 54469450Smsmith 545193267Sjkim case ACPI_REGISTER_PM1_ENABLE: /* PM1 A/B: 16-bit access each */ 54669450Smsmith 547193267Sjkim Status = AcpiHwWriteMultiple (Value, 548306536Sjkim &AcpiGbl_XPm1aEnable, 549306536Sjkim &AcpiGbl_XPm1bEnable); 55069450Smsmith break; 55169450Smsmith 552193267Sjkim case ACPI_REGISTER_PM1_CONTROL: /* PM1 A/B: 16-bit access each */ 553167802Sjkim /* 554167802Sjkim * Perform a read first to preserve certain bits (per ACPI spec) 555167802Sjkim * Note: This includes SCI_EN, we never want to change this bit 556167802Sjkim */ 557193267Sjkim Status = AcpiHwReadMultiple (&ReadValue, 558306536Sjkim &AcpiGbl_FADT.XPm1aControlBlock, 559306536Sjkim &AcpiGbl_FADT.XPm1bControlBlock); 56099679Siwasaki if (ACPI_FAILURE (Status)) 56199679Siwasaki { 562193267Sjkim goto Exit; 56399679Siwasaki } 56499679Siwasaki 565167802Sjkim /* Insert the bits to be preserved */ 566167802Sjkim 567167802Sjkim ACPI_INSERT_BITS (Value, ACPI_PM1_CONTROL_PRESERVED_BITS, ReadValue); 568167802Sjkim 569167802Sjkim /* Now we can write the data */ 570167802Sjkim 571193267Sjkim Status = AcpiHwWriteMultiple (Value, 572306536Sjkim &AcpiGbl_FADT.XPm1aControlBlock, 573306536Sjkim &AcpiGbl_FADT.XPm1bControlBlock); 57471867Smsmith break; 57569450Smsmith 576193267Sjkim case ACPI_REGISTER_PM2_CONTROL: /* 8-bit access */ 577193267Sjkim /* 578193267Sjkim * For control registers, all reserved bits must be preserved, 579193267Sjkim * as per the ACPI spec. 580193267Sjkim */ 581197104Sjkim Status = AcpiHwRead (&ReadValue, &AcpiGbl_FADT.XPm2ControlBlock); 582193267Sjkim if (ACPI_FAILURE (Status)) 583193267Sjkim { 584193267Sjkim goto Exit; 585193267Sjkim } 58669450Smsmith 587193267Sjkim /* Insert the bits to be preserved */ 58869450Smsmith 589193267Sjkim ACPI_INSERT_BITS (Value, ACPI_PM2_CONTROL_PRESERVED_BITS, ReadValue); 59071867Smsmith 591197104Sjkim Status = AcpiHwWrite (Value, &AcpiGbl_FADT.XPm2ControlBlock); 59271867Smsmith break; 59371867Smsmith 59491116Smsmith case ACPI_REGISTER_PM_TIMER: /* 32-bit access */ 59569450Smsmith 596197104Sjkim Status = AcpiHwWrite (Value, &AcpiGbl_FADT.XPmTimerBlock); 59769450Smsmith break; 59869450Smsmith 59991116Smsmith case ACPI_REGISTER_SMI_COMMAND_BLOCK: /* 8-bit access */ 60069450Smsmith 60191116Smsmith /* SMI_CMD is currently always in IO space */ 60269450Smsmith 603193267Sjkim Status = AcpiHwWritePort (AcpiGbl_FADT.SmiCommand, Value, 8); 60469450Smsmith break; 60569450Smsmith 606250838Sjkim default: 60769450Smsmith 608204773Sjkim ACPI_ERROR ((AE_INFO, "Unknown Register ID: 0x%X", 609193267Sjkim RegisterId)); 61099679Siwasaki Status = AE_BAD_PARAMETER; 61169450Smsmith break; 61269450Smsmith } 61369450Smsmith 614193267SjkimExit: 61599679Siwasaki return_ACPI_STATUS (Status); 61669450Smsmith} 61769450Smsmith 61869450Smsmith 61969450Smsmith/****************************************************************************** 62069450Smsmith * 621193267Sjkim * FUNCTION: AcpiHwReadMultiple 62269450Smsmith * 623193267Sjkim * PARAMETERS: Value - Where the register value is returned 624193267Sjkim * RegisterA - First ACPI register (required) 625193267Sjkim * RegisterB - Second ACPI register (optional) 62669450Smsmith * 627117521Snjl * RETURN: Status 62869450Smsmith * 629193267Sjkim * DESCRIPTION: Read from the specified two-part ACPI register (such as PM1 A/B) 63069450Smsmith * 63169450Smsmith ******************************************************************************/ 63269450Smsmith 633193267Sjkimstatic ACPI_STATUS 634193267SjkimAcpiHwReadMultiple ( 63599679Siwasaki UINT32 *Value, 636193267Sjkim ACPI_GENERIC_ADDRESS *RegisterA, 637193267Sjkim ACPI_GENERIC_ADDRESS *RegisterB) 63869450Smsmith{ 639193267Sjkim UINT32 ValueA = 0; 640193267Sjkim UINT32 ValueB = 0; 64199679Siwasaki ACPI_STATUS Status; 64269450Smsmith 64369450Smsmith 644193267Sjkim /* The first register is always required */ 64583174Smsmith 646197104Sjkim Status = AcpiHwRead (&ValueA, RegisterA); 647193267Sjkim if (ACPI_FAILURE (Status)) 64869450Smsmith { 649193267Sjkim return (Status); 65069450Smsmith } 651138287Smarks 652193267Sjkim /* Second register is optional */ 653138287Smarks 654193267Sjkim if (RegisterB->Address) 655138287Smarks { 656197104Sjkim Status = AcpiHwRead (&ValueB, RegisterB); 657193267Sjkim if (ACPI_FAILURE (Status)) 658193267Sjkim { 659193267Sjkim return (Status); 660193267Sjkim } 661138287Smarks } 66269450Smsmith 66369450Smsmith /* 664193267Sjkim * OR the two return values together. No shifting or masking is necessary, 665193267Sjkim * because of how the PM1 registers are defined in the ACPI specification: 666193267Sjkim * 667193267Sjkim * "Although the bits can be split between the two register blocks (each 668193267Sjkim * register block has a unique pointer within the FADT), the bit positions 669193267Sjkim * are maintained. The register block with unimplemented bits (that is, 670193267Sjkim * those implemented in the other register block) always returns zeros, 671193267Sjkim * and writes have no side effects" 67269450Smsmith */ 673193267Sjkim *Value = (ValueA | ValueB); 674193267Sjkim return (AE_OK); 67569450Smsmith} 67669450Smsmith 67769450Smsmith 67869450Smsmith/****************************************************************************** 67969450Smsmith * 680193267Sjkim * FUNCTION: AcpiHwWriteMultiple 68169450Smsmith * 682193267Sjkim * PARAMETERS: Value - The value to write 683193267Sjkim * RegisterA - First ACPI register (required) 684193267Sjkim * RegisterB - Second ACPI register (optional) 68569450Smsmith * 686117521Snjl * RETURN: Status 68769450Smsmith * 688193267Sjkim * DESCRIPTION: Write to the specified two-part ACPI register (such as PM1 A/B) 68969450Smsmith * 69069450Smsmith ******************************************************************************/ 69169450Smsmith 692193267Sjkimstatic ACPI_STATUS 693193267SjkimAcpiHwWriteMultiple ( 69469450Smsmith UINT32 Value, 695193267Sjkim ACPI_GENERIC_ADDRESS *RegisterA, 696193267Sjkim ACPI_GENERIC_ADDRESS *RegisterB) 69769450Smsmith{ 69899679Siwasaki ACPI_STATUS Status; 69969450Smsmith 70069450Smsmith 701193267Sjkim /* The first register is always required */ 70283174Smsmith 703197104Sjkim Status = AcpiHwWrite (Value, RegisterA); 704193267Sjkim if (ACPI_FAILURE (Status)) 70569450Smsmith { 706193267Sjkim return (Status); 70769450Smsmith } 708123315Snjl 70969450Smsmith /* 710193267Sjkim * Second register is optional 711193267Sjkim * 712193267Sjkim * No bit shifting or clearing is necessary, because of how the PM1 713193267Sjkim * registers are defined in the ACPI specification: 714193267Sjkim * 715193267Sjkim * "Although the bits can be split between the two register blocks (each 716193267Sjkim * register block has a unique pointer within the FADT), the bit positions 717193267Sjkim * are maintained. The register block with unimplemented bits (that is, 718193267Sjkim * those implemented in the other register block) always returns zeros, 719193267Sjkim * and writes have no side effects" 72069450Smsmith */ 721193267Sjkim if (RegisterB->Address) 72269450Smsmith { 723197104Sjkim Status = AcpiHwWrite (Value, RegisterB); 72469450Smsmith } 72599679Siwasaki 72699679Siwasaki return (Status); 72769450Smsmith} 728193267Sjkim 729231844Sjkim#endif /* !ACPI_REDUCED_HARDWARE */ 730