pm_34xx.c
来自「omap3 linux 2.6 用nocc去除了冗余代码」· C语言 代码 · 共 1,647 行 · 第 1/3 页
C
1,647 行
static int omap3_pm_enter(suspend_state_t state){ int ret = 0; switch (state) { case PM_SUSPEND_STANDBY: case PM_SUSPEND_MEM: ret = omap3_pm_suspend(); break; /* case PM_SUSPEND_DISK: ret = -ENOTSUPP; break; */ default: ret = -EINVAL; } return ret;}static int omap3_pm_valid(suspend_state_t state){ int ret = 0; switch (state) { case PM_SUSPEND_STANDBY: case PM_SUSPEND_MEM: ret = 1; break; default: ret = -EINVAL; } return ret;}static int omap3_pm_finish(suspend_state_t state){ pm_idle = saved_idle; return 0;}static struct pm_ops omap_pm_ops = { .valid = omap3_pm_valid, .prepare = omap3_pm_prepare, .enter = omap3_pm_enter, .finish = omap3_pm_finish,};static int omap3_idle_bm_check(void){ u32 core_dep; u8 state; /* Check if any modules other than debug uart and gpios are active*/ core_dep = ( (CM_FCLKEN1_CORE & CORE_FCLK_MASK) | (CM_FCLKEN_SGX & SGX_FCLK_MASK) | (CM_FCLKEN_DSS & DSS_FCLK_MASK) | (CM_FCLKEN_CAM & CAM_FCLK_MASK) | (CM_FCLKEN_PER & PER_FCLK_MASK) | (CM_FCLKEN_USBHOST & USBHOST_FCLK_MASK) | (CM_FCLKEN3_CORE & CORE3_FCLK_MASK)); /* To allow core retention during LPR scenario */ if (!lpr_enabled) core_dep |= (CM_FCLKEN_DSS & DSS_FCLK_MASK); DPRINTK("FCLKS: %x,%x,%x,%x,%x,%x,%x\n", (CM_FCLKEN1_CORE & CORE_FCLK_MASK), (CM_FCLKEN3_CORE & CORE3_FCLK_MASK), (CM_FCLKEN_SGX & SGX_FCLK_MASK), (CM_FCLKEN_DSS & DSS_FCLK_MASK), (CM_FCLKEN_CAM & CAM_FCLK_MASK), (CM_FCLKEN_PER & PER_FCLK_MASK), (CM_FCLKEN_USBHOST & USBHOST_FCLK_MASK)); /* Check if any modules have ICLK bit enabled and interface clock */ /* autoidle disabled */ core_dep |= (CORE1_ICLK_VALID & (CM_ICLKEN1_CORE & ~CM_AUTOIDLE1_CORE)); /* Check for secure modules which have only ICLK */ /* Do not check for rng module.It has been ensured that * if rng is active cpu idle will never be entered */ core_dep |= (CORE2_ICLK_VALID & CM_ICLKEN2_CORE & ~4); /* Enabling SGX ICLK will prevent CORE ret*/ core_dep |= SGX_ICLK_VALID & (CM_ICLKEN_SGX); core_dep |= (CORE3_ICLK_VALID & (CM_ICLKEN3_CORE & ~CM_AUTOIDLE3_CORE)); core_dep |= (USBHOST_ICLK_VALID & (CM_ICLKEN_USBHOST & ~CM_AUTOIDLE_USBHOST)); core_dep |= (DSS_ICLK_VALID & (CM_ICLKEN_DSS & ~CM_AUTOIDLE_DSS)); core_dep |= (CAM_ICLK_VALID & (CM_ICLKEN_CAM & ~CM_AUTOIDLE_CAM)); core_dep |= (PER_ICLK_VALID & (CM_ICLKEN_PER & ~CM_AUTOIDLE_PER)); core_dep |= (WKUP_ICLK_VALID & (CM_ICLKEN_WKUP & ~CM_AUTOIDLE_WKUP)); DPRINTK("ICLKS: %x,%x,%x,%x%x,%x,%x\n", (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 & ~CM_AUTOIDLE_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, &state); DPRINTK("IVA:%d\n", state); if (state == PRCM_ON) core_dep |= 1; if (core_dep) return 1; else return 0;}/* Correct target state based on inactivity timer expiry, etc */static void correct_target_state(void){ switch (target_state.mpu_state) { case PRCM_MPU_ACTIVE: case PRCM_MPU_INACTIVE: target_state.neon_state = PRCM_ON; break; case PRCM_MPU_CSWR_L2RET: case PRCM_MPU_OSWR_L2RET: case PRCM_MPU_CSWR_L2OFF: case PRCM_MPU_OSWR_L2OFF: target_state.neon_state = PRCM_RET; break; case PRCM_MPU_OFF: target_state.neon_state = PRCM_OFF; if (!enable_off) { target_state.mpu_state = PRCM_MPU_CSWR_L2RET; target_state.neon_state = PRCM_RET; } break; } if (target_state.core_state > PRCM_CORE_INACTIVE) { target_state.per_state = PRCM_RET; } else target_state.per_state = PRCM_ON; res1_level = resource_get_level(memret1); res2_level = resource_get_level(memret2); res3_level = resource_get_level(logret1); if (target_state.core_state == PRCM_CORE_CSWR_MEMRET) memory_logic_res_seting();}static int omap3_enter_idle(struct cpuidle_device *dev, struct cpuidle_state *state){ struct omap3_processor_cx *cx = cpuidle_get_statedata(state); u8 cur_per_state, cur_neon_state, pre_neon_state, pre_per_state; unsigned long timer_32k_sleep_ticks; u32 fclken_core, iclken_core, fclken_per, iclken_per; u32 reprogram_ns; int reprogram_us; unsigned long long reprogram_cycles; int wakeup_latency; /* Reset previous power state registers for mpu and core*/ PM_PREPWSTST_MPU = 0xFF; PM_PREPWSTST_CORE = 0xFF; PM_PREPWSTST_NEON = 0xFF; PM_PREPWSTST_PER = 0xFF; current_cx_state = *cx; target_state.mpu_state = cx->mpu_state; target_state.core_state = cx->core_state; if (INTCPS_PENDING_IRQ0 | INTCPS_PENDING_IRQ1 | INTCPS_PENDING_IRQ2) { store_prepwst(); return 0; } if (cx->type == OMAP3_STATE_C0) { omap_sram_idle(); store_prepwst(); return 0; } correct_target_state(); wakeup_latency = cx->wakeup_latency; if (target_state.core_state != cx->core_state) { /* Currently, this can happen only for core_off */ /* Adjust wakeup latency to that of core_cswr state */ /* Hard coded now and needs to be made more generic */ /* omap3_power_states[4] is CSWR for core */ wakeup_latency = omap3_power_states[4].wakeup_latency; } timer_32k_sleep_ticks = omap_32k_sync_timer_read(); /* Reprogram the tick timer */ reprogram_us = (s32) ktime_to_ns(tick_nohz_get_sleep_length())/1000; if (reprogram_us > wakeup_latency) { reprogram_us = reprogram_us - wakeup_latency; reprogram_ns = reprogram_us * 1000; reprogram_cycles = (unsigned long long) reprogram_ns * div_sc(32768, NSEC_PER_SEC, 32); reprogram_cycles >>= 32; omap_32k_timer_start((unsigned long) reprogram_cycles); } /* Check for pending interrupts. If there is an interrupt, return */ if (INTCPS_PENDING_IRQ0 | INTCPS_PENDING_IRQ1 | INTCPS_PENDING_IRQ2) { store_prepwst(); return 0; } prcm_get_power_domain_state(DOM_PER, &cur_per_state); prcm_get_power_domain_state(DOM_NEON, &cur_neon_state); fclken_core = CM_FCLKEN1_CORE; iclken_core = CM_ICLKEN1_CORE; fclken_per = CM_FCLKEN_PER; iclken_per = CM_ICLKEN_PER; /* If target state if core_off, save registers * before changing anything */ if (target_state.core_state >= PRCM_CORE_OSWR_MEMRET) { prcm_save_registers(); omap_uart_save_ctx(); } /* Check for pending interrupts. If there is an interrupt, return */ if (INTCPS_PENDING_IRQ0 | INTCPS_PENDING_IRQ1 | INTCPS_PENDING_IRQ2) { store_prepwst(); return 0; } /* Program MPU and NEON to target state */ if (target_state.mpu_state > PRCM_MPU_ACTIVE) { if ((cur_neon_state == PRCM_ON) && (target_state.neon_state != PRCM_ON)) { if (target_state.neon_state == PRCM_OFF) omap3_save_neon_context();; prcm_force_power_domain_state(DOM_NEON, target_state.neon_state); } prcm_set_mpu_domain_state(target_state.mpu_state); } /* Check for pending interrupts. If there is an interrupt, return */ if (INTCPS_PENDING_IRQ0 | INTCPS_PENDING_IRQ1 | INTCPS_PENDING_IRQ2) goto restore; /* Program CORE and PER to target state */ if ((target_state.core_state > PRCM_CORE_ACTIVE) && (pre_uart_inactivity())) { if ((cur_per_state == PRCM_ON) && (target_state.per_state != PRCM_ON)) { if (target_state.per_state == PRCM_OFF) omap3_save_per_context();; CM_FCLKEN_PER = 0; CM_ICLKEN_PER = 0; prcm_force_power_domain_state(DOM_PER, target_state.per_state); } disable_smartreflex(SR1_ID); disable_smartreflex(SR2_ID); /* WORKAROUND FOR SILICON ERRATA 1.64*/ if (is_sil_rev_equal_to(OMAP3430_REV_ES1_0)) { if ((CM_CLKOUT_CTRL & (0x1 << 7)) == 0x80) CM_CLKOUT_CTRL &= ~(0x1 << 7); } prcm_set_core_domain_state(target_state.core_state); /* Enable Autoidle for GPT1 explicitly - Errata 1.4 */ CM_AUTOIDLE_WKUP |= 0x1; CM_FCLKEN1_CORE &= ~0x6000; /* Disable HSUSB OTG ICLK explicitly*/ CM_ICLKEN1_CORE &= ~0x10; /* Enabling IO_PAD capabilities */ PM_WKEN_WKUP |= 0x100; } /* Check for pending interrupts. If there is an interrupt, return */ if (INTCPS_PENDING_IRQ0 | INTCPS_PENDING_IRQ1 | INTCPS_PENDING_IRQ2) goto restore; omap_sram_idle();restore: /* Disabling IO_PAD capabilities */ PM_WKEN_WKUP &= ~(0x100); CM_FCLKEN1_CORE = fclken_core; CM_ICLKEN1_CORE = iclken_core; post_uart_inactivity(); if (target_state.mpu_state > PRCM_MPU_ACTIVE) { prcm_set_mpu_domain_state(PRCM_MPU_ACTIVE); if ((cur_neon_state == PRCM_ON) && (target_state.mpu_state > PRCM_MPU_INACTIVE)) { prcm_force_power_domain_state(DOM_NEON, cur_neon_state); prcm_get_pre_power_domain_state(DOM_NEON, &pre_neon_state); if (pre_neon_state == PRCM_OFF) omap3_restore_neon_context(); } } if (target_state.core_state > PRCM_CORE_ACTIVE) { prcm_set_core_domain_state(PRCM_CORE_ACTIVE); enable_smartreflex(SR1_ID); enable_smartreflex(SR2_ID); if (cur_per_state == PRCM_ON) { prcm_force_power_domain_state(DOM_PER, cur_per_state); prcm_get_pre_power_domain_state(DOM_PER, &pre_per_state); CM_FCLKEN_PER = fclken_per; CM_ICLKEN_PER = iclken_per; if (pre_per_state == PRCM_OFF) { omap3_restore_per_context(); } } if (target_state.core_state >= PRCM_CORE_OSWR_MEMRET) { prcm_restore_registers(); prcm_restore_core_context(target_state.core_state); omap3_restore_core_settings(); } /* Errata 1.4 * if the timer device gets idled which is when we * are cutting the timer ICLK which is when we try * to put Core to RET. * Wait Period = 2 timer interface clock cycles + * 1 timer functional clock cycle * Interface clock = L4 clock. For the computation L4 * clock is assumed at 50MHz (worst case). * Functional clock = 32KHz * Wait Period = 2*10^-6/50 + 1/32768 = 0.000030557 = 30.557uSec * Roundingoff the delay value to a safer 50uSec */ omap_udelay(GPTIMER_WAIT_DELAY); CM_AUTOIDLE_WKUP &= ~(0x1); } DPRINTK("MPU state:%x,CORE state:%x\n", PM_PREPWSTST_MPU, PM_PREPWSTST_CORE); store_prepwst(); timer_32k_sleep_ticks = omap_32k_sync_timer_read() - timer_32k_sleep_ticks; if (target_state.core_state >= PRCM_CORE_OSWR_MEMRET) omap_uart_restore_ctx(); if ((target_state.core_state > PRCM_CORE_CSWR_MEMRET) && (target_state.core_state != PRCM_CORE_OSWR_MEMRET)) { restore_sram_functions(); /*restore sram data */ _omap_sram_idle = omap_sram_push(omap34xx_suspend, omap34xx_suspend_sz); } return omap_32k_ticks_to_usecs(timer_32k_sleep_ticks);}static int omap3_idle_init(struct cpuidle_device *dev){ int i, count = 0; struct omap3_processor_cx *cx; struct cpuidle_state *state; for (i = 0; i < OMAP3_MAX_STATES; i++) { cx = &omap3_power_states[i]; state = &dev->states[count]; if (!cx->valid) continue; cpuidle_set_statedata(state, cx); state->exit_latency = cx->sleep_latency + cx->wakeup_latency; state->target_residency = cx->threshold; state->flags = cx->flags; state->enter = omap3_enter_idle; count++; } if (!count) return -EINVAL; dev->state_count = count; return 0;}void omap_init_power_states(void){ omap3_power_states[0].valid = 1; omap3_power_states[0].type = OMAP3_STATE_C0; omap3_power_states[0].sleep_latency = 0; omap3_power_states[0].wakeup_latency = 0; omap3_power_states[0].threshold = 0; omap3_power_states[0].mpu_state = PRCM_MPU_ACTIVE; omap3_power_states[0].core_state = PRCM_CORE_ACTIVE; omap3_power_states[0].flags = CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_SHALLOW; omap3_power_states[1].valid = 1; omap3_power_states[1].type = OMAP3_STATE_C1; omap3_power_states[1].sleep_latency = 10; omap3_power_states[1].wakeup_latency = 10; omap3_power_states[1].threshold = 30; omap3_power_states[1].mpu_state = PRCM_MPU_ACTIVE; omap3_power_states[1].core_state = PRCM_CORE_ACTIVE; omap3_power_states[1].flags = CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_SHALLOW; omap3_power_states[2].valid = 1; omap3_power_states[2].type = OMAP3_STATE_C2; omap3_power_states[2].sleep_latency = 50; omap3_power_states[2].wakeup_latency = 50; omap3_power_states[2].threshold = 300; omap3_power_states[2].mpu_state = PRCM_MPU_CSWR_L2RET; omap3_power_states[2].core_state = PRCM_CORE_ACTIVE; omap3_power_states[2].flags = CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_BALANCED; omap3_power_states[3].valid = 1; omap3_power_states[3].type = OMAP3_STATE_C3; omap3_power_states[3].sleep_latency = 1500; omap3_power_states[3].wakeup_latency = 1800; omap3_power_states[3].threshold = 4000; omap3_power_states[3].mpu_state = PRCM_MPU_CSWR_L2RET; omap3_power_states[3].core_state = PRCM_CORE_ACTIVE; omap3_power_states[3].flags = CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_BALANCED; omap3_power_states[4].valid = 1; omap3_power_states[4].type = OMAP3_STATE_C4; omap3_power_states[4].sleep_latency = 2500; omap3_power_states[4].wakeup_latency = 7500; omap3_power_states[4].threshold = 12000; omap3_power_states[4].mpu_state = PRCM_MPU_CSWR_L2RET; omap3_power_states[4].core_state = PRCM_CORE_CSWR_MEMRET; omap3_power_states[4].flags = CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_BALANCED | CPUIDLE_FLAG_CHECK_BM; omap3_power_states[5].valid = 1; omap3_power_states[5].type = OMAP3_STATE_C5; omap3_power_states[5].sleep_latency = 3000; omap3_power_states[5].wakeup_latency = 8500; omap3_power_states[5].threshold = 15000; omap3_power_states[5].mpu_state = PRCM_MPU_CSWR_L2RET; omap3_power_states[5].core_state = PRCM_CORE_CSWR_MEMRET; omap3_power_states[5].flags = CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_BALANCED | CPUIDLE_FLAG_CHECK_BM; omap3_power_states[6].valid = 0; omap3_power_states[6].type = OMAP3_STATE_C6; omap3_power_states[6].sleep_latency = 10000; omap3_power_states[6].wakeup_latency = 30000; omap3_power_states[6].threshold = 300000; omap3_power_states[6].mpu_state = PRCM_MPU_OFF; omap3_power_states[6].core_state = PRCM_CORE_OFF; omap3_power_states[6].flags = CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_DEEP | CPUIDLE_FLAG_CHECK_BM;}struct cpuidle_driver omap3_idle_driver = { .name = "omap3_idle", .init = omap3_idle_init, .redetect = omap3_idle_init, .bm_check = omap3_idle_bm_check, .owner = THIS_MODULE,};/* Sysfs interface to select the system sleep state */static ssize_t omap_pm_sleep_idle_state_show(struct kset *subsys, char *buf){ return sprintf(buf, "%hu\n", cpuidle_deepest_st);}static ssize_t omap_pm_sleep_idle_state_store(struct kset *subsys, const char *buf, size_t n){ unsigned short value; if (sscanf(buf, "%hu", &value) != 1 || (value > (MAX_SUPPORTED_STATES - 1))) { printk(KERN_ERR "idle_sleep_store: Invalid value\n"); return -EINVAL; } cpuidle_deepest_st = value; return n;}static struct subsys_attribute sleep_idle_state = { .attr = { .name = __stringify(cpuidle_deepest_state), .mode = 0644, }, .show = omap_pm_sleep_idle_state_show, .store = omap_pm_sleep_idle_state_store,};static ssize_t omap_pm_off_show(struct kset *subsys, char *buf){ return sprintf(buf, "%hu\n", enable_off);}static ssize_t omap_pm_off_store(struct kset *subsys, const char *buf, size_t n){ unsigned short value; if (sscanf(buf, "%hu", &value) != 1 || ((value != 0) && (value != 1))) { printk(KERN_ERR "off_enable: Invalid value\n"); return -EINVAL; } enable_off = value; return n;}static struct subsys_attribute off_enable = { .attr = { .name = __stringify(enable_mpucoreoff), .mode = 0644, }, .show = omap_pm_off_show, .store = omap_pm_off_store,};static ssize_t omap_pm_domain_show(struct kset *subsys, char *buf){ prcm_printreg(debug_domain); return 0;}static ssize_t omap_pm_domain_store(struct kset *subsys, const char *buf, size_t n){ unsigned short value; if (sscanf(buf, "%hu", &value) != 1 || (value > PRCM_NUM_DOMAINS) || (value == DOM_CORE2) || (value == 12)) { printk(KERN_ERR "dump_domain: Invalid value\n"); return -EINVAL; } debug_domain = value; return n;}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?