diff options
author | Leifu Zhao <leifu.zhao@intel.com> | 2020-04-24 18:59:12 +0800 |
---|---|---|
committer | Commit Bot <commit-bot@chromium.org> | 2020-05-15 19:20:48 +0000 |
commit | 45a7c5cf8ff59a917bd7dda6ccd3f14dbab2c4dd (patch) | |
tree | e6a355c05fc0ae6f6bf5a21ffcbb2ddd9d500d33 /chip/ish/aontaskfw | |
parent | c828740d6050fc40cf1b881374679ebf0e4b5666 (diff) | |
download | chrome-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-x | chip/ish/aontaskfw/ipapg.S | 130 | ||||
-rw-r--r-- | chip/ish/aontaskfw/ish_aon_defs.h | 37 | ||||
-rw-r--r-- | chip/ish/aontaskfw/ish_aon_share.h | 4 | ||||
-rw-r--r-- | chip/ish/aontaskfw/ish_aontask.c | 167 |
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;"); } } |