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 - 2016, 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 <contrib/dev/acpica/include/acpi.h> 46 #include <contrib/dev/acpica/include/accommon.h> 47 #include <contrib/dev/acpica/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 = (1 << (Reg->AccessWidth + 2)); 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 32-bit max 251 * version of AcpiRead, used internally since the overhead of 252 * 64-bit values is not needed. 253 * 254 * LIMITATIONS: <These limitations also apply to AcpiHwWrite> 255 * SpaceID must be SystemMemory or SystemIO. 256 * 257 ******************************************************************************/ 258 259 ACPI_STATUS 260 AcpiHwRead ( 261 UINT32 *Value, 262 ACPI_GENERIC_ADDRESS *Reg) 263 { 264 UINT64 Address; 265 UINT8 AccessWidth; 266 UINT32 BitWidth; 267 UINT8 BitOffset; 268 UINT64 Value64; 269 UINT32 Value32; 270 UINT8 Index; 271 ACPI_STATUS Status; 272 273 274 ACPI_FUNCTION_NAME (HwRead); 275 276 277 /* Validate contents of the GAS register */ 278 279 Status = AcpiHwValidateRegister (Reg, 32, &Address); 280 if (ACPI_FAILURE (Status)) 281 { 282 return (Status); 283 } 284 285 /* 286 * Initialize entire 32-bit return value to zero, convert AccessWidth 287 * into number of bits based 288 */ 289 *Value = 0; 290 AccessWidth = AcpiHwGetAccessBitWidth (Address, Reg, 32); 291 BitWidth = Reg->BitOffset + Reg->BitWidth; 292 BitOffset = Reg->BitOffset; 293 294 /* 295 * Two address spaces supported: Memory or IO. PCI_Config is 296 * not supported here because the GAS structure is insufficient 297 */ 298 Index = 0; 299 while (BitWidth) 300 { 301 if (BitOffset >= AccessWidth) 302 { 303 Value32 = 0; 304 BitOffset -= AccessWidth; 305 } 306 else 307 { 308 if (Reg->SpaceId == ACPI_ADR_SPACE_SYSTEM_MEMORY) 309 { 310 Status = AcpiOsReadMemory ((ACPI_PHYSICAL_ADDRESS) 311 Address + Index * ACPI_DIV_8 (AccessWidth), 312 &Value64, AccessWidth); 313 Value32 = (UINT32) Value64; 314 } 315 else /* ACPI_ADR_SPACE_SYSTEM_IO, validated earlier */ 316 { 317 Status = AcpiHwReadPort ((ACPI_IO_ADDRESS) 318 Address + Index * ACPI_DIV_8 (AccessWidth), 319 &Value32, AccessWidth); 320 } 321 } 322 323 /* 324 * Use offset style bit writes because "Index * AccessWidth" is 325 * ensured to be less than 32-bits by AcpiHwValidateRegister(). 326 */ 327 ACPI_SET_BITS (Value, Index * AccessWidth, 328 ACPI_MASK_BITS_ABOVE_32 (AccessWidth), Value32); 329 330 BitWidth -= BitWidth > AccessWidth ? AccessWidth : BitWidth; 331 Index++; 332 } 333 334 ACPI_DEBUG_PRINT ((ACPI_DB_IO, 335 "Read: %8.8X width %2d from %8.8X%8.8X (%s)\n", 336 *Value, AccessWidth, ACPI_FORMAT_UINT64 (Address), 337 AcpiUtGetRegionName (Reg->SpaceId))); 338 339 return (Status); 340 } 341 342 343 /****************************************************************************** 344 * 345 * FUNCTION: AcpiHwWrite 346 * 347 * PARAMETERS: Value - Value to be written 348 * Reg - GAS register structure 349 * 350 * RETURN: Status 351 * 352 * DESCRIPTION: Write to either memory or IO space. This is a 32-bit max 353 * version of AcpiWrite, used internally since the overhead of 354 * 64-bit values is not needed. 355 * 356 ******************************************************************************/ 357 358 ACPI_STATUS 359 AcpiHwWrite ( 360 UINT32 Value, 361 ACPI_GENERIC_ADDRESS *Reg) 362 { 363 UINT64 Address; 364 UINT8 AccessWidth; 365 UINT32 BitWidth; 366 UINT8 BitOffset; 367 UINT64 Value64; 368 UINT32 Value32; 369 UINT8 Index; 370 ACPI_STATUS Status; 371 372 373 ACPI_FUNCTION_NAME (HwWrite); 374 375 376 /* Validate contents of the GAS register */ 377 378 Status = AcpiHwValidateRegister (Reg, 32, &Address); 379 if (ACPI_FAILURE (Status)) 380 { 381 return (Status); 382 } 383 384 /* Convert AccessWidth into number of bits based */ 385 386 AccessWidth = AcpiHwGetAccessBitWidth (Address, Reg, 32); 387 BitWidth = Reg->BitOffset + Reg->BitWidth; 388 BitOffset = Reg->BitOffset; 389 390 /* 391 * Two address spaces supported: Memory or IO. PCI_Config is 392 * not supported here because the GAS structure is insufficient 393 */ 394 Index = 0; 395 while (BitWidth) 396 { 397 /* 398 * Use offset style bit reads because "Index * AccessWidth" is 399 * ensured to be less than 32-bits by AcpiHwValidateRegister(). 400 */ 401 Value32 = ACPI_GET_BITS (&Value, Index * AccessWidth, 402 ACPI_MASK_BITS_ABOVE_32 (AccessWidth)); 403 404 if (BitOffset >= AccessWidth) 405 { 406 BitOffset -= AccessWidth; 407 } 408 else 409 { 410 if (Reg->SpaceId == ACPI_ADR_SPACE_SYSTEM_MEMORY) 411 { 412 Value64 = (UINT64) Value32; 413 Status = AcpiOsWriteMemory ((ACPI_PHYSICAL_ADDRESS) 414 Address + Index * ACPI_DIV_8 (AccessWidth), 415 Value64, AccessWidth); 416 } 417 else /* ACPI_ADR_SPACE_SYSTEM_IO, validated earlier */ 418 { 419 Status = AcpiHwWritePort ((ACPI_IO_ADDRESS) 420 Address + Index * ACPI_DIV_8 (AccessWidth), 421 Value32, AccessWidth); 422 } 423 } 424 425 /* 426 * Index * AccessWidth is ensured to be less than 32-bits by 427 * AcpiHwValidateRegister(). 428 */ 429 BitWidth -= BitWidth > AccessWidth ? AccessWidth : BitWidth; 430 Index++; 431 } 432 433 ACPI_DEBUG_PRINT ((ACPI_DB_IO, 434 "Wrote: %8.8X width %2d to %8.8X%8.8X (%s)\n", 435 Value, AccessWidth, ACPI_FORMAT_UINT64 (Address), 436 AcpiUtGetRegionName (Reg->SpaceId))); 437 438 return (Status); 439 } 440 441 442 #if (!ACPI_REDUCED_HARDWARE) 443 /******************************************************************************* 444 * 445 * FUNCTION: AcpiHwClearAcpiStatus 446 * 447 * PARAMETERS: None 448 * 449 * RETURN: Status 450 * 451 * DESCRIPTION: Clears all fixed and general purpose status bits 452 * 453 ******************************************************************************/ 454 455 ACPI_STATUS 456 AcpiHwClearAcpiStatus ( 457 void) 458 { 459 ACPI_STATUS Status; 460 ACPI_CPU_FLAGS LockFlags = 0; 461 462 463 ACPI_FUNCTION_TRACE (HwClearAcpiStatus); 464 465 466 ACPI_DEBUG_PRINT ((ACPI_DB_IO, "About to write %04X to %8.8X%8.8X\n", 467 ACPI_BITMASK_ALL_FIXED_STATUS, 468 ACPI_FORMAT_UINT64 (AcpiGbl_XPm1aStatus.Address))); 469 470 LockFlags = AcpiOsAcquireLock (AcpiGbl_HardwareLock); 471 472 /* Clear the fixed events in PM1 A/B */ 473 474 Status = AcpiHwRegisterWrite (ACPI_REGISTER_PM1_STATUS, 475 ACPI_BITMASK_ALL_FIXED_STATUS); 476 477 AcpiOsReleaseLock (AcpiGbl_HardwareLock, LockFlags); 478 479 if (ACPI_FAILURE (Status)) 480 { 481 goto Exit; 482 } 483 484 /* Clear the GPE Bits in all GPE registers in all GPE blocks */ 485 486 Status = AcpiEvWalkGpeList (AcpiHwClearGpeBlock, NULL); 487 488 Exit: 489 return_ACPI_STATUS (Status); 490 } 491 492 493 /******************************************************************************* 494 * 495 * FUNCTION: AcpiHwGetBitRegisterInfo 496 * 497 * PARAMETERS: RegisterId - Index of ACPI Register to access 498 * 499 * RETURN: The bitmask to be used when accessing the register 500 * 501 * DESCRIPTION: Map RegisterId into a register bitmask. 502 * 503 ******************************************************************************/ 504 505 ACPI_BIT_REGISTER_INFO * 506 AcpiHwGetBitRegisterInfo ( 507 UINT32 RegisterId) 508 { 509 ACPI_FUNCTION_ENTRY (); 510 511 512 if (RegisterId > ACPI_BITREG_MAX) 513 { 514 ACPI_ERROR ((AE_INFO, "Invalid BitRegister ID: 0x%X", RegisterId)); 515 return (NULL); 516 } 517 518 return (&AcpiGbl_BitRegisterInfo[RegisterId]); 519 } 520 521 522 /****************************************************************************** 523 * 524 * FUNCTION: AcpiHwWritePm1Control 525 * 526 * PARAMETERS: Pm1aControl - Value to be written to PM1A control 527 * Pm1bControl - Value to be written to PM1B control 528 * 529 * RETURN: Status 530 * 531 * DESCRIPTION: Write the PM1 A/B control registers. These registers are 532 * different than than the PM1 A/B status and enable registers 533 * in that different values can be written to the A/B registers. 534 * Most notably, the SLP_TYP bits can be different, as per the 535 * values returned from the _Sx predefined methods. 536 * 537 ******************************************************************************/ 538 539 ACPI_STATUS 540 AcpiHwWritePm1Control ( 541 UINT32 Pm1aControl, 542 UINT32 Pm1bControl) 543 { 544 ACPI_STATUS Status; 545 546 547 ACPI_FUNCTION_TRACE (HwWritePm1Control); 548 549 550 Status = AcpiHwWrite (Pm1aControl, &AcpiGbl_FADT.XPm1aControlBlock); 551 if (ACPI_FAILURE (Status)) 552 { 553 return_ACPI_STATUS (Status); 554 } 555 556 if (AcpiGbl_FADT.XPm1bControlBlock.Address) 557 { 558 Status = AcpiHwWrite (Pm1bControl, &AcpiGbl_FADT.XPm1bControlBlock); 559 } 560 return_ACPI_STATUS (Status); 561 } 562 563 564 /****************************************************************************** 565 * 566 * FUNCTION: AcpiHwRegisterRead 567 * 568 * PARAMETERS: RegisterId - ACPI Register ID 569 * ReturnValue - Where the register value is returned 570 * 571 * RETURN: Status and the value read. 572 * 573 * DESCRIPTION: Read from the specified ACPI register 574 * 575 ******************************************************************************/ 576 577 ACPI_STATUS 578 AcpiHwRegisterRead ( 579 UINT32 RegisterId, 580 UINT32 *ReturnValue) 581 { 582 UINT32 Value = 0; 583 ACPI_STATUS Status; 584 585 586 ACPI_FUNCTION_TRACE (HwRegisterRead); 587 588 589 switch (RegisterId) 590 { 591 case ACPI_REGISTER_PM1_STATUS: /* PM1 A/B: 16-bit access each */ 592 593 Status = AcpiHwReadMultiple (&Value, 594 &AcpiGbl_XPm1aStatus, 595 &AcpiGbl_XPm1bStatus); 596 break; 597 598 case ACPI_REGISTER_PM1_ENABLE: /* PM1 A/B: 16-bit access each */ 599 600 Status = AcpiHwReadMultiple (&Value, 601 &AcpiGbl_XPm1aEnable, 602 &AcpiGbl_XPm1bEnable); 603 break; 604 605 case ACPI_REGISTER_PM1_CONTROL: /* PM1 A/B: 16-bit access each */ 606 607 Status = AcpiHwReadMultiple (&Value, 608 &AcpiGbl_FADT.XPm1aControlBlock, 609 &AcpiGbl_FADT.XPm1bControlBlock); 610 611 /* 612 * Zero the write-only bits. From the ACPI specification, "Hardware 613 * Write-Only Bits": "Upon reads to registers with write-only bits, 614 * software masks out all write-only bits." 615 */ 616 Value &= ~ACPI_PM1_CONTROL_WRITEONLY_BITS; 617 break; 618 619 case ACPI_REGISTER_PM2_CONTROL: /* 8-bit access */ 620 621 Status = AcpiHwRead (&Value, &AcpiGbl_FADT.XPm2ControlBlock); 622 break; 623 624 case ACPI_REGISTER_PM_TIMER: /* 32-bit access */ 625 626 Status = AcpiHwRead (&Value, &AcpiGbl_FADT.XPmTimerBlock); 627 break; 628 629 case ACPI_REGISTER_SMI_COMMAND_BLOCK: /* 8-bit access */ 630 631 Status = AcpiHwReadPort (AcpiGbl_FADT.SmiCommand, &Value, 8); 632 break; 633 634 default: 635 636 ACPI_ERROR ((AE_INFO, "Unknown Register ID: 0x%X", 637 RegisterId)); 638 Status = AE_BAD_PARAMETER; 639 break; 640 } 641 642 if (ACPI_SUCCESS (Status)) 643 { 644 *ReturnValue = Value; 645 } 646 647 return_ACPI_STATUS (Status); 648 } 649 650 651 /****************************************************************************** 652 * 653 * FUNCTION: AcpiHwRegisterWrite 654 * 655 * PARAMETERS: RegisterId - ACPI Register ID 656 * Value - The value to write 657 * 658 * RETURN: Status 659 * 660 * DESCRIPTION: Write to the specified ACPI register 661 * 662 * NOTE: In accordance with the ACPI specification, this function automatically 663 * preserves the value of the following bits, meaning that these bits cannot be 664 * changed via this interface: 665 * 666 * PM1_CONTROL[0] = SCI_EN 667 * PM1_CONTROL[9] 668 * PM1_STATUS[11] 669 * 670 * ACPI References: 671 * 1) Hardware Ignored Bits: When software writes to a register with ignored 672 * bit fields, it preserves the ignored bit fields 673 * 2) SCI_EN: OSPM always preserves this bit position 674 * 675 ******************************************************************************/ 676 677 ACPI_STATUS 678 AcpiHwRegisterWrite ( 679 UINT32 RegisterId, 680 UINT32 Value) 681 { 682 ACPI_STATUS Status; 683 UINT32 ReadValue; 684 685 686 ACPI_FUNCTION_TRACE (HwRegisterWrite); 687 688 689 switch (RegisterId) 690 { 691 case ACPI_REGISTER_PM1_STATUS: /* PM1 A/B: 16-bit access each */ 692 /* 693 * Handle the "ignored" bit in PM1 Status. According to the ACPI 694 * specification, ignored bits are to be preserved when writing. 695 * Normally, this would mean a read/modify/write sequence. However, 696 * preserving a bit in the status register is different. Writing a 697 * one clears the status, and writing a zero preserves the status. 698 * Therefore, we must always write zero to the ignored bit. 699 * 700 * This behavior is clarified in the ACPI 4.0 specification. 701 */ 702 Value &= ~ACPI_PM1_STATUS_PRESERVED_BITS; 703 704 Status = AcpiHwWriteMultiple (Value, 705 &AcpiGbl_XPm1aStatus, 706 &AcpiGbl_XPm1bStatus); 707 break; 708 709 case ACPI_REGISTER_PM1_ENABLE: /* PM1 A/B: 16-bit access each */ 710 711 Status = AcpiHwWriteMultiple (Value, 712 &AcpiGbl_XPm1aEnable, 713 &AcpiGbl_XPm1bEnable); 714 break; 715 716 case ACPI_REGISTER_PM1_CONTROL: /* PM1 A/B: 16-bit access each */ 717 /* 718 * Perform a read first to preserve certain bits (per ACPI spec) 719 * Note: This includes SCI_EN, we never want to change this bit 720 */ 721 Status = AcpiHwReadMultiple (&ReadValue, 722 &AcpiGbl_FADT.XPm1aControlBlock, 723 &AcpiGbl_FADT.XPm1bControlBlock); 724 if (ACPI_FAILURE (Status)) 725 { 726 goto Exit; 727 } 728 729 /* Insert the bits to be preserved */ 730 731 ACPI_INSERT_BITS (Value, ACPI_PM1_CONTROL_PRESERVED_BITS, ReadValue); 732 733 /* Now we can write the data */ 734 735 Status = AcpiHwWriteMultiple (Value, 736 &AcpiGbl_FADT.XPm1aControlBlock, 737 &AcpiGbl_FADT.XPm1bControlBlock); 738 break; 739 740 case ACPI_REGISTER_PM2_CONTROL: /* 8-bit access */ 741 /* 742 * For control registers, all reserved bits must be preserved, 743 * as per the ACPI spec. 744 */ 745 Status = AcpiHwRead (&ReadValue, &AcpiGbl_FADT.XPm2ControlBlock); 746 if (ACPI_FAILURE (Status)) 747 { 748 goto Exit; 749 } 750 751 /* Insert the bits to be preserved */ 752 753 ACPI_INSERT_BITS (Value, ACPI_PM2_CONTROL_PRESERVED_BITS, ReadValue); 754 755 Status = AcpiHwWrite (Value, &AcpiGbl_FADT.XPm2ControlBlock); 756 break; 757 758 case ACPI_REGISTER_PM_TIMER: /* 32-bit access */ 759 760 Status = AcpiHwWrite (Value, &AcpiGbl_FADT.XPmTimerBlock); 761 break; 762 763 case ACPI_REGISTER_SMI_COMMAND_BLOCK: /* 8-bit access */ 764 765 /* SMI_CMD is currently always in IO space */ 766 767 Status = AcpiHwWritePort (AcpiGbl_FADT.SmiCommand, Value, 8); 768 break; 769 770 default: 771 772 ACPI_ERROR ((AE_INFO, "Unknown Register ID: 0x%X", 773 RegisterId)); 774 Status = AE_BAD_PARAMETER; 775 break; 776 } 777 778 Exit: 779 return_ACPI_STATUS (Status); 780 } 781 782 783 /****************************************************************************** 784 * 785 * FUNCTION: AcpiHwReadMultiple 786 * 787 * PARAMETERS: Value - Where the register value is returned 788 * RegisterA - First ACPI register (required) 789 * RegisterB - Second ACPI register (optional) 790 * 791 * RETURN: Status 792 * 793 * DESCRIPTION: Read from the specified two-part ACPI register (such as PM1 A/B) 794 * 795 ******************************************************************************/ 796 797 static ACPI_STATUS 798 AcpiHwReadMultiple ( 799 UINT32 *Value, 800 ACPI_GENERIC_ADDRESS *RegisterA, 801 ACPI_GENERIC_ADDRESS *RegisterB) 802 { 803 UINT32 ValueA = 0; 804 UINT32 ValueB = 0; 805 ACPI_STATUS Status; 806 807 808 /* The first register is always required */ 809 810 Status = AcpiHwRead (&ValueA, RegisterA); 811 if (ACPI_FAILURE (Status)) 812 { 813 return (Status); 814 } 815 816 /* Second register is optional */ 817 818 if (RegisterB->Address) 819 { 820 Status = AcpiHwRead (&ValueB, RegisterB); 821 if (ACPI_FAILURE (Status)) 822 { 823 return (Status); 824 } 825 } 826 827 /* 828 * OR the two return values together. No shifting or masking is necessary, 829 * because of how the PM1 registers are defined in the ACPI specification: 830 * 831 * "Although the bits can be split between the two register blocks (each 832 * register block has a unique pointer within the FADT), the bit positions 833 * are maintained. The register block with unimplemented bits (that is, 834 * those implemented in the other register block) always returns zeros, 835 * and writes have no side effects" 836 */ 837 *Value = (ValueA | ValueB); 838 return (AE_OK); 839 } 840 841 842 /****************************************************************************** 843 * 844 * FUNCTION: AcpiHwWriteMultiple 845 * 846 * PARAMETERS: Value - The value to write 847 * RegisterA - First ACPI register (required) 848 * RegisterB - Second ACPI register (optional) 849 * 850 * RETURN: Status 851 * 852 * DESCRIPTION: Write to the specified two-part ACPI register (such as PM1 A/B) 853 * 854 ******************************************************************************/ 855 856 static ACPI_STATUS 857 AcpiHwWriteMultiple ( 858 UINT32 Value, 859 ACPI_GENERIC_ADDRESS *RegisterA, 860 ACPI_GENERIC_ADDRESS *RegisterB) 861 { 862 ACPI_STATUS Status; 863 864 865 /* The first register is always required */ 866 867 Status = AcpiHwWrite (Value, RegisterA); 868 if (ACPI_FAILURE (Status)) 869 { 870 return (Status); 871 } 872 873 /* 874 * Second register is optional 875 * 876 * No bit shifting or clearing is necessary, because of how the PM1 877 * registers are defined in the ACPI specification: 878 * 879 * "Although the bits can be split between the two register blocks (each 880 * register block has a unique pointer within the FADT), the bit positions 881 * are maintained. The register block with unimplemented bits (that is, 882 * those implemented in the other register block) always returns zeros, 883 * and writes have no side effects" 884 */ 885 if (RegisterB->Address) 886 { 887 Status = AcpiHwWrite (Value, RegisterB); 888 } 889 890 return (Status); 891 } 892 893 #endif /* !ACPI_REDUCED_HARDWARE */ 894