summaryrefslogtreecommitdiff
path: root/chip/ish/aontaskfw
diff options
context:
space:
mode:
authorLeifu Zhao <leifu.zhao@intel.com>2020-04-24 18:59:12 +0800
committerCommit Bot <commit-bot@chromium.org>2020-05-15 19:20:48 +0000
commit45a7c5cf8ff59a917bd7dda6ccd3f14dbab2c4dd (patch)
treee6a355c05fc0ae6f6bf5a21ffcbb2ddd9d500d33 /chip/ish/aontaskfw
parentc828740d6050fc40cf1b881374679ebf0e4b5666 (diff)
downloadchrome-ec-45a7c5cf8ff59a917bd7dda6ccd3f14dbab2c4dd.tar.gz
ish: enable IPAPG for ish 5.4 on tgl rvp platform
Enable ip accessible power gating for ish 5.4 on tgl rvp platform. BUG=b:154891699 BRANCH=none TEST=ISH can successfully enter into IPAPG on tgl rvp. Change-Id: Iee30124a0928389f4c75dffff065fab7a5a2d970 Signed-off-by: Leifu Zhao <leifu.zhao@intel.com> Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/2164091 Reviewed-by: Leifu Zhao <leifu.zhao@intel.corp-partner.google.com> Reviewed-by: Jack Rosenthal <jrosenth@chromium.org> Tested-by: Leifu Zhao <leifu.zhao@intel.corp-partner.google.com> Commit-Queue: Jack Rosenthal <jrosenth@chromium.org> Auto-Submit: Leifu Zhao <leifu.zhao@intel.corp-partner.google.com>
Diffstat (limited to 'chip/ish/aontaskfw')
-rwxr-xr-xchip/ish/aontaskfw/ipapg.S130
-rw-r--r--chip/ish/aontaskfw/ish_aon_defs.h37
-rw-r--r--chip/ish/aontaskfw/ish_aon_share.h4
-rw-r--r--chip/ish/aontaskfw/ish_aontask.c167
4 files changed, 329 insertions, 9 deletions
diff --git a/chip/ish/aontaskfw/ipapg.S b/chip/ish/aontaskfw/ipapg.S
new file mode 100755
index 0000000000..f0d3f8c554
--- /dev/null
+++ b/chip/ish/aontaskfw/ipapg.S
@@ -0,0 +1,130 @@
+/* Copyright 2020 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "registers.h"
+
+ .equ PMU_STATUS_PG, (1 << 4)
+ .equ PMU_STATUS_PG_AON, (1 << 5)
+
+ .equ PMU_PG_EN, (1 << 0)
+ .equ PMU_PG_EXIT_COMPLETE, (1 << 8)
+
+ .equ FWST_AON_STATE_MASK, (0x7 << 24)
+ .equ FWST_AON_STATE_HALT, (0x2 << 24)
+
+ .equ EFLAGS_NT, (1 << 14)
+
+ .equ TSS_ESP0_OFFSET, 0x4
+ .equ TSS_LDT_SEG_SEL_OFFSET, 0x60
+
+ .equ AON_CS, 0x4
+ .equ AON_DS, 0xc
+
+
+ .global ipapg
+ipapg:
+ push %ebp
+ push %edi
+ push %esi
+ push %ebx
+ mov %cr0, %eax
+ push %eax
+ mov %cr4, %eax
+ push %eax
+
+ clts
+
+ #write down return address for ROM
+ movl $(PMU_STATUS_PG|PMU_STATUS_PG_AON), PMU_STATUS_REG_ADDR
+ movl $out_of_pg, %eax
+ movl %eax, PMU_SCRATCHPAD0_REG_ADDR
+ movl (%eax), %eax
+ movl %eax, PMU_SCRATCHPAD1_REG_ADDR
+
+ #enable IPAPG, we will actually enter PG on the next halt
+ movl $(PMU_PG_EN|PMU_PG_EXIT_COMPLETE), PMU_PG_EN_REG_ADDR
+
+ #save esp so we can restore stack after returning from ROM
+ lea aon_tss, %eax
+ movl %esp, TSS_ESP0_OFFSET(%eax)
+
+ sti
+ hlt
+
+ #unreachable
+
+
+ #got out of IPAPG, jumped here from ROM if there was no abort condition
+out_of_pg:
+ cli
+
+ #restore stack
+ lea aon_tss, %eax
+ movl TSS_ESP0_OFFSET(%eax), %esp
+
+ #set the nested task bit in eflags
+ pushfl
+ orl $EFLAGS_NT, (%esp)
+ popfl
+
+ clts
+ fninit
+
+ #restore non-volatile registers and CR0 & CR4
+ pop %eax
+ mov %eax, %cr4
+ pop %eax
+ mov %eax, %cr0
+ pop %ebx
+ pop %esi
+ pop %edi
+ pop %ebp
+
+ #check if we're indeed after IPAPG exit
+ testl $PMU_STATUS_PG, PMU_STATUS_REG_ADDR
+ jz after_pg
+
+ #we didn't go through ROM, clear PG_EN bit and return an abort condition to AON
+ movl $0, PMU_PG_EN_REG_ADDR
+ movl $0, %eax
+ jmp return_to_aon
+
+after_pg:
+ #return to caller that we got ouf of PG
+ movl $1, %eax
+
+return_to_aon:
+ movl $0, PMU_STATUS_REG_ADDR
+
+ #return to AON task (still with ROM GDT and segments in case of PG exit)
+ ret
+
+ .global pg_exit_save_ctx
+pg_exit_save_ctx:
+ sgdtl mainfw_gdt
+ str tr
+ ret
+
+ .global pg_exit_restore_ctx
+pg_exit_restore_ctx:
+
+ #load RTOS GDT and AON task
+ lgdtl mainfw_gdt
+ ltr tr
+
+ #load AON LDT and segments
+ lea aon_tss, %eax
+ lldt TSS_LDT_SEG_SEL_OFFSET(%eax)
+ mov $AON_DS, %ax
+ mov %ax, %ds
+ mov %ax, %es
+ mov %ax, %fs
+ mov %ax, %gs
+ mov %ax, %ss
+ ljmpl $AON_CS, $cont
+
+cont:
+ nop
+ ret
diff --git a/chip/ish/aontaskfw/ish_aon_defs.h b/chip/ish/aontaskfw/ish_aon_defs.h
new file mode 100644
index 0000000000..3cc3a491c0
--- /dev/null
+++ b/chip/ish/aontaskfw/ish_aon_defs.h
@@ -0,0 +1,37 @@
+/* Copyright 2019 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef __CROS_EC_ISH_AON_DEFS_H
+#define __CROS_EC_ISH_AON_DEFS_H
+
+#include "ia_structs.h"
+
+/* aontask entry point function */
+void ish_aon_main(void);
+
+#ifdef CONFIG_ISH_IPAPG
+extern int ipapg(void);
+extern void pg_exit_restore_ctx(void);
+extern void pg_exit_save_ctx(void);
+#else
+static int ipapg(void)
+{
+ return 0;
+}
+static void pg_exit_restore_ctx(void)
+{
+}
+static void pg_exit_save_ctx(void)
+{
+}
+#endif
+
+struct gdt_header mainfw_gdt;
+uint16_t tr;
+
+#define FPU_REG_SET_SIZE 108
+uint8_t fpu_reg_set[FPU_REG_SET_SIZE];
+
+#endif /* __CROS_EC_ISH_AON_DEFS_H */
diff --git a/chip/ish/aontaskfw/ish_aon_share.h b/chip/ish/aontaskfw/ish_aon_share.h
index e804bd72e8..ff60a004c9 100644
--- a/chip/ish/aontaskfw/ish_aon_share.h
+++ b/chip/ish/aontaskfw/ish_aon_share.h
@@ -27,6 +27,10 @@ struct ish_aon_share {
uint32_t error_count;
/* last error */
int last_error;
+ /* successfully exit from IPAPG or not */
+ uint32_t pg_exit;
+ /* high 32bits of 64 bits dram address for dma */
+ uint32_t uma_msb;
/* aontask's TSS segment entry */
struct tss_entry *aon_tss;
/* aontask's LDT start address */
diff --git a/chip/ish/aontaskfw/ish_aontask.c b/chip/ish/aontaskfw/ish_aontask.c
index c6e5552127..ab9d02abbf 100644
--- a/chip/ish/aontaskfw/ish_aontask.c
+++ b/chip/ish/aontaskfw/ish_aontask.c
@@ -46,6 +46,7 @@
#include "common.h"
#include "ia_structs.h"
#include "ish_aon_share.h"
+#include "ish_aon_defs.h"
#include "ish_dma.h"
#include "power_mgt.h"
@@ -166,17 +167,14 @@ static struct idt_header aon_idt_hdr = {
(sizeof(struct idt_entry) * AON_IDT_ENTRY_VEC_FIRST))
};
-/* aontask entry point function */
-void ish_aon_main(void);
-
/**
* 8 bytes reserved on stack, just for GDB to show the correct stack
- * information when doing source code level debuging
+ * information when doing source code level debugging
*/
#define AON_SP_RESERVED (8)
/* TSS segment for aon task */
-static struct tss_entry aon_tss = {
+struct tss_entry aon_tss = {
.prev_task_link = 0,
.reserved1 = 0,
.esp0 = (uint8_t *)(CONFIG_AON_PERSISTENT_BASE - AON_SP_RESERVED),
@@ -190,7 +188,7 @@ static struct tss_entry aon_tss = {
.ss2 = 0,
.reserved4 = 0,
.cr3 = 0,
- /* task excute entry point */
+ /* task execute entry point */
.eip = (uint32_t)&ish_aon_main,
.eflags = 0,
.eax = 0,
@@ -525,6 +523,104 @@ static void sram_power(int on)
}
}
+#define RTC_TICKS_IN_SECOND 32768
+
+static __maybe_unused uint64_t get_rtc(void)
+{
+ uint32_t lower;
+ uint32_t upper;
+ do {
+ upper = MISC_ISH_RTC_COUNTER1;
+ lower = MISC_ISH_RTC_COUNTER0;
+ } while (upper != MISC_ISH_RTC_COUNTER1);
+
+ return ((uint64_t)upper << 32) | lower;
+}
+
+#ifdef CONFIG_ISH_IPAPG
+static int is_ipapg_allowed(void)
+{
+ uint32_t power_ctrl_enabled, sw_power_req, power_ctrl_wake;
+ int system_power_state;
+
+ if (!IS_ENABLED(CONFIG_ISH_IPAPG))
+ return 0;
+
+ system_power_state = ((PMU_PMC_HOST_RST_CTL & PMU_HOST_RST_B) == 0);
+
+ PMU_PMC_HOST_RST_CTL = PMU_PMC_HOST_RST_CTL;
+
+ power_ctrl_enabled = PMU_D3_STATUS;
+ sw_power_req = PMU_SW_PG_REQ;
+ power_ctrl_wake = PMU_PMC_PG_WAKE;
+
+ if (system_power_state)
+ power_ctrl_enabled |= PMU_PCE_PG_ALLOWED;
+
+ PMU_INTERNAL_PCE = (power_ctrl_enabled & PMU_PCE_SHADOW_MASK) |
+ (PMU_PCE_CHANGE_DETECTED) | (PMU_PCE_CHANGE_MASK);
+
+ PMU_SW_PG_REQ = sw_power_req | PMU_SW_PG_REQ_B_RISE |
+ PMU_SW_PG_REQ_B_FALL;
+ PMU_PMC_PG_WAKE = power_ctrl_wake | PMU_PMC_PG_WAKE_RISE |
+ PMU_PMC_PG_WAKE_FALL;
+ PMU_D3_STATUS = (PMU_D3_STATUS) & (PMU_D0I3_ENABLE_MASK |
+ PMU_D3_BIT_SET | PMU_BME_BIT_SET);
+
+ power_ctrl_enabled = PMU_D3_STATUS;
+ sw_power_req = PMU_SW_PG_REQ;
+ power_ctrl_wake = PMU_PMC_PG_WAKE;
+
+ if (system_power_state) {
+ uint64_t rtc_start = get_rtc();
+ uint64_t rtc_end;
+ while (power_ctrl_wake & PMU_PMC_PG_WAKE_VAL) {
+ power_ctrl_wake = PMU_PMC_PG_WAKE;
+ rtc_end = get_rtc();
+ if (rtc_end - rtc_start > RTC_TICKS_IN_SECOND)
+ break;
+ }
+ }
+
+ if (((power_ctrl_enabled & PMU_PCE_PG_ALLOWED) || system_power_state) &&
+ (((sw_power_req & PMU_SW_PG_REQ_B_VAL) == 0) ||
+ ((power_ctrl_enabled & PMU_PCE_PMCRE) == 0)) &&
+ ((power_ctrl_wake & PMU_PMC_PG_WAKE_VAL) == 0))
+ return 1;
+ else
+ return 0;
+}
+#else
+static int is_ipapg_allowed(void)
+{
+ return 0;
+}
+#endif
+
+#define NUMBER_IRQ_PINS 30
+static uint32_t ioapic_rte[NUMBER_IRQ_PINS];
+
+static int do_ipapg(void)
+{
+ int ret;
+ uint32_t rte_offset = IOAPIC_IOREDTBL;
+
+ for (int pin = 0; pin < ARRAY_SIZE(ioapic_rte); pin++) {
+ IOAPIC_IDX = rte_offset + pin * 2;
+ ioapic_rte[pin] = IOAPIC_WDW;
+ }
+
+ ret = ipapg();
+
+ rte_offset = IOAPIC_IOREDTBL;
+ for (int pin = 0; pin < ARRAY_SIZE(ioapic_rte); pin++) {
+ IOAPIC_IDX = rte_offset + pin * 2;
+ IOAPIC_WDW = ioapic_rte[pin];
+ }
+
+ return ret;
+}
+
static inline void set_vnnred_aoncg(void)
{
if (IS_ENABLED(CONFIG_ISH_NEW_PM)) {
@@ -543,6 +639,11 @@ static inline void clear_vnnred_aoncg(void)
static void handle_d0i2(void)
{
+ if (IS_ENABLED(CONFIG_ISH_IPAPG)) {
+ pg_exit_save_ctx();
+ aon_share.pg_exit = 0;
+ }
+
/* set main SRAM into retention mode*/
PMU_LDO_CTRL = PMU_LDO_ENABLE_BIT
| PMU_LDO_RETENTION_BIT;
@@ -552,7 +653,19 @@ static void handle_d0i2(void)
set_vnnred_aoncg();
- ish_mia_halt();
+ if (IS_ENABLED(CONFIG_ISH_IPAPG) && is_ipapg_allowed()) {
+ uint32_t sram_cfg_reg;
+
+ sram_cfg_reg = ISH_SRAM_CTRL_CSFGR;
+
+ aon_share.pg_exit = do_ipapg();
+
+ if (aon_share.pg_exit)
+ ISH_SRAM_CTRL_CSFGR = sram_cfg_reg;
+ } else {
+ ish_mia_halt();
+ }
+
/* wakeup from PMU interrupt */
clear_vnnred_aoncg();
@@ -566,12 +679,23 @@ static void handle_d0i2(void)
*/
while (!(PMU_LDO_CTRL & PMU_LDO_READY_BIT))
continue;
+
+ if (IS_ENABLED(CONFIG_ISH_IPAPG)) {
+ if (aon_share.pg_exit)
+ ish_dma_set_msb(PAGING_CHAN, aon_share.uma_msb,
+ aon_share.uma_msb);
+ }
}
static void handle_d0i3(void)
{
int ret;
+ if (IS_ENABLED(CONFIG_ISH_IPAPG)) {
+ pg_exit_save_ctx();
+ aon_share.pg_exit = 0;
+ }
+
/* store main FW 's context to IMR DDR from main SRAM */
ret = store_main_fw();
@@ -584,7 +708,19 @@ static void handle_d0i3(void)
set_vnnred_aoncg();
- ish_mia_halt();
+ if (IS_ENABLED(CONFIG_ISH_IPAPG) && is_ipapg_allowed()) {
+ uint32_t sram_cfg_reg;
+
+ sram_cfg_reg = ISH_SRAM_CTRL_CSFGR;
+
+ aon_share.pg_exit = do_ipapg();
+
+ if (aon_share.pg_exit)
+ ISH_SRAM_CTRL_CSFGR = sram_cfg_reg;
+ } else {
+ ish_mia_halt();
+ }
+
/* wakeup from PMU interrupt */
clear_vnnred_aoncg();
@@ -592,6 +728,12 @@ static void handle_d0i3(void)
/* power on main SRAM */
sram_power(1);
+ if (IS_ENABLED(CONFIG_ISH_IPAPG)) {
+ if (aon_share.pg_exit)
+ ish_dma_set_msb(PAGING_CHAN, aon_share.uma_msb,
+ aon_share.uma_msb);
+ }
+
/* restore main FW 's context to main SRAM from IMR DDR */
ret = restore_main_fw();
@@ -787,9 +929,16 @@ void ish_aon_main(void)
/* restore main FW's IDT and switch back to main FW */
__asm__ volatile(
"lidtl %0;\n"
- "iret;"
:
: "m" (aon_share.main_fw_idt_hdr)
);
+
+ if (IS_ENABLED(CONFIG_ISH_IPAPG) && aon_share.pg_exit) {
+ mainfw_gdt.entries[tr / sizeof(struct gdt_entry)]
+ .flags &= 0xfd;
+ pg_exit_restore_ctx();
+ }
+
+ __asm__ volatile ("iret;");
}
}