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