pm_34xx.c
来自「omap3 linux 2.6 用nocc去除了冗余代码」· C语言 代码 · 共 1,647 行 · 第 1/3 页
C
1,647 行
/* * linux/arch/arm/mach-omap2/pm_34xx.c * * OMAP3 Power Management Routines * * Copyright (C) 2007 Texas Instruments, Inc. * Karthik Dasu <karthik-dp@ti.com> * * Copyright (C) 2006 Nokia Corporation * Tony Lindgren <tony@atomide.com> * * Copyright (C) 2005 Texas Instruments, Inc. * Richard Woodruff <r-woodruff2@ti.com> * * Based on pm.c for omap1 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. */#include <linux/pm.h>#include <linux/sched.h>#include <linux/proc_fs.h>#include <linux/interrupt.h>#include <linux/sysfs.h>#include <linux/module.h>#include <linux/delay.h>#include <linux/cpuidle.h>#include <asm/io.h>#include <asm/irq.h>#include <asm/atomic.h>#include <asm/mach/time.h>#include <asm/mach/irq.h>#include <asm/mach-types.h>#include <linux/mm.h>#include <asm/mmu.h>#include <asm/tlbflush.h>#include <asm/arch/irqs.h>#include <asm/arch/clock.h>#include <asm/arch/sram.h>#include <asm/arch/pm.h>#include <linux/tick.h>#define SR1_ID 1#define SR2_ID 2#include "prcm-regs.h"/* * Define DEBUG_HW_SUP for extended information during 'cat /proc/pm_prepwst' */#undef DEBUG_HW_SUP#define S600M 600000000#define S550M 550000000#define S500M 500000000#define S250M 250000000#define S125M 125000000#define S19M 19200000#define S120M 120000000#define S477M 476000000#define S381M 381000000#define S191M 190000000#define S96M 96000000#define S166M 166000000#define S83M 83000000#define PRCM_MPU_IRQ 0xB /* MPU IRQ 11 */#define CORE_FCLK_MASK 0x3FF9E29 /* Mask of all functional clocks*/ /* in core except UART */#define CORE3_FCLK_MASK 0x7 /* Mask of all functional clocks */#define USBHOST_FCLK_MASK 0x3 /* Mask of all functional clocks in USB */#define SGX_FCLK_MASK 0x2 /* Mask of all functional clocks in SGX */#define DSS_FCLK_MASK 0x7 /* Mask of all functional clocks in DSS */#define CAM_FCLK_MASK 0x1 /* Mask of all functional clocks in CAM */#define PER_FCLK_MASK 0x17FF /* Mask of all functional clocks in PER */ /* except UART and GPIO */#define CORE1_ICLK_VALID 0x3FFFFFF9 /*Ignore SDRC_ICLK*/#define CORE2_ICLK_VALID 0x1F#define CORE3_ICLK_VALID 0x4#define USBHOST_ICLK_VALID 0x1#define SGX_ICLK_VALID 0x1#define DSS_ICLK_VALID 0x1#define CAM_ICLK_VALID 0x1#define PER_ICLK_VALID 0x1#define WKUP_ICLK_VALID 0x3E /* Ignore GPT1 ICLK as it is handled explicitly*/#define OMAP3_MAX_STATES 7#define OMAP3_STATE_C0 0 /* MPU ACTIVE + CORE ACTIVE(only WFI)*/#define OMAP3_STATE_C1 1 /* MPU WFI + Dynamic tick + CORE ACTIVE*/#define OMAP3_STATE_C2 2 /* MPU CSWR + CORE ACTIVE*/#define OMAP3_STATE_C3 3 /* MPU OFF + CORE ACTIVE*/#define OMAP3_STATE_C4 4 /* MPU RET + CORE CSWR */#define OMAP3_STATE_C5 5 /* MPU OFF + CORE CSWR */#define OMAP3_STATE_C6 6 /* MPU OFF + CORE OFF */#define MAX_SUPPORTED_STATES 5#define IOPAD_WKUP 1/* #define DEBUG_CPUIDLE 1 */#define DPRINTK(fmt, args...)int cpuidle_deepest_st = 0;/* Macro for debugging */#define RESTORE_TABLE_ENTRY 1/* * Time-out value for frame buffer (in seconds). */int fb_timeout_val = 30;u32 target_opp_no;int enable_off = 1;u32 debug_domain = DOM_CORE1;struct res_handle *memret1;struct res_handle *memret2;struct res_handle *logret1;int res1_level = -1, res2_level = -1, res3_level = -1;static struct constraint_handle *vdd1_opp_co;static struct constraint_handle *vdd2_opp_co;static struct constraint_id cnstr_id1 = { .type = RES_FREQ_CO, .data = (void *)"vdd1_opp",};static struct constraint_id cnstr_id2 = { .type = RES_FREQ_CO, .data = (void *)"vdd2_opp",};/* * Time-out value for UART before cutting clock (in msecs). */#define UART_TIME_OUT 6000extern void omap_uart_save_ctx(void);extern void omap_uart_restore_ctx(void);extern void set_blank_interval(int fb_timeout_val);#define SCRATCHPAD_ROM 0x48002860#define SCRATCHPAD 0x48002910#define SCRATCHPAD_ROM_OFFSET 0x19C#define TABLE_ADDRESS_OFFSET 0x31#define TABLE_VALUE_OFFSET 0x30#define CONTROL_REG_VALUE_OFFSET 0x32struct system_power_state target_state;static u32 *scratchpad_restore_addr;static u32 restore_pointer_address;static u32 mpu_ret_cnt;static u32 mpu_off_cnt;static u32 core_ret_cnt;static u32 core_off_cnt;struct omap3_processor_cx { u8 valid; u8 type; u32 sleep_latency; u32 wakeup_latency; u32 mpu_state; u32 core_state; u32 threshold; u32 flags;};#define LAST_IDLE_STATE_ARR_SIZE 10struct idle_state { u32 mpu_state; u32 core_state; u32 fclks; u32 iclks; u8 iva_state;};static struct idle_state last_idle_state[LAST_IDLE_STATE_ARR_SIZE];u32 arr_wrptr;struct omap3_processor_cx omap3_power_states[OMAP3_MAX_STATES];struct omap3_processor_cx current_cx_state;static void (*saved_idle)(void);u32 current_vdd1_opp = PRCM_VDD1_OPP3;u32 current_vdd2_opp = PRCM_VDD2_OPP3;EXPORT_SYMBOL(current_vdd1_opp);EXPORT_SYMBOL(current_vdd2_opp);EXPORT_SYMBOL(power_subsys);struct clk *p_vdd1_clk;struct clk *p_vdd2_clk;u32 vdd1_opp_no;u32 vdd2_opp_no;static unsigned long awake_time_end;struct mpu_core_vdd_state target_sleep_state;/* * Functions to save & restore core context. */extern void prcm_save_core_context(u32 target_core_state);extern void prcm_restore_core_context(u32 target_core_state);/** * store_prepwst - Store the previous power state */static void store_prepwst(void){ last_idle_state[arr_wrptr].mpu_state = PM_PREPWSTST_MPU; last_idle_state[arr_wrptr].core_state = PM_PREPWSTST_CORE; if ((PM_PREPWSTST_MPU & 0x3) == 0x1) mpu_ret_cnt++; if ((PM_PREPWSTST_MPU & 0x3) == 0x0) mpu_off_cnt++; if ((PM_PREPWSTST_CORE & 0x3) == 0x1) core_ret_cnt++; if ((PM_PREPWSTST_CORE & 0x3) == 0x0) core_off_cnt++; last_idle_state[arr_wrptr].fclks = ( (CM_FCLKEN1_CORE & CORE_FCLK_MASK) | (CM_FCLKEN_SGX & SGX_FCLK_MASK) | (CM_FCLKEN_DSS & DSS_FCLK_MASK) | (CM_FCLKEN_USBHOST & USBHOST_FCLK_MASK) | (CM_FCLKEN3_CORE & CORE3_FCLK_MASK) | (CM_FCLKEN_CAM & CAM_FCLK_MASK) | (CM_FCLKEN_PER & PER_FCLK_MASK)); last_idle_state[arr_wrptr].iclks = ( (CORE1_ICLK_VALID & (CM_ICLKEN1_CORE & ~CM_AUTOIDLE1_CORE)) | (CORE2_ICLK_VALID & (CM_ICLKEN2_CORE & ~CM_AUTOIDLE2_CORE)) | (CORE3_ICLK_VALID & (CM_ICLKEN3_CORE & ~CM_AUTOIDLE3_CORE)) | (SGX_ICLK_VALID & (CM_ICLKEN_SGX)) | (USBHOST_ICLK_VALID & (CM_ICLKEN_USBHOST)) | (DSS_ICLK_VALID & (CM_ICLKEN_DSS & ~CM_AUTOIDLE_DSS)) | (CAM_ICLK_VALID & (CM_ICLKEN_CAM & ~CM_AUTOIDLE_CAM)) | (PER_ICLK_VALID & (CM_ICLKEN_PER & ~CM_AUTOIDLE_PER)) | (WKUP_ICLK_VALID & (CM_ICLKEN_WKUP & ~CM_AUTOIDLE_WKUP))); prcm_get_power_domain_state(DOM_IVA2, &(last_idle_state[arr_wrptr].iva_state)); arr_wrptr++; if (arr_wrptr == LAST_IDLE_STATE_ARR_SIZE) arr_wrptr = 0;}int omap_get_system_sleep_time(int ticks){ ticks -= (current_cx_state.wakeup_latency)/10000; return ticks;}static void restore_control_register(u32 val){ __asm__ __volatile__ ("mcr p15, 0, %0, c1, c0, 0" : : "r" (val));}/** * restore_table_entry - restore table entry that was modified for enabling MMU */static void restore_table_entry(void){ u32 *scratchpad_address; u32 previous_value, control_reg_value; u32 *address; /* Get virtual address of SCRATCHPAD */ scratchpad_address = (u32 *) io_p2v(SCRATCHPAD); /* Get address of entry that was modified */ address = (u32 *) *(scratchpad_address + TABLE_ADDRESS_OFFSET); /* Get the previous value which needs to be restored */ previous_value = *(scratchpad_address + TABLE_VALUE_OFFSET); /* Convert address to virtual address */ address = __va(address); /* Restore table entry */ *address = previous_value; /* Flush TLB */ flush_tlb_all(); control_reg_value = *(scratchpad_address + CONTROL_REG_VALUE_OFFSET); /* Restore control register*/ /* This will enable caches and prediction */ restore_control_register(control_reg_value);}static void (*_omap_sram_idle)(u32 *addr, int save_state);void omap_sram_idle(void){ /* Variable to tell what needs to be saved and restored * in omap_sram_idle*/ /* save_state = 0 => Nothing to save and restored */ /* save_state = 1 => Only L1 and logic lost */ /* save_state = 2 => Only L2 lost */ /* save_state = 3 => L1, L2 and logic lost */ int save_state = 0; if (!_omap_sram_idle) return; switch (target_state.mpu_state) { case PRCM_MPU_ACTIVE: case PRCM_MPU_INACTIVE: case PRCM_MPU_CSWR_L2RET: /* No need to save context */ save_state = 0; break; case PRCM_MPU_OSWR_L2RET: /* L1 and Logic lost */ save_state = 1; break; case PRCM_MPU_CSWR_L2OFF: /* Only L2 lost */ save_state = 2; break; case PRCM_MPU_OSWR_L2OFF: case PRCM_MPU_OFF: /* L1, L2 and logic lost */ save_state = 3; break; default: /* Invalid state */ printk(KERN_ERR "Invalid mpu state in sram_idle\n"); return; } _omap_sram_idle(context_mem, save_state); /* Restore table entry modified during MMU restoration */ if ((PM_PREPWSTST_MPU & 0x3) == 0x0) restore_table_entry();}static int pre_uart_inactivity(void){ int driver8250_managed = 0; if (are_driver8250_uarts_active(&driver8250_managed)) { awake_time_end = jiffies + msecs_to_jiffies(UART_TIME_OUT); return 0; } if (time_before(jiffies, awake_time_end)) { return 0; } return 1;}static void post_uart_inactivity(void){ if (awake_time_end == 0) awake_time_end = jiffies;}static int omap3_pm_prepare(suspend_state_t state){ int error = 0; /* We cannot sleep in idle until we have resumed */ saved_idle = pm_idle; pm_idle = NULL; switch (state) { case PM_SUSPEND_STANDBY: case PM_SUSPEND_MEM: break; /*TODO: Need to fix this*/ /*case PM_SUSPEND_DISK: return -ENOTSUPP;*/ default: return -EINVAL; } return error;}/* Save and retore global configuration in NEON domain */static void omap3_save_neon_context(void){ /* Nothing to do here */ return;}static void omap3_restore_neon_context(void){ vfp_enable();}/** * omap3_save_per_context - Save global configuration in PER domain * * Only the GPIO save is done here. */static void omap3_save_per_context(void){ omap_gpio_save(); omap_uart_save_ctx();}/** * omap3_restore_per_context - Restore global configuration in PER domain * * Only the GPIO restore is done here. */static void omap3_restore_per_context(void){ omap_gpio_restore(); omap_uart_restore_ctx();}/* Configuration that is OS specific is done here */static void omap3_restore_core_settings(void){ prcm_lock_iva_dpll(current_vdd1_opp); restore_sram_functions(); _omap_sram_idle = omap_sram_push(omap34xx_suspend, omap34xx_suspend_sz); save_scratchpad_contents();}static void memory_logic_res_seting(void){ if (res3_level == LOGIC_RET) { if ((res1_level == MEMORY_RET) && (res2_level == MEMORY_RET)) target_state.core_state = PRCM_CORE_CSWR_MEMRET; else if (res1_level == MEMORY_OFF && res2_level == MEMORY_RET) target_state.core_state = PRCM_CORE_CSWR_MEM1OFF; else if (res1_level == MEMORY_RET && res2_level == MEMORY_OFF) target_state.core_state = PRCM_CORE_CSWR_MEM2OFF; else target_state.core_state = PRCM_CORE_CSWR_MEMOFF; } else if (res3_level == LOGIC_OFF) { if ((res1_level && res2_level) == MEMORY_RET) target_state.core_state = PRCM_CORE_OSWR_MEMRET; else if (res1_level == MEMORY_OFF && res2_level == MEMORY_RET) target_state.core_state = PRCM_CORE_OSWR_MEM1OFF; else if (res1_level == MEMORY_RET && res2_level == MEMORY_OFF) target_state.core_state = PRCM_CORE_OSWR_MEM2OFF; else target_state.core_state = PRCM_CORE_OSWR_MEMOFF; } else DPRINTK("Current State not supported in Retention");}/** * omap3_pm_suspend */static int omap3_pm_suspend(void){ int ret; disable_smartreflex(SR1_ID); disable_smartreflex(SR2_ID); local_irq_disable(); local_fiq_disable(); target_state.iva2_state = PRCM_RET; target_state.gfx_state = PRCM_RET; target_state.dss_state = PRCM_RET; target_state.cam_state = PRCM_RET; target_state.per_state = PRCM_RET; target_state.neon_state = PRCM_RET; target_state.usbhost_state = PRCM_RET; target_state.mpu_state = PRCM_MPU_CSWR_L2RET; if (target_state.neon_state == PRCM_OFF) omap3_save_neon_context(); if (target_state.per_state == PRCM_OFF) omap3_save_per_context(); target_state.core_state = PRCM_CORE_CSWR_MEMRET; if (target_state.core_state == PRCM_CORE_CSWR_MEMRET) { res1_level = resource_get_level(memret1); res2_level = resource_get_level(memret2); res3_level = resource_get_level(logret1); memory_logic_res_seting(); } if (target_state.core_state >= PRCM_CORE_OSWR_MEMRET) { prcm_save_core_context(target_state.core_state); omap_uart_save_ctx(); } omap_disable_system_timer(); ret = prcm_set_chip_power_mode(&target_state, PRCM_WAKEUP_T2_KEYPAD | PRCM_WAKEUP_TOUCHSCREEN); if (ret != 0) { printk(KERN_ERR "pm_suspend: Unable to set target state\n"); } else { printk(KERN_INFO "pm_suspend: Successfully set target state\n"); printk(KERN_INFO "Target MPU state: CSWR_L2RET, " "Target CORE state: CSWR_MEMRET\n"); } omap_enable_system_timer(); if (target_state.neon_state == PRCM_OFF) omap3_restore_neon_context(); if (target_state.per_state == PRCM_OFF) omap3_restore_per_context(); if (target_state.core_state >= PRCM_CORE_OSWR_MEMRET) { prcm_restore_core_context(target_state.core_state); omap_uart_restore_ctx(); } if ((target_state.core_state > PRCM_CORE_CSWR_MEMRET) && (target_state.core_state != PRCM_CORE_OSWR_MEMRET)) { restore_sram_functions(); _omap_sram_idle = omap_sram_push(omap34xx_suspend, omap34xx_suspend_sz); } local_fiq_enable(); local_irq_enable(); enable_smartreflex(SR1_ID); enable_smartreflex(SR2_ID); return 0;}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?