void southbridge_smm_clear_state(void) { u32 smi_en; #if CONFIG_ELOG /* Log events from chipset before clearing */ pch_log_state(); #endif printk(BIOS_DEBUG, "Initializing Southbridge SMI..."); printk(BIOS_SPEW, " ... pmbase = 0x%04x\n", get_pmbase()); smi_en = inl(get_pmbase() + SMI_EN); if (smi_en & APMC_EN) { printk(BIOS_INFO, "SMI# handler already enabled?\n"); return; } printk(BIOS_DEBUG, "\n"); /* Dump and clear status registers */ clear_smi_status(); clear_pm1_status(); clear_tco_status(); clear_gpe_status(); }
static void pch_log_gpio_gpe(u32 gpe0_sts_reg, u32 gpe0_en_reg, int start) { /* GPE Bank 1 is GPIO 0-31 */ u32 gpe0_en = inl(get_pmbase() + gpe0_en_reg); u32 gpe0_sts = inl(get_pmbase() + gpe0_sts_reg) & gpe0_en; int i; for (i = 0; i <= 31; i++) { if (gpe0_sts & (1 << i)) elog_add_event_wake(ELOG_WAKE_SOURCE_GPIO, i + start); } }
static uint16_t reset_pm1_status(void) { uint16_t pmbase = get_pmbase(); uint16_t pm1_sts = inw(pmbase + PM1_STS); outw(pm1_sts, pmbase + PM1_STS); return pm1_sts; }
static uint8_t mainboard_smi_ec(void) { uint8_t cmd = google_chromeec_get_event(); uint16_t pmbase = get_pmbase(); uint32_t pm1_cnt; #if IS_ENABLED(CONFIG_ELOG_GSMI) /* Log this event */ if (cmd) elog_add_event_byte(ELOG_TYPE_EC_EVENT, cmd); #endif switch (cmd) { case EC_HOST_EVENT_LID_CLOSED: printk(BIOS_DEBUG, "LID CLOSED, SHUTDOWN\n"); /* Go to S5 */ pm1_cnt = inl(pmbase + PM1_CNT); pm1_cnt |= SLP_EN | (SLP_TYP_S5 << SLP_TYP_SHIFT); outl(pm1_cnt, pmbase + PM1_CNT); break; } return cmd; }
static uint32_t reset_alt_status(void) { uint16_t pmbase = get_pmbase(); uint32_t alt_gpio_smi = inl(pmbase + ALT_GPIO_SMI); outl(alt_gpio_smi, pmbase + ALT_GPIO_SMI); return alt_gpio_smi; }
void generate_cpu_entries(void) { int len_pr, core; int pcontrol_blk = get_pmbase(), plen = 6; const struct pattrs *pattrs = pattrs_get(); for (core=0; core<pattrs->num_cpus; core++) { if (core > 0) { pcontrol_blk = 0; plen = 0; } /* Generate processor \_PR.CPUx */ len_pr = acpigen_write_processor( core, pcontrol_blk, plen); /* Generate P-state tables */ len_pr += generate_P_state_entries( core, pattrs->num_cpus); /* Generate C-state tables */ len_pr += acpigen_write_CST_package( cstate_map, ARRAY_SIZE(cstate_map)); /* Generate T-state tables */ len_pr += generate_T_state_entries( core, pattrs->num_cpus); len_pr--; acpigen_patch_len(len_pr); } }
void disable_gpe(uint32_t mask) { uint16_t pmbase = get_pmbase(); uint32_t gpe0_en = inl(pmbase + GPE0_EN); gpe0_en &= ~mask; outl(gpe0_en, pmbase + GPE0_EN); }
static uint32_t reset_gpe_status(void) { uint16_t pmbase = get_pmbase(); uint32_t gpe_sts = inl(pmbase + GPE0_STS); outl(gpe_sts, pmbase + GPE0_STS); return gpe_sts; }
void disable_pm1_control(uint32_t mask) { uint16_t pmbase = get_pmbase(); uint32_t pm1_cnt = inl(pmbase + PM1_CNT); pm1_cnt &= ~mask; outl(pm1_cnt, pmbase + PM1_CNT); }
void disable_smi(uint32_t mask) { uint16_t pmbase = get_pmbase(); uint32_t smi_en = inl(pmbase + SMI_EN); smi_en &= ~mask; outl(smi_en, pmbase + SMI_EN); }
static uint32_t reset_smi_status(void) { uint16_t pmbase = get_pmbase(); uint32_t smi_sts = inl(pmbase + SMI_STS); outl(smi_sts, pmbase + SMI_STS); return smi_sts; }
static void pch_log_standard_gpe(u32 gpe0_sts_reg, u32 gpe0_en_reg) { u32 gpe0_en = inl(get_pmbase() + gpe0_en_reg); u32 gpe0_sts = inl(get_pmbase() + gpe0_sts_reg) & gpe0_en; /* PME (TODO: determine wake device) */ if (gpe0_sts & (1 << 11)) elog_add_event_wake(ELOG_WAKE_SOURCE_PME, 0); /* Internal PME (TODO: determine wake device) */ if (gpe0_sts & (1 << 13)) elog_add_event_wake(ELOG_WAKE_SOURCE_PME_INTERNAL, 0); /* SMBUS Wake */ if (gpe0_sts & (1 << 7)) elog_add_event_wake(ELOG_WAKE_SOURCE_SMBUS, 0); }
static uint32_t reset_tco_status(void) { uint16_t pmbase = get_pmbase(); uint32_t tco_sts = inl(pmbase + TCO_STS); uint32_t tco_en = inl(pmbase + TCO1_CNT); outl(tco_sts, pmbase + TCO_STS); return tco_sts & tco_en; }
void southbridge_smm_init(void) { u32 smi_en; #if CONFIG_ELOG /* Log events from chipset before clearing */ pch_log_state(); #endif printk(BIOS_DEBUG, "Initializing Southbridge SMI..."); printk(BIOS_SPEW, " ... pmbase = 0x%04x\n", get_pmbase()); smi_en = inl(get_pmbase() + SMI_EN); if (smi_en & APMC_EN) { printk(BIOS_INFO, "SMI# handler already enabled?\n"); return; } printk(BIOS_DEBUG, "\n"); /* Dump and clear status registers */ clear_smi_status(); clear_pm1_status(); clear_tco_status(); clear_gpe_status(); /* Configure events */ enable_pm1(PWRBTN_EN | GBL_EN); disable_gpe(PME_B0_EN); /* Enable SMI generation: * - on TCO events * - on APMC writes (io 0xb2) * - on writes to SLP_EN (sleep states) * - on writes to GBL_RLS (bios commands) * No SMIs: * - on microcontroller writes (io 0x62/0x66) */ enable_smi(TCO_EN | APMC_EN | SLP_SMI_EN | GBL_SMI_EN | EOS); }
static u8 mainboard_smi_ec(void) { u8 cmd = google_chromeec_get_event(); u32 pm1_cnt; #if CONFIG_ELOG_GSMI /* Log this event */ if (cmd) elog_add_event_byte(ELOG_TYPE_EC_EVENT, cmd); #endif switch (cmd) { case EC_HOST_EVENT_LID_CLOSED: printk(BIOS_DEBUG, "LID CLOSED, SHUTDOWN\n"); /* Go to S5 */ pm1_cnt = inl(get_pmbase() + PM1_CNT); pm1_cnt |= (0xf << 10); outl(pm1_cnt, get_pmbase() + PM1_CNT); break; } return cmd; }
void southcluster_smm_clear_state(void) { uint32_t smi_en; /* Log events from chipset before clearing */ southcluster_log_state(); printk(BIOS_DEBUG, "Initializing Southbridge SMI..."); printk(BIOS_SPEW, " pmbase = 0x%04x\n", get_pmbase()); smi_en = inl(get_pmbase() + SMI_EN); if (smi_en & APMC_EN) { printk(BIOS_INFO, "SMI# handler already enabled?\n"); return; } /* Dump and clear status registers */ clear_smi_status(); clear_pm1_status(); clear_tco_status(); clear_gpe_status(); clear_alt_status(); clear_pmc_status(); }
static void pch_log_gpe(void) { int i; u16 pmbase = get_pmbase(); u32 gpe0_sts, gpe0_en; int gpe0_high_gpios[] = { [0] = 27, [24] = 17, [25] = 19, [26] = 21, [27] = 22, [28] = 43, [29] = 56, [30] = 57, [31] = 60 }; pch_log_standard_gpe(GPE0_EN, GPE0_STS); /* GPIO 0-15 */ gpe0_en = inw(pmbase + GPE0_EN + 2); gpe0_sts = inw(pmbase + GPE0_STS + 2) & gpe0_en; for (i = 0; i <= 15; i++) { if (gpe0_sts & (1 << i)) elog_add_event_wake(ELOG_WAKE_SOURCE_GPIO, i); } /* * Now check and log upper status bits */ gpe0_en = inl(pmbase + GPE0_EN_2); gpe0_sts = inl(pmbase + GPE0_STS_2) & gpe0_en; for (i = 0; i <= 31; i++) { if (!gpe0_high_gpios[i]) continue; if (gpe0_sts & (1 << i)) elog_add_event_wake(ELOG_WAKE_SOURCE_GPIO, gpe0_high_gpios[i]); } }
void acpi_create_fadt(acpi_fadt_t * fadt, acpi_facs_t * facs, void *dsdt) { acpi_header_t *header = &(fadt->header); u16 pmbase = get_pmbase(); memset((void *) fadt, 0, sizeof(acpi_fadt_t)); memcpy(header->signature, "FACP", 4); header->length = sizeof(acpi_fadt_t); header->revision = 3; memcpy(header->oem_id, OEM_ID, 6); memcpy(header->oem_table_id, ACPI_TABLE_CREATOR, 8); memcpy(header->asl_compiler_id, ASLC, 4); header->asl_compiler_revision = 1; fadt->firmware_ctrl = (unsigned long) facs; fadt->dsdt = (unsigned long) dsdt; fadt->model = 1; fadt->preferred_pm_profile = PM_MOBILE; fadt->sci_int = 0x9; fadt->smi_cmd = APM_CNT; fadt->acpi_enable = APM_CNT_ACPI_ENABLE; fadt->acpi_disable = APM_CNT_ACPI_DISABLE; fadt->s4bios_req = 0x0; fadt->pstate_cnt = 0; fadt->pm1a_evt_blk = pmbase; fadt->pm1b_evt_blk = 0x0; fadt->pm1a_cnt_blk = pmbase + 0x4; fadt->pm1b_cnt_blk = 0x0; fadt->pm2_cnt_blk = pmbase + 0x50; fadt->pm_tmr_blk = pmbase + 0x8; fadt->gpe0_blk = pmbase + 0x80; fadt->gpe1_blk = 0; fadt->pm1_evt_len = 4; fadt->pm1_cnt_len = 2; fadt->pm2_cnt_len = 1; fadt->pm_tmr_len = 4; fadt->gpe0_blk_len = 32; fadt->gpe1_blk_len = 0; fadt->gpe1_base = 0; fadt->cst_cnt = 0; fadt->p_lvl2_lat = 1; fadt->p_lvl3_lat = 87; fadt->flush_size = 1024; fadt->flush_stride = 16; fadt->duty_offset = 1; fadt->duty_width = 0; fadt->day_alrm = 0xd; fadt->mon_alrm = 0x00; fadt->century = 0x00; fadt->iapc_boot_arch = ACPI_FADT_LEGACY_DEVICES | ACPI_FADT_8042; fadt->flags = ACPI_FADT_WBINVD | ACPI_FADT_C1_SUPPORTED | ACPI_FADT_C2_MP_SUPPORTED | ACPI_FADT_SLEEP_BUTTON | ACPI_FADT_RESET_REGISTER | ACPI_FADT_SEALED_CASE | ACPI_FADT_S4_RTC_WAKE | ACPI_FADT_PLATFORM_CLOCK; fadt->reset_reg.space_id = 1; fadt->reset_reg.bit_width = 8; fadt->reset_reg.bit_offset = 0; fadt->reset_reg.resv = 0; fadt->reset_reg.addrl = 0xcf9; fadt->reset_reg.addrh = 0; fadt->reset_value = 6; fadt->x_firmware_ctl_l = (unsigned long)facs; fadt->x_firmware_ctl_h = 0; fadt->x_dsdt_l = (unsigned long)dsdt; fadt->x_dsdt_h = 0; fadt->x_pm1a_evt_blk.space_id = 1; fadt->x_pm1a_evt_blk.bit_width = 32; fadt->x_pm1a_evt_blk.bit_offset = 0; fadt->x_pm1a_evt_blk.resv = 0; fadt->x_pm1a_evt_blk.addrl = pmbase; fadt->x_pm1a_evt_blk.addrh = 0x0; fadt->x_pm1b_evt_blk.space_id = 1; fadt->x_pm1b_evt_blk.bit_width = 0; fadt->x_pm1b_evt_blk.bit_offset = 0; fadt->x_pm1b_evt_blk.resv = 0; fadt->x_pm1b_evt_blk.addrl = 0x0; fadt->x_pm1b_evt_blk.addrh = 0x0; fadt->x_pm1a_cnt_blk.space_id = 1; fadt->x_pm1a_cnt_blk.bit_width = 16; fadt->x_pm1a_cnt_blk.bit_offset = 0; fadt->x_pm1a_cnt_blk.resv = 0; fadt->x_pm1a_cnt_blk.addrl = pmbase + 0x4; fadt->x_pm1a_cnt_blk.addrh = 0x0; fadt->x_pm1b_cnt_blk.space_id = 1; fadt->x_pm1b_cnt_blk.bit_width = 0; fadt->x_pm1b_cnt_blk.bit_offset = 0; fadt->x_pm1b_cnt_blk.resv = 0; fadt->x_pm1b_cnt_blk.addrl = 0x0; fadt->x_pm1b_cnt_blk.addrh = 0x0; fadt->x_pm2_cnt_blk.space_id = 1; fadt->x_pm2_cnt_blk.bit_width = 8; fadt->x_pm2_cnt_blk.bit_offset = 0; fadt->x_pm2_cnt_blk.resv = 0; fadt->x_pm2_cnt_blk.addrl = pmbase + 0x50; fadt->x_pm2_cnt_blk.addrh = 0x0; fadt->x_pm_tmr_blk.space_id = 1; fadt->x_pm_tmr_blk.bit_width = 32; fadt->x_pm_tmr_blk.bit_offset = 0; fadt->x_pm_tmr_blk.resv = 0; fadt->x_pm_tmr_blk.addrl = pmbase + 0x8; fadt->x_pm_tmr_blk.addrh = 0x0; fadt->x_gpe0_blk.space_id = 0; fadt->x_gpe0_blk.bit_width = 0; fadt->x_gpe0_blk.bit_offset = 0; fadt->x_gpe0_blk.resv = 0; fadt->x_gpe0_blk.addrl = 0; fadt->x_gpe0_blk.addrh = 0x0; fadt->x_gpe1_blk.space_id = 1; fadt->x_gpe1_blk.bit_width = 0; fadt->x_gpe1_blk.bit_offset = 0; fadt->x_gpe1_blk.resv = 0; fadt->x_gpe1_blk.addrl = 0x0; fadt->x_gpe1_blk.addrh = 0x0; header->checksum = acpi_checksum((void *) fadt, header->length); }
void enable_pm1(uint16_t events) { outw(events, get_pmbase() + PM1_EN); }
void pch_log_state(void) { u16 pm1_sts, gen_pmcon_3, tco2_sts; u8 gen_pmcon_2; struct device *lpc = dev_find_slot(0, PCI_DEVFN(0x1f, 0)); if (!lpc) return; pm1_sts = inw(get_pmbase() + PM1_STS); tco2_sts = inw(get_pmbase() + TCO2_STS); gen_pmcon_2 = pci_read_config8(lpc, GEN_PMCON_2); gen_pmcon_3 = pci_read_config16(lpc, GEN_PMCON_3); /* PWR_FLR Power Failure */ if (gen_pmcon_2 & (1 << 0)) elog_add_event(ELOG_TYPE_POWER_FAIL); /* SUS Well Power Failure */ if (gen_pmcon_3 & (1 << 14)) elog_add_event(ELOG_TYPE_SUS_POWER_FAIL); /* SYS_PWROK Failure */ if (gen_pmcon_2 & (1 << 1)) elog_add_event(ELOG_TYPE_SYS_PWROK_FAIL); /* PWROK Failure */ if (gen_pmcon_2 & (1 << 0)) elog_add_event(ELOG_TYPE_PWROK_FAIL); /* Second TCO Timeout */ if (tco2_sts & (1 << 1)) elog_add_event(ELOG_TYPE_TCO_RESET); /* Power Button Override */ if (pm1_sts & (1 << 11)) elog_add_event(ELOG_TYPE_POWER_BUTTON_OVERRIDE); /* System Reset Status (reset button pushed) */ if (gen_pmcon_2 & (1 << 4)) elog_add_event(ELOG_TYPE_RESET_BUTTON); /* General Reset Status */ if (gen_pmcon_3 & (1 << 9)) elog_add_event(ELOG_TYPE_SYSTEM_RESET); /* ACPI Wake */ if (pm1_sts & (1 << 15)) elog_add_event_byte(ELOG_TYPE_ACPI_WAKE, acpi_is_wakeup_s3() ? 3 : 5); /* * Wake sources */ /* Power Button */ if (pm1_sts & (1 << 8)) elog_add_event_wake(ELOG_WAKE_SOURCE_PWRBTN, 0); /* RTC */ if (pm1_sts & (1 << 10)) elog_add_event_wake(ELOG_WAKE_SOURCE_RTC, 0); /* PCI Express (TODO: determine wake device) */ if (pm1_sts & (1 << 14)) elog_add_event_wake(ELOG_WAKE_SOURCE_PCIE, 0); /* GPE */ if (pch_is_lp()) pch_lp_log_gpe(); else pch_log_gpe(); }