0001
0002
0003
0004
0005
0006
0007
0008
0009 #include <acpi/acpi.h>
0010 #include "accommon.h"
0011 #include "acevents.h"
0012
0013 #define _COMPONENT ACPI_HARDWARE
0014 ACPI_MODULE_NAME("hwregs")
0015
0016 #if (!ACPI_REDUCED_HARDWARE)
0017
0018 static u8
0019 acpi_hw_get_access_bit_width(u64 address,
0020 struct acpi_generic_address *reg,
0021 u8 max_bit_width);
0022
0023 static acpi_status
0024 acpi_hw_read_multiple(u32 *value,
0025 struct acpi_generic_address *register_a,
0026 struct acpi_generic_address *register_b);
0027
0028 static acpi_status
0029 acpi_hw_write_multiple(u32 value,
0030 struct acpi_generic_address *register_a,
0031 struct acpi_generic_address *register_b);
0032
0033 #endif
0034
0035
0036
0037
0038
0039
0040
0041
0042
0043
0044
0045
0046
0047
0048
0049 static u8
0050 acpi_hw_get_access_bit_width(u64 address,
0051 struct acpi_generic_address *reg, u8 max_bit_width)
0052 {
0053 u8 access_bit_width;
0054
0055
0056
0057
0058
0059
0060
0061
0062
0063
0064
0065
0066
0067
0068
0069 if (!reg->bit_offset && reg->bit_width &&
0070 ACPI_IS_POWER_OF_TWO(reg->bit_width) &&
0071 ACPI_IS_ALIGNED(reg->bit_width, 8)) {
0072 access_bit_width = reg->bit_width;
0073 } else if (reg->access_width) {
0074 access_bit_width = ACPI_ACCESS_BIT_WIDTH(reg->access_width);
0075 } else {
0076 access_bit_width =
0077 ACPI_ROUND_UP_POWER_OF_TWO_8(reg->bit_offset +
0078 reg->bit_width);
0079 if (access_bit_width <= 8) {
0080 access_bit_width = 8;
0081 } else {
0082 while (!ACPI_IS_ALIGNED(address, access_bit_width >> 3)) {
0083 access_bit_width >>= 1;
0084 }
0085 }
0086 }
0087
0088
0089
0090 if (reg->space_id == ACPI_ADR_SPACE_SYSTEM_IO) {
0091 max_bit_width = 32;
0092 }
0093
0094
0095
0096
0097
0098
0099 if (access_bit_width < max_bit_width) {
0100 return (access_bit_width);
0101 }
0102 return (max_bit_width);
0103 }
0104
0105
0106
0107
0108
0109
0110
0111
0112
0113
0114
0115
0116
0117
0118
0119
0120
0121 acpi_status
0122 acpi_hw_validate_register(struct acpi_generic_address *reg,
0123 u8 max_bit_width, u64 *address)
0124 {
0125 u8 bit_width;
0126 u8 access_width;
0127
0128
0129
0130 if (!reg) {
0131 return (AE_BAD_PARAMETER);
0132 }
0133
0134
0135
0136
0137
0138
0139 ACPI_MOVE_64_TO_64(address, ®->address);
0140 if (!(*address)) {
0141 return (AE_BAD_ADDRESS);
0142 }
0143
0144
0145
0146 if ((reg->space_id != ACPI_ADR_SPACE_SYSTEM_MEMORY) &&
0147 (reg->space_id != ACPI_ADR_SPACE_SYSTEM_IO)) {
0148 ACPI_ERROR((AE_INFO,
0149 "Unsupported address space: 0x%X", reg->space_id));
0150 return (AE_SUPPORT);
0151 }
0152
0153
0154
0155 if (reg->access_width > 4) {
0156 ACPI_ERROR((AE_INFO,
0157 "Unsupported register access width: 0x%X",
0158 reg->access_width));
0159 return (AE_SUPPORT);
0160 }
0161
0162
0163
0164 access_width =
0165 acpi_hw_get_access_bit_width(*address, reg, max_bit_width);
0166 bit_width =
0167 ACPI_ROUND_UP(reg->bit_offset + reg->bit_width, access_width);
0168 if (max_bit_width < bit_width) {
0169 ACPI_WARNING((AE_INFO,
0170 "Requested bit width 0x%X is smaller than register bit width 0x%X",
0171 max_bit_width, bit_width));
0172 return (AE_SUPPORT);
0173 }
0174
0175 return (AE_OK);
0176 }
0177
0178
0179
0180
0181
0182
0183
0184
0185
0186
0187
0188
0189
0190
0191
0192
0193
0194
0195 acpi_status acpi_hw_read(u64 *value, struct acpi_generic_address *reg)
0196 {
0197 u64 address;
0198 u8 access_width;
0199 u32 bit_width;
0200 u8 bit_offset;
0201 u64 value64;
0202 u32 value32;
0203 u8 index;
0204 acpi_status status;
0205
0206 ACPI_FUNCTION_NAME(hw_read);
0207
0208
0209
0210 status = acpi_hw_validate_register(reg, 64, &address);
0211 if (ACPI_FAILURE(status)) {
0212 return (status);
0213 }
0214
0215
0216
0217
0218
0219 *value = 0;
0220 access_width = acpi_hw_get_access_bit_width(address, reg, 64);
0221 bit_width = reg->bit_offset + reg->bit_width;
0222 bit_offset = reg->bit_offset;
0223
0224
0225
0226
0227
0228 index = 0;
0229 while (bit_width) {
0230 if (bit_offset >= access_width) {
0231 value64 = 0;
0232 bit_offset -= access_width;
0233 } else {
0234 if (reg->space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY) {
0235 status =
0236 acpi_os_read_memory((acpi_physical_address)
0237 address +
0238 index *
0239 ACPI_DIV_8
0240 (access_width),
0241 &value64, access_width);
0242 } else {
0243
0244 status = acpi_hw_read_port((acpi_io_address)
0245 address +
0246 index *
0247 ACPI_DIV_8
0248 (access_width),
0249 &value32,
0250 access_width);
0251 value64 = (u64)value32;
0252 }
0253 }
0254
0255
0256
0257
0258
0259 ACPI_SET_BITS(value, index * access_width,
0260 ACPI_MASK_BITS_ABOVE_64(access_width), value64);
0261
0262 bit_width -=
0263 bit_width > access_width ? access_width : bit_width;
0264 index++;
0265 }
0266
0267 ACPI_DEBUG_PRINT((ACPI_DB_IO,
0268 "Read: %8.8X%8.8X width %2d from %8.8X%8.8X (%s)\n",
0269 ACPI_FORMAT_UINT64(*value), access_width,
0270 ACPI_FORMAT_UINT64(address),
0271 acpi_ut_get_region_name(reg->space_id)));
0272
0273 return (status);
0274 }
0275
0276
0277
0278
0279
0280
0281
0282
0283
0284
0285
0286
0287
0288
0289
0290 acpi_status acpi_hw_write(u64 value, struct acpi_generic_address *reg)
0291 {
0292 u64 address;
0293 u8 access_width;
0294 u32 bit_width;
0295 u8 bit_offset;
0296 u64 value64;
0297 u8 index;
0298 acpi_status status;
0299
0300 ACPI_FUNCTION_NAME(hw_write);
0301
0302
0303
0304 status = acpi_hw_validate_register(reg, 64, &address);
0305 if (ACPI_FAILURE(status)) {
0306 return (status);
0307 }
0308
0309
0310
0311 access_width = acpi_hw_get_access_bit_width(address, reg, 64);
0312 bit_width = reg->bit_offset + reg->bit_width;
0313 bit_offset = reg->bit_offset;
0314
0315
0316
0317
0318
0319 index = 0;
0320 while (bit_width) {
0321
0322
0323
0324
0325 value64 = ACPI_GET_BITS(&value, index * access_width,
0326 ACPI_MASK_BITS_ABOVE_64(access_width));
0327
0328 if (bit_offset >= access_width) {
0329 bit_offset -= access_width;
0330 } else {
0331 if (reg->space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY) {
0332 status =
0333 acpi_os_write_memory((acpi_physical_address)
0334 address +
0335 index *
0336 ACPI_DIV_8
0337 (access_width),
0338 value64, access_width);
0339 } else {
0340
0341 status = acpi_hw_write_port((acpi_io_address)
0342 address +
0343 index *
0344 ACPI_DIV_8
0345 (access_width),
0346 (u32)value64,
0347 access_width);
0348 }
0349 }
0350
0351
0352
0353
0354
0355 bit_width -=
0356 bit_width > access_width ? access_width : bit_width;
0357 index++;
0358 }
0359
0360 ACPI_DEBUG_PRINT((ACPI_DB_IO,
0361 "Wrote: %8.8X%8.8X width %2d to %8.8X%8.8X (%s)\n",
0362 ACPI_FORMAT_UINT64(value), access_width,
0363 ACPI_FORMAT_UINT64(address),
0364 acpi_ut_get_region_name(reg->space_id)));
0365
0366 return (status);
0367 }
0368
0369 #if (!ACPI_REDUCED_HARDWARE)
0370
0371
0372
0373
0374
0375
0376
0377
0378
0379
0380
0381
0382 acpi_status acpi_hw_clear_acpi_status(void)
0383 {
0384 acpi_status status;
0385 acpi_cpu_flags lock_flags = 0;
0386
0387 ACPI_FUNCTION_TRACE(hw_clear_acpi_status);
0388
0389 ACPI_DEBUG_PRINT((ACPI_DB_IO, "About to write %04X to %8.8X%8.8X\n",
0390 ACPI_BITMASK_ALL_FIXED_STATUS,
0391 ACPI_FORMAT_UINT64(acpi_gbl_xpm1a_status.address)));
0392
0393 lock_flags = acpi_os_acquire_raw_lock(acpi_gbl_hardware_lock);
0394
0395
0396
0397 status = acpi_hw_register_write(ACPI_REGISTER_PM1_STATUS,
0398 ACPI_BITMASK_ALL_FIXED_STATUS);
0399
0400 acpi_os_release_raw_lock(acpi_gbl_hardware_lock, lock_flags);
0401
0402 if (ACPI_FAILURE(status)) {
0403 goto exit;
0404 }
0405
0406
0407
0408 status = acpi_ev_walk_gpe_list(acpi_hw_clear_gpe_block, NULL);
0409
0410 exit:
0411 return_ACPI_STATUS(status);
0412 }
0413
0414
0415
0416
0417
0418
0419
0420
0421
0422
0423
0424
0425
0426 struct acpi_bit_register_info *acpi_hw_get_bit_register_info(u32 register_id)
0427 {
0428 ACPI_FUNCTION_ENTRY();
0429
0430 if (register_id > ACPI_BITREG_MAX) {
0431 ACPI_ERROR((AE_INFO, "Invalid BitRegister ID: 0x%X",
0432 register_id));
0433 return (NULL);
0434 }
0435
0436 return (&acpi_gbl_bit_register_info[register_id]);
0437 }
0438
0439
0440
0441
0442
0443
0444
0445
0446
0447
0448
0449
0450
0451
0452
0453
0454
0455
0456 acpi_status acpi_hw_write_pm1_control(u32 pm1a_control, u32 pm1b_control)
0457 {
0458 acpi_status status;
0459
0460 ACPI_FUNCTION_TRACE(hw_write_pm1_control);
0461
0462 status =
0463 acpi_hw_write(pm1a_control, &acpi_gbl_FADT.xpm1a_control_block);
0464 if (ACPI_FAILURE(status)) {
0465 return_ACPI_STATUS(status);
0466 }
0467
0468 if (acpi_gbl_FADT.xpm1b_control_block.address) {
0469 status =
0470 acpi_hw_write(pm1b_control,
0471 &acpi_gbl_FADT.xpm1b_control_block);
0472 }
0473 return_ACPI_STATUS(status);
0474 }
0475
0476
0477
0478
0479
0480
0481
0482
0483
0484
0485
0486
0487
0488 acpi_status acpi_hw_register_read(u32 register_id, u32 *return_value)
0489 {
0490 u32 value = 0;
0491 u64 value64;
0492 acpi_status status;
0493
0494 ACPI_FUNCTION_TRACE(hw_register_read);
0495
0496 switch (register_id) {
0497 case ACPI_REGISTER_PM1_STATUS:
0498
0499 status = acpi_hw_read_multiple(&value,
0500 &acpi_gbl_xpm1a_status,
0501 &acpi_gbl_xpm1b_status);
0502 break;
0503
0504 case ACPI_REGISTER_PM1_ENABLE:
0505
0506 status = acpi_hw_read_multiple(&value,
0507 &acpi_gbl_xpm1a_enable,
0508 &acpi_gbl_xpm1b_enable);
0509 break;
0510
0511 case ACPI_REGISTER_PM1_CONTROL:
0512
0513 status = acpi_hw_read_multiple(&value,
0514 &acpi_gbl_FADT.
0515 xpm1a_control_block,
0516 &acpi_gbl_FADT.
0517 xpm1b_control_block);
0518
0519
0520
0521
0522
0523
0524 value &= ~ACPI_PM1_CONTROL_WRITEONLY_BITS;
0525 break;
0526
0527 case ACPI_REGISTER_PM2_CONTROL:
0528
0529 status =
0530 acpi_hw_read(&value64, &acpi_gbl_FADT.xpm2_control_block);
0531 if (ACPI_SUCCESS(status)) {
0532 value = (u32)value64;
0533 }
0534 break;
0535
0536 case ACPI_REGISTER_PM_TIMER:
0537
0538 status = acpi_hw_read(&value64, &acpi_gbl_FADT.xpm_timer_block);
0539 if (ACPI_SUCCESS(status)) {
0540 value = (u32)value64;
0541 }
0542
0543 break;
0544
0545 case ACPI_REGISTER_SMI_COMMAND_BLOCK:
0546
0547 status =
0548 acpi_hw_read_port(acpi_gbl_FADT.smi_command, &value, 8);
0549 break;
0550
0551 default:
0552
0553 ACPI_ERROR((AE_INFO, "Unknown Register ID: 0x%X", register_id));
0554 status = AE_BAD_PARAMETER;
0555 break;
0556 }
0557
0558 if (ACPI_SUCCESS(status)) {
0559 *return_value = (u32)value;
0560 }
0561
0562 return_ACPI_STATUS(status);
0563 }
0564
0565
0566
0567
0568
0569
0570
0571
0572
0573
0574
0575
0576
0577
0578
0579
0580
0581
0582
0583
0584
0585
0586
0587
0588
0589
0590
0591 acpi_status acpi_hw_register_write(u32 register_id, u32 value)
0592 {
0593 acpi_status status;
0594 u32 read_value;
0595 u64 read_value64;
0596
0597 ACPI_FUNCTION_TRACE(hw_register_write);
0598
0599 switch (register_id) {
0600 case ACPI_REGISTER_PM1_STATUS:
0601
0602
0603
0604
0605
0606
0607
0608
0609
0610
0611 value &= ~ACPI_PM1_STATUS_PRESERVED_BITS;
0612
0613 status = acpi_hw_write_multiple(value,
0614 &acpi_gbl_xpm1a_status,
0615 &acpi_gbl_xpm1b_status);
0616 break;
0617
0618 case ACPI_REGISTER_PM1_ENABLE:
0619
0620 status = acpi_hw_write_multiple(value,
0621 &acpi_gbl_xpm1a_enable,
0622 &acpi_gbl_xpm1b_enable);
0623 break;
0624
0625 case ACPI_REGISTER_PM1_CONTROL:
0626
0627
0628
0629
0630 status = acpi_hw_read_multiple(&read_value,
0631 &acpi_gbl_FADT.
0632 xpm1a_control_block,
0633 &acpi_gbl_FADT.
0634 xpm1b_control_block);
0635 if (ACPI_FAILURE(status)) {
0636 goto exit;
0637 }
0638
0639
0640
0641 ACPI_INSERT_BITS(value, ACPI_PM1_CONTROL_PRESERVED_BITS,
0642 read_value);
0643
0644
0645
0646 status = acpi_hw_write_multiple(value,
0647 &acpi_gbl_FADT.
0648 xpm1a_control_block,
0649 &acpi_gbl_FADT.
0650 xpm1b_control_block);
0651 break;
0652
0653 case ACPI_REGISTER_PM2_CONTROL:
0654
0655
0656
0657
0658 status =
0659 acpi_hw_read(&read_value64,
0660 &acpi_gbl_FADT.xpm2_control_block);
0661 if (ACPI_FAILURE(status)) {
0662 goto exit;
0663 }
0664 read_value = (u32)read_value64;
0665
0666
0667
0668 ACPI_INSERT_BITS(value, ACPI_PM2_CONTROL_PRESERVED_BITS,
0669 read_value);
0670
0671 status =
0672 acpi_hw_write(value, &acpi_gbl_FADT.xpm2_control_block);
0673 break;
0674
0675 case ACPI_REGISTER_PM_TIMER:
0676
0677 status = acpi_hw_write(value, &acpi_gbl_FADT.xpm_timer_block);
0678 break;
0679
0680 case ACPI_REGISTER_SMI_COMMAND_BLOCK:
0681
0682
0683
0684 status =
0685 acpi_hw_write_port(acpi_gbl_FADT.smi_command, value, 8);
0686 break;
0687
0688 default:
0689
0690 ACPI_ERROR((AE_INFO, "Unknown Register ID: 0x%X", register_id));
0691 status = AE_BAD_PARAMETER;
0692 break;
0693 }
0694
0695 exit:
0696 return_ACPI_STATUS(status);
0697 }
0698
0699
0700
0701
0702
0703
0704
0705
0706
0707
0708
0709
0710
0711
0712
0713 static acpi_status
0714 acpi_hw_read_multiple(u32 *value,
0715 struct acpi_generic_address *register_a,
0716 struct acpi_generic_address *register_b)
0717 {
0718 u32 value_a = 0;
0719 u32 value_b = 0;
0720 u64 value64;
0721 acpi_status status;
0722
0723
0724
0725 status = acpi_hw_read(&value64, register_a);
0726 if (ACPI_FAILURE(status)) {
0727 return (status);
0728 }
0729 value_a = (u32)value64;
0730
0731
0732
0733 if (register_b->address) {
0734 status = acpi_hw_read(&value64, register_b);
0735 if (ACPI_FAILURE(status)) {
0736 return (status);
0737 }
0738 value_b = (u32)value64;
0739 }
0740
0741
0742
0743
0744
0745
0746
0747
0748
0749
0750
0751 *value = (value_a | value_b);
0752 return (AE_OK);
0753 }
0754
0755
0756
0757
0758
0759
0760
0761
0762
0763
0764
0765
0766
0767
0768
0769 static acpi_status
0770 acpi_hw_write_multiple(u32 value,
0771 struct acpi_generic_address *register_a,
0772 struct acpi_generic_address *register_b)
0773 {
0774 acpi_status status;
0775
0776
0777
0778 status = acpi_hw_write(value, register_a);
0779 if (ACPI_FAILURE(status)) {
0780 return (status);
0781 }
0782
0783
0784
0785
0786
0787
0788
0789
0790
0791
0792
0793
0794
0795 if (register_b->address) {
0796 status = acpi_hw_write(value, register_b);
0797 }
0798
0799 return (status);
0800 }
0801
0802 #endif