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