static acpi_status acpi_hw_write_multiple(u32 value, struct acpi_generic_address *register_a, struct acpi_generic_address *register_b) { acpi_status status; /* The first register is always required */ status = acpi_hw_write(value, register_a); if (ACPI_FAILURE(status)) { return (status); } /* * Second register is optional * * No bit shifting or clearing is necessary, because of how the PM1 * registers are defined in the ACPI specification: * * "Although the bits can be split between the two register blocks (each * register block has a unique pointer within the FADT), the bit positions * are maintained. The register block with unimplemented bits (that is, * those implemented in the other register block) always returns zeros, * and writes have no side effects" */ if (register_b->address) { status = acpi_hw_write(value, register_b); } return (status); }
static acpi_status acpi_hw_enable_wakeup_gpe_block(struct acpi_gpe_xrupt_info *gpe_xrupt_info, struct acpi_gpe_block_info *gpe_block, void *context) { u32 i; acpi_status status; /* Examine each GPE Register within the block */ for (i = 0; i < gpe_block->register_count; i++) { if (!gpe_block->register_info[i].enable_for_wake) { continue; } /* Enable all "wake" GPEs in this register */ status = acpi_hw_write(gpe_block->register_info[i].enable_for_wake, &gpe_block->register_info[i].enable_address); if (ACPI_FAILURE(status)) { return (status); } } return (AE_OK); }
acpi_status acpi_hw_enable_runtime_gpe_block(struct acpi_gpe_xrupt_info *gpe_xrupt_info, struct acpi_gpe_block_info * gpe_block, void *context) { u32 i; acpi_status status; /* NOTE: assumes that all GPEs are currently disabled */ /* Examine each GPE Register within the block */ for (i = 0; i < gpe_block->register_count; i++) { if (!gpe_block->register_info[i].enable_for_run) { continue; } /* Enable all "runtime" GPEs in this register */ status = acpi_hw_write(gpe_block->register_info[i].enable_for_run, &gpe_block->register_info[i].enable_address); if (ACPI_FAILURE(status)) { return (status); } } return (AE_OK); }
acpi_status acpi_hw_clear_gpe(struct acpi_gpe_event_info * gpe_event_info) { struct acpi_gpe_register_info *gpe_register_info; acpi_status status; u32 register_bit; ACPI_FUNCTION_ENTRY(); /* Get the info block for the entire GPE register */ gpe_register_info = gpe_event_info->register_info; if (!gpe_register_info) { return (AE_NOT_EXIST); } /* * Write a one to the appropriate bit in the status register to * clear this GPE. */ register_bit = acpi_hw_get_gpe_register_bit(gpe_event_info); status = acpi_hw_write(register_bit, &gpe_register_info->status_address); return (status); }
acpi_status acpi_hw_low_disable_gpe(struct acpi_gpe_event_info *gpe_event_info) { struct acpi_gpe_register_info *gpe_register_info; acpi_status status; u32 enable_mask; /* Get the info block for the entire GPE register */ gpe_register_info = gpe_event_info->register_info; if (!gpe_register_info) { return (AE_NOT_EXIST); } /* Get current value of the enable register that contains this GPE */ status = acpi_hw_read(&enable_mask, &gpe_register_info->enable_address); if (ACPI_FAILURE(status)) { return (status); } /* Clear just the bit that corresponds to this GPE */ ACPI_CLEAR_BIT(enable_mask, ((u32)1 << (gpe_event_info->gpe_number - gpe_register_info->base_gpe_number))); /* Write the updated enable mask */ status = acpi_hw_write(enable_mask, &gpe_register_info->enable_address); return (status); }
acpi_status acpi_hw_low_set_gpe(struct acpi_gpe_event_info *gpe_event_info, u32 action) { struct acpi_gpe_register_info *gpe_register_info; acpi_status status; u32 enable_mask; u32 register_bit; ACPI_FUNCTION_ENTRY(); /* Get the info block for the entire GPE register */ gpe_register_info = gpe_event_info->register_info; if (!gpe_register_info) { return (AE_NOT_EXIST); } /* Get current value of the enable register that contains this GPE */ status = acpi_hw_read(&enable_mask, &gpe_register_info->enable_address); if (ACPI_FAILURE(status)) { return (status); } /* Set or clear just the bit that corresponds to this GPE */ register_bit = acpi_hw_get_gpe_register_bit(gpe_event_info); switch (action) { case ACPI_GPE_CONDITIONAL_ENABLE: /* Only enable if the enable_for_run bit is set */ if (!(register_bit & gpe_register_info->enable_for_run)) { return (AE_BAD_PARAMETER); } /*lint -fallthrough */ case ACPI_GPE_ENABLE: ACPI_SET_BIT(enable_mask, register_bit); break; case ACPI_GPE_DISABLE: ACPI_CLEAR_BIT(enable_mask, register_bit); break; default: ACPI_ERROR((AE_INFO, "Invalid GPE Action, %u", action)); return (AE_BAD_PARAMETER); } /* Write the updated enable mask */ status = acpi_hw_write(enable_mask, &gpe_register_info->enable_address); return (status); }
acpi_status acpi_hw_write_pm1_control(u32 pm1a_control, u32 pm1b_control) { acpi_status status; ACPI_FUNCTION_TRACE(hw_write_pm1_control); status = acpi_hw_write(pm1a_control, &acpi_gbl_FADT.xpm1a_control_block); if (ACPI_FAILURE(status)) { return_ACPI_STATUS(status); } if (acpi_gbl_FADT.xpm1b_control_block.address) { status = acpi_hw_write(pm1b_control, &acpi_gbl_FADT.xpm1b_control_block); } return_ACPI_STATUS(status); }
static acpi_status acpi_hw_gpe_enable_write(u8 enable_mask, struct acpi_gpe_register_info *gpe_register_info) { acpi_status status; gpe_register_info->enable_mask = enable_mask; status = acpi_hw_write(enable_mask, &gpe_register_info->enable_address); return (status); }
static acpi_status acpi_hw_write_multiple(u32 value, struct acpi_generic_address *register_a, struct acpi_generic_address *register_b) { acpi_status status; status = acpi_hw_write(value, register_a); if (ACPI_FAILURE(status)) { return (status); } if (register_b->address) { status = acpi_hw_write(value, register_b); } return (status); }
acpi_status acpi_hw_clear_gpe(struct acpi_gpe_event_info * gpe_event_info) { acpi_status status; u8 register_bit; ACPI_FUNCTION_ENTRY(); register_bit = (u8)(1 << (gpe_event_info->gpe_number - gpe_event_info->register_info->base_gpe_number)); /* * Write a one to the appropriate bit in the status register to * clear this GPE. */ status = acpi_hw_write(register_bit, &gpe_event_info->register_info->status_address); return (status); }
acpi_status acpi_hw_write_gpe_enable_reg(struct acpi_gpe_event_info * gpe_event_info) { struct acpi_gpe_register_info *gpe_register_info; acpi_status status; ACPI_FUNCTION_ENTRY(); /* Get the info block for the entire GPE register */ gpe_register_info = gpe_event_info->register_info; if (!gpe_register_info) { return (AE_NOT_EXIST); } /* Write the entire GPE (runtime) enable register */ status = acpi_hw_write(gpe_register_info->enable_for_run, &gpe_register_info->enable_address); return (status); }
acpi_status acpi_hw_clear_gpe_block(struct acpi_gpe_xrupt_info *gpe_xrupt_info, struct acpi_gpe_block_info *gpe_block, void *context) { u32 i; acpi_status status; /* Examine each GPE Register within the block */ for (i = 0; i < gpe_block->register_count; i++) { /* Clear status on all GPEs in this register */ status = acpi_hw_write(0xFF, &gpe_block->register_info[i].status_address); if (ACPI_FAILURE(status)) { return (status); } } return (AE_OK); }
acpi_status acpi_hw_register_write(u32 register_id, u32 value) { acpi_status status; u32 read_value; struct acpi_generic_address reg; ACPI_FUNCTION_TRACE(hw_register_write); switch (register_id) { case ACPI_REGISTER_PM1_STATUS: /* PM1 A/B: 16-bit access each */ /* * Handle the "ignored" bit in PM1 Status. According to the ACPI * specification, ignored bits are to be preserved when writing. * Normally, this would mean a read/modify/write sequence. However, * preserving a bit in the status register is different. Writing a * one clears the status, and writing a zero preserves the status. * Therefore, we must always write zero to the ignored bit. * * This behavior is clarified in the ACPI 4.0 specification. */ value &= ~ACPI_PM1_STATUS_PRESERVED_BITS; status = acpi_hw_write_multiple(value, &acpi_gbl_xpm1a_status, &acpi_gbl_xpm1b_status); break; case ACPI_REGISTER_PM1_ENABLE: /* PM1 A/B: 16-bit access each */ status = acpi_hw_write_multiple(value, &acpi_gbl_xpm1a_enable, &acpi_gbl_xpm1b_enable); break; case ACPI_REGISTER_PM1_CONTROL: /* PM1 A/B: 16-bit access each */ /* * Perform a read first to preserve certain bits (per ACPI spec) * Note: This includes SCI_EN, we never want to change this bit */ status = acpi_hw_read_multiple(&read_value, &acpi_gbl_FADT. xpm1a_control_block, &acpi_gbl_FADT. xpm1b_control_block); if (ACPI_FAILURE(status)) { goto exit; } /* Insert the bits to be preserved */ ACPI_INSERT_BITS(value, ACPI_PM1_CONTROL_PRESERVED_BITS, read_value); /* Now we can write the data */ status = acpi_hw_write_multiple(value, &acpi_gbl_FADT. xpm1a_control_block, &acpi_gbl_FADT. xpm1b_control_block); break; case ACPI_REGISTER_PM2_CONTROL: /* 8-bit access */ /* * For control registers, all reserved bits must be preserved, * as per the ACPI spec. */ status = acpi_hw_read(&read_value, &acpi_gbl_FADT.xpm2_control_block); if (ACPI_FAILURE(status)) { goto exit; } /* Insert the bits to be preserved */ ACPI_INSERT_BITS(value, ACPI_PM2_CONTROL_PRESERVED_BITS, read_value); status = acpi_hw_write(value, &acpi_gbl_FADT.xpm2_control_block); break; case ACPI_REGISTER_PM_TIMER: /* 32-bit access */ status = acpi_hw_write(value, &acpi_gbl_FADT.xpm_timer_block); break; case ACPI_REGISTER_SMI_COMMAND_BLOCK: /* 8-bit access */ /* SMI_CMD is currently always in IO space */ status = acpi_hw_write_port(acpi_gbl_FADT.smi_command, value, 8); break; case ACPI_REGISTER_GPE0_STATUS: reg = acpi_gbl_FADT.xgpe0_block; reg.bit_width = 32; reg.address = 0x420; status = acpi_hw_write(value, ®); break; case ACPI_REGISTER_GPE0_ENABLE: reg = acpi_gbl_FADT.xgpe0_block; reg.bit_width = 32; reg.address = 0x428; status = acpi_hw_write(value, ®); break; default: ACPI_ERROR((AE_INFO, "Unknown Register ID: 0x%X", register_id)); status = AE_BAD_PARAMETER; break; } exit: return_ACPI_STATUS(status); }
static acpi_status acpi_ev_create_gpe_info_blocks(struct acpi_gpe_block_info *gpe_block) { struct acpi_gpe_register_info *gpe_register_info = NULL; struct acpi_gpe_event_info *gpe_event_info = NULL; struct acpi_gpe_event_info *this_event; struct acpi_gpe_register_info *this_register; u32 i; u32 j; acpi_status status; ACPI_FUNCTION_TRACE(ev_create_gpe_info_blocks); /* Allocate the GPE register information block */ gpe_register_info = ACPI_ALLOCATE_ZEROED((acpi_size) gpe_block-> register_count * sizeof(struct acpi_gpe_register_info)); if (!gpe_register_info) { ACPI_ERROR((AE_INFO, "Could not allocate the GpeRegisterInfo table")); return_ACPI_STATUS(AE_NO_MEMORY); } /* * Allocate the GPE event_info block. There are eight distinct GPEs * per register. Initialization to zeros is sufficient. */ gpe_event_info = ACPI_ALLOCATE_ZEROED((acpi_size) gpe_block->gpe_count * sizeof(struct acpi_gpe_event_info)); if (!gpe_event_info) { ACPI_ERROR((AE_INFO, "Could not allocate the GpeEventInfo table")); status = AE_NO_MEMORY; goto error_exit; } /* Save the new Info arrays in the GPE block */ gpe_block->register_info = gpe_register_info; gpe_block->event_info = gpe_event_info; /* * Initialize the GPE Register and Event structures. A goal of these * tables is to hide the fact that there are two separate GPE register * sets in a given GPE hardware block, the status registers occupy the * first half, and the enable registers occupy the second half. */ this_register = gpe_register_info; this_event = gpe_event_info; for (i = 0; i < gpe_block->register_count; i++) { /* Init the register_info for this GPE register (8 GPEs) */ this_register->base_gpe_number = (u8) (gpe_block->block_base_number + (i * ACPI_GPE_REGISTER_WIDTH)); this_register->status_address.address = gpe_block->block_address.address + i; this_register->enable_address.address = gpe_block->block_address.address + i + gpe_block->register_count; this_register->status_address.space_id = gpe_block->block_address.space_id; this_register->enable_address.space_id = gpe_block->block_address.space_id; this_register->status_address.bit_width = ACPI_GPE_REGISTER_WIDTH; this_register->enable_address.bit_width = ACPI_GPE_REGISTER_WIDTH; this_register->status_address.bit_offset = 0; this_register->enable_address.bit_offset = 0; /* Init the event_info for each GPE within this register */ for (j = 0; j < ACPI_GPE_REGISTER_WIDTH; j++) { this_event->gpe_number = (u8) (this_register->base_gpe_number + j); this_event->register_info = this_register; this_event++; } /* Disable all GPEs within this register */ status = acpi_hw_write(0x00, &this_register->enable_address); if (ACPI_FAILURE(status)) { goto error_exit; } /* Clear any pending GPE events within this register */ status = acpi_hw_write(0xFF, &this_register->status_address); if (ACPI_FAILURE(status)) { goto error_exit; } this_register++; } return_ACPI_STATUS(AE_OK); error_exit: if (gpe_register_info) { ACPI_FREE(gpe_register_info); } if (gpe_event_info) { ACPI_FREE(gpe_event_info); } return_ACPI_STATUS(status); }
acpi_status acpi_hw_register_write(u32 register_id, u32 value) { acpi_status status; u32 read_value; ACPI_FUNCTION_TRACE(hw_register_write); switch (register_id) { case ACPI_REGISTER_PM1_STATUS: value &= ~ACPI_PM1_STATUS_PRESERVED_BITS; status = acpi_hw_write_multiple(value, &acpi_gbl_xpm1a_status, &acpi_gbl_xpm1b_status); break; case ACPI_REGISTER_PM1_ENABLE: status = acpi_hw_write_multiple(value, &acpi_gbl_xpm1a_enable, &acpi_gbl_xpm1b_enable); break; case ACPI_REGISTER_PM1_CONTROL: status = acpi_hw_read_multiple(&read_value, &acpi_gbl_FADT. xpm1a_control_block, &acpi_gbl_FADT. xpm1b_control_block); if (ACPI_FAILURE(status)) { goto exit; } ACPI_INSERT_BITS(value, ACPI_PM1_CONTROL_PRESERVED_BITS, read_value); status = acpi_hw_write_multiple(value, &acpi_gbl_FADT. xpm1a_control_block, &acpi_gbl_FADT. xpm1b_control_block); break; case ACPI_REGISTER_PM2_CONTROL: status = acpi_hw_read(&read_value, &acpi_gbl_FADT.xpm2_control_block); if (ACPI_FAILURE(status)) { goto exit; } ACPI_INSERT_BITS(value, ACPI_PM2_CONTROL_PRESERVED_BITS, read_value); status = acpi_hw_write(value, &acpi_gbl_FADT.xpm2_control_block); break; case ACPI_REGISTER_PM_TIMER: status = acpi_hw_write(value, &acpi_gbl_FADT.xpm_timer_block); break; case ACPI_REGISTER_SMI_COMMAND_BLOCK: status = acpi_hw_write_port(acpi_gbl_FADT.smi_command, value, 8); break; default: ACPI_ERROR((AE_INFO, "Unknown Register ID: %X", register_id)); status = AE_BAD_PARAMETER; break; } exit: return_ACPI_STATUS(status); }