static void modem_fatal_fn(struct work_struct *work) { u32 modem_state; u32 panic_smsm_states = SMSM_RESET | SMSM_SYSTEM_DOWNLOAD; u32 reset_smsm_states = SMSM_SYSTEM_REBOOT_USR | SMSM_SYSTEM_PWRDWN_USR; struct modem_data *drv; drv = container_of(work, struct modem_data, fatal_work); pr_err("Watchdog bite received from modem!\n"); modem_state = smsm_get_state(SMSM_MODEM_STATE); pr_err("Modem SMSM state = 0x%x!\n", modem_state); if (modem_state == 0 || modem_state & panic_smsm_states) { subsystem_restart_dev(drv->subsys); enable_irq(drv->irq); } else if (modem_state & reset_smsm_states) { pr_err("User-invoked system reset/powerdown."); kernel_restart(NULL); } else { unsigned long timeout = msecs_to_jiffies(6000); pr_err("Modem AHB locked up. Trying to free up modem!\n"); writel_relaxed(0x3, drv->cbase + MSS_MODEM_RESET); /* * If we are still alive (allowing for the 5 second * delayed-panic-reboot), the modem is either still wedged or * SMSM didn't come through. Force panic in that case. */ schedule_delayed_work(&drv->unlock_work, timeout); } }
/* * Poll the shared memory states as indicated by the poll groups. * * nr_grps: number of groups in the array * grps: array of groups * * The function returns when conditions specified by any of the poll * groups become true. The conditions specified by a poll group are * deemed true when 1) at least one bit from bits_any_set is set OR one * bit from bits_any_clear is cleared; and 2) all bits in bits_all_set * are set; and 3) all bits in bits_all_clear are cleared. * * Return value: * >=0: index of the poll group whose conditions have become true * -ETIMEDOUT: timed out */ static int msm_pm_poll_state(int nr_grps, struct msm_pm_polled_group *grps) { int i, k; KDEBUG_FUNC(); for (i = 0; i < 500000; i++) for (k = 0; k < nr_grps; k++) { bool all_set, all_clear; bool any_set, any_clear; grps[k].value_read = smsm_get_state(grps[k].group_id); all_set = msm_pm_all_set(grps[k].value_read, grps[k].bits_all_set); all_clear = msm_pm_all_clear(grps[k].value_read, grps[k].bits_all_clear); any_set = msm_pm_any_set(grps[k].value_read, grps[k].bits_any_set); any_clear = msm_pm_any_clear(grps[k].value_read, grps[k].bits_any_clear); if (all_set && all_clear && (any_set || any_clear)) return k; } printk(KERN_ERR "%s failed:\n", __func__); for (k = 0; k < nr_grps; k++) printk(KERN_ERR "(%x, %x, %x, %x) %x\n", grps[k].bits_all_set, grps[k].bits_all_clear, grps[k].bits_any_set, grps[k].bits_any_clear, grps[k].value_read); return -ETIMEDOUT; }
static int modem_shutdown(const struct subsys_desc *subsys) { struct modem_data *drv; drv = container_of(subsys, struct modem_data, subsys_desc); /* * If the modem didn't already crash, setting SMSM_RESET here will help * flush caches etc. The ignore_smsm_ack flag is set to ignore the * SMSM_RESET notification that is generated due to the modem settings * its own SMSM_RESET bit in response to the apps setting the apps * SMSM_RESET bit. */ if (!(smsm_get_state(SMSM_MODEM_STATE) & SMSM_RESET)) { drv->ignore_smsm_ack = 1; smsm_reset_modem(SMSM_RESET); } /* Disable the modem watchdog to allow clean modem bootup */ writel_relaxed(0x0, drv->wdog + 0x8); /* * The write above needs to go through before the modem is powered up * again. */ mb(); /* Wait here to allow the modem to clean up caches, etc. */ msleep(20); pil_shutdown(&drv->pil_desc); disable_irq_nosync(drv->irq); return 0; }
static void modem_sw_fatal_fn(struct work_struct *work) { uint32_t panic_smsm_states = SMSM_RESET | SMSM_SYSTEM_DOWNLOAD; uint32_t reset_smsm_states = SMSM_SYSTEM_REBOOT_USR | SMSM_SYSTEM_PWRDWN_USR; uint32_t modem_state; pr_err("Watchdog bite received from modem SW!\n"); modem_state = smsm_get_state(SMSM_MODEM_STATE); if (modem_state & panic_smsm_states) { pr_err("Modem SMSM state changed to SMSM_RESET.\n" "Probable err_fatal on the modem. " "Calling subsystem restart...\n"); subsystem_restart("modem"); } else if (modem_state & reset_smsm_states) { pr_err("%s: User-invoked system reset/powerdown. " "Resetting the SoC now.\n", __func__); kernel_restart(NULL); } else { /* TODO: Bus unlock code/sequence goes _here_ */ subsystem_restart("modem"); } }
/* * Restore interrupt subsystem from sleep -- phase 3. * Print debug information. */ void msm_irq_exit_sleep3(uint32_t irq_mask, uint32_t wakeup_reason, uint32_t pending_irqs) { if (msm_irq_debug_mask & IRQ_DEBUG_SLEEP) DPRINT_REGS(VIC_IRQ_STATUS, "%s %x %x %x state %x now", __func__, irq_mask, pending_irqs, wakeup_reason, smsm_get_state(SMSM_MODEM_STATE)); }
static uint32_t is_modem_smsm_inited(void) { uint32_t modem_state; uint32_t ready_state = (SMSM_INIT | SMSM_SMDINIT); modem_state = smsm_get_state(SMSM_MODEM_STATE); return (modem_state & ready_state) == ready_state; }
/* * Restore interrupt subsystem from sleep -- phase 3 * Print debug information */ void msm_gic_irq_exit_sleep3(uint32_t irq_mask, uint32_t wakeup_reason, uint32_t pending_irqs) { if (msm_gic_irq_debug_mask & IRQ_DEBUG_SLEEP) pr_info("%s, irq_mask %x pending_irqs %x, wakeup_reason %x," "state %x now\n", __func__, irq_mask, pending_irqs, wakeup_reason, smsm_get_state(SMSM_MODEM_STATE)); }
/* * Restore interrupt subsystem from sleep -- phase 3. * Print debug information. */ void msm_irq_exit_sleep3(uint32_t irq_mask, uint32_t wakeup_reason, uint32_t pending_irqs) { if (msm_irq_debug_mask & IRQ_DEBUG_SLEEP) printk(KERN_INFO "%s %x %x %x now %x %x state %x\n", __func__, irq_mask, pending_irqs, wakeup_reason, readl(VIC_IRQ_STATUS0), readl(VIC_IRQ_STATUS1), smsm_get_state(SMSM_MODEM_STATE)); }
static int msm_pm_modem_busy(void) { if (!(smsm_get_state(SMSM_POWER_MASTER_DEM) & DEM_MASTER_SMSM_READY)) { MSM_PM_DPRINTK(MSM_PM_DEBUG_POWER_COLLAPSE, KERN_INFO, "%s(): master not ready\n", __func__); return -EBUSY; } return 0; }
static void modem_crash_shutdown(const struct subsys_desc *subsys) { struct modem_data *drv; /* If modem hasn't already crashed, send SMSM_RESET. */ drv = container_of(subsys, struct modem_data, subsys_desc); if (!(smsm_get_state(SMSM_MODEM_STATE) & SMSM_RESET)) { modem_unregister_notifier(&drv->notifier); smsm_reset_modem(SMSM_RESET); } /* Wait to allow the modem to clean up caches etc. */ mdelay(5); }
static void modem_crash_shutdown(const struct subsys_desc *subsys) { struct modem_data *drv; drv = container_of(subsys, struct modem_data, subsys_desc); if (!(smsm_get_state(SMSM_MODEM_STATE) & SMSM_RESET)) { modem_unregister_notifier(&drv->notifier); smsm_reset_modem(SMSM_RESET); } mdelay(5); }
void msm_irq_exit_sleep3(void) { if (!smsm_int_info) { printk(KERN_ERR "msm_irq_exit_sleep <SM NO INT_INFO>\n"); return; } if (msm_irq_debug_mask & IRQ_DEBUG_SLEEP) printk(KERN_INFO "msm_irq_exit_sleep3 %x %x %x now %x %x " "state %x\n", smsm_int_info->interrupt_mask, smsm_int_info->pending_interrupts, smsm_int_info->wakeup_reason, readl(VIC_IRQ_STATUS0), readl(VIC_IRQ_STATUS1), smsm_get_state(SMSM_STATE_MODEM)); }
static int modem_shutdown(const struct subsys_data *subsys) { void __iomem *q6_fw_wdog_addr; void __iomem *q6_sw_wdog_addr; int smsm_notif_unregistered = 0; if (!(smsm_get_state(SMSM_MODEM_STATE) & SMSM_RESET)) { smsm_state_cb_deregister(SMSM_MODEM_STATE, SMSM_RESET, smsm_state_cb, 0); smsm_notif_unregistered = 1; smsm_reset_modem(SMSM_RESET); } /* * Cancel any pending wdog_check work items, since we're shutting * down anyway. */ cancel_delayed_work(&modem_wdog_check_work); /* * Disable the modem watchdog since it keeps running even after the * modem is shutdown. */ q6_fw_wdog_addr = ioremap_nocache(Q6_FW_WDOG_ENABLE, 4); if (!q6_fw_wdog_addr) return -ENOMEM; q6_sw_wdog_addr = ioremap_nocache(Q6_SW_WDOG_ENABLE, 4); if (!q6_sw_wdog_addr) { iounmap(q6_fw_wdog_addr); return -ENOMEM; } writel_relaxed(0x0, q6_fw_wdog_addr); writel_relaxed(0x0, q6_sw_wdog_addr); mb(); iounmap(q6_sw_wdog_addr); iounmap(q6_fw_wdog_addr); pil_force_shutdown("modem"); pil_force_shutdown("modem_fw"); disable_irq_nosync(Q6FW_WDOG_EXPIRED_IRQ); disable_irq_nosync(Q6SW_WDOG_EXPIRED_IRQ); if (smsm_notif_unregistered) smsm_state_cb_register(SMSM_MODEM_STATE, SMSM_RESET, smsm_state_cb, 0); return 0; }
void msm_irq_exit_sleep3(void) { if (!smsm_int_info) { printk(KERN_ERR "msm_irq_exit_sleep <SM NO INT_INFO>\n"); return; } if (msm_irq_debug_mask & IRQ_DEBUG_SLEEP) { printk(KERN_INFO "%s %x %x %x state %x now", __func__, smsm_int_info->interrupt_mask, smsm_int_info->pending_interrupts, smsm_int_info->wakeup_reason, smsm_get_state(SMSM_STATE_MODEM)); print_vic_irq_stat(); } }
static void modem_fatal_fn(struct work_struct *work) { uint32_t modem_state; uint32_t panic_smsm_states = SMSM_RESET | SMSM_SYSTEM_DOWNLOAD; uint32_t reset_smsm_states = SMSM_SYSTEM_REBOOT_USR | SMSM_SYSTEM_PWRDWN_USR; pr_err("%s: Watchdog bite received from modem!\n", MODULE_NAME); modem_state = smsm_get_state(SMSM_MODEM_STATE); pr_err("%s: Modem SMSM state = 0x%x!", MODULE_NAME, modem_state); if (modem_state == 0 || modem_state & panic_smsm_states) { subsystem_restart("modem"); enable_irq(MARM_WDOG_EXPIRED); } else if (modem_state & reset_smsm_states) { pr_err("%s: User-invoked system reset/powerdown.", MODULE_NAME); soc_restart(RESTART_MODE_MODEM_WATCHDOG_BITE, "MODEM DOG!"); } else { int ret; void *hwio_modem_reset_addr = ioremap_nocache(MODEM_HWIO_MSS_RESET_ADDR, 8); pr_err("%s: Modem AHB locked up.\n", MODULE_NAME); pr_err("%s: Trying to free up modem!\n", MODULE_NAME); /* We don't want it happens */ BUG_ON(!hwio_modem_reset_addr); writel(0x3, hwio_modem_reset_addr); /* If we are still alive after 6 seconds (allowing for * the 5-second-delayed-panic-reboot), modem is either * still wedged or SMSM didn't come through. Force panic * in that case. */ ret = schedule_delayed_work(&modem_unlock_timeout_work, msecs_to_jiffies(6000)); iounmap(hwio_modem_reset_addr); } }
/** * Fatal error handler * Resets DSPS. */ static void dsps_fatal_handler(struct work_struct *work) { uint32_t dsps_state; dsps_state = smsm_get_state(SMSM_DSPS_STATE); pr_debug("%s: DSPS state 0x%x\n", __func__, dsps_state); if (dsps_state & SMSM_RESET) { pr_err("%s: DSPS fatal error detected. Resetting\n", __func__); panic(MODULE_NAME "DSPS fatal error detected."); } else { pr_debug("%s: User-initiated DSPS reset. Resetting\n", __func__); panic(MODULE_NAME "User-initiated DSPS reset."); } }
static int msm_pm_wait_state(uint32_t wait_all_set, uint32_t wait_all_clear, uint32_t wait_any_set, uint32_t wait_any_clear) { int i; uint32_t state; for (i = 0; i < 100000; i++) { state = smsm_get_state(PM_SMSM_READ_STATE); if (((wait_all_set || wait_all_clear) && !(~state & wait_all_set) && !(state & wait_all_clear)) || (state & wait_any_set) || (~state & wait_any_clear)) return 0; udelay(1); } pr_err("msm_pm_wait_state(%x, %x, %x, %x) failed %x\n", wait_all_set, wait_all_clear, wait_any_set, wait_any_clear, state); return -ETIMEDOUT; }
static void modem_fatal_fn(struct work_struct *work) { uint32_t modem_state; uint32_t panic_smsm_states = SMSM_RESET | SMSM_SYSTEM_DOWNLOAD; uint32_t reset_smsm_states = SMSM_SYSTEM_REBOOT_USR | SMSM_SYSTEM_PWRDWN_USR; pr_err("%s: Watchdog bite received from modem!\n", MODULE_NAME); modem_state = smsm_get_state(SMSM_MODEM_STATE); pr_err("%s: Modem SMSM state = 0x%x!", MODULE_NAME, modem_state); if (modem_state == 0 || modem_state & panic_smsm_states) { subsystem_restart("modem"); } else if (modem_state & reset_smsm_states) { pr_err("%s: User-invoked system reset/powerdown.", MODULE_NAME); do_soc_restart(); } else { int ret; pr_err("%s: Modem AHB locked up.\n", MODULE_NAME); pr_err("%s: Trying to free up modem!\n", MODULE_NAME); if ( hwio_modem_reset_addr ) writel(0x3, hwio_modem_reset_addr); /* If we are still alive after 6 seconds (allowing for * the 5-second-delayed-panic-reboot), modem is either * still wedged or SMSM didn't come through. Force panic * in that case. */ ret = schedule_delayed_work(&modem_unlock_timeout_work, msecs_to_jiffies(6000)); iounmap(hwio_modem_reset_addr); } }
static int modem_shutdown(const struct subsys_desc *subsys) { struct modem_data *drv; drv = container_of(subsys, struct modem_data, subsys_desc); if (!(smsm_get_state(SMSM_MODEM_STATE) & SMSM_RESET)) { drv->ignore_smsm_ack = 1; smsm_reset_modem(SMSM_RESET); } writel_relaxed(0x0, drv->wdog + 0x8); mb(); msleep(20); pil_shutdown(&drv->pil_desc); disable_irq_nosync(drv->irq); return 0; }
/** * Fatal error handler * Resets DSPS. */ static void dsps_restart_handler(struct work_struct *work) { uint32_t dsps_state; int restart_level; char *smem_reset_reason; unsigned smem_reset_size; const char dflt_reason[] = "Died too early due to unknown reason"; dsps_state = smsm_get_state(SMSM_DSPS_STATE); restart_level = get_restart_level(); pr_debug("%s: DSPS state 0x%x. Restart lvl %d\n", __func__, dsps_state, restart_level); if ((dsps_state & SMSM_RESET) || (atomic_read(&drv->wd_crash) == 1)) { smem_reset_reason = smem_get_entry(SMEM_SSR_REASON_DSPS0, &smem_reset_size); if (smem_reset_reason != NULL && smem_reset_reason[0] != 0) { smem_reset_reason[smem_reset_size-1] = 0; pr_err("%s: DSPS failure: %s\nResetting DSPS\n", __func__, smem_reset_reason); memset(smem_reset_reason, 0, smem_reset_size); wmb(); } else pr_err("%s: DSPS failure: %s\nResetting DSPS\n", __func__, dflt_reason); } else pr_err("%s: User-initiated DSPS reset.\nResetting DSPS\n", __func__); if (atomic_add_return(1, &drv->crash_in_progress) > 1) { pr_err("%s: DSPS already resetting. Count %d\n", __func__, atomic_read(&drv->crash_in_progress)); } else { subsystem_restart("dsps"); } }
static void modem_sw_fatal_fn(struct work_struct *work) { uint32_t panic_smsm_states = SMSM_RESET | SMSM_SYSTEM_DOWNLOAD; uint32_t reset_smsm_states = SMSM_SYSTEM_REBOOT_USR | SMSM_SYSTEM_PWRDWN_USR; uint32_t modem_state; pr_err("Watchdog bite received from modem SW!\n"); modem_state = smsm_get_state(SMSM_MODEM_STATE); if (modem_state & panic_smsm_states) { pr_err("Modem SMSM state changed to SMSM_RESET.\n" "Probable err_fatal on the modem. " "Calling subsystem restart...\n"); #ifdef FEATURE_PANTECH_WLAN_QCOM_PATCH //lee.eunsuk 20120423, SSR panic(MODULE_NAME "Modem crashed."); #else subsystem_restart("modem"); #endif } else if (modem_state & reset_smsm_states) { pr_err("%s: User-invoked system reset/powerdown. " "Resetting the SoC now.\n", __func__); kernel_restart(NULL); } else { /* TODO: Bus unlock code/sequence goes _here_ */ #ifdef FEATURE_PANTECH_WLAN_QCOM_PATCH //lee.eunsuk 20120423, SSR panic(MODULE_NAME "Modem crashed."); #else subsystem_restart("modem"); #endif } }
/* * Power collapse the Apps processor. This function executes the handshake * protocol with Modem. * * Return value: * -EAGAIN: modem reset occurred or early exit from power collapse * -EBUSY: modem not ready for our power collapse -- no power loss * -ETIMEDOUT: timed out waiting for modem's handshake -- no power loss * 0: success */ static int msm_pm_power_collapse (bool from_idle, uint32_t sleep_delay, uint32_t sleep_limit) { struct msm_pm_polled_group state_grps[2]; unsigned long saved_acpuclk_rate; int collapsed = 0; int ret; int val; int modem_early_exit = 0; MSM_PM_DPRINTK(MSM_PM_DEBUG_SUSPEND|MSM_PM_DEBUG_POWER_COLLAPSE, KERN_INFO, "%s(): idle %d, delay %u, limit %u\n", __func__, (int)from_idle, sleep_delay, sleep_limit); if (!(smsm_get_state(SMSM_POWER_MASTER_DEM) & DEM_MASTER_SMSM_READY)) { MSM_PM_DPRINTK( MSM_PM_DEBUG_SUSPEND | MSM_PM_DEBUG_POWER_COLLAPSE, KERN_INFO, "%s(): master not ready\n", __func__); ret = -EBUSY; goto power_collapse_bail; } memset(msm_pm_smem_data, 0, sizeof(*msm_pm_smem_data)); if (cpu_is_msm8625()) { /* Program the SPM */ ret = msm_spm_set_low_power_mode(MSM_SPM_MODE_POWER_COLLAPSE, false); WARN_ON(ret); } /* Call CPR suspend only for "idlePC" case */ if (msm_cpr_ops && from_idle) msm_cpr_ops->cpr_suspend(); msm_pm_irq_extns->enter_sleep1(true, from_idle, &msm_pm_smem_data->irq_mask); msm_sirc_enter_sleep(); msm_gpio_enter_sleep(from_idle); msm_pm_smem_data->sleep_time = sleep_delay; msm_pm_smem_data->resources_used = sleep_limit; /* Enter PWRC/PWRC_SUSPEND */ if (from_idle) smsm_change_state(SMSM_APPS_DEM, DEM_SLAVE_SMSM_RUN, DEM_SLAVE_SMSM_PWRC); else smsm_change_state(SMSM_APPS_DEM, DEM_SLAVE_SMSM_RUN, DEM_SLAVE_SMSM_PWRC | DEM_SLAVE_SMSM_PWRC_SUSPEND); MSM_PM_DEBUG_PRINT_STATE("msm_pm_power_collapse(): PWRC"); MSM_PM_DEBUG_PRINT_SLEEP_INFO(); memset(state_grps, 0, sizeof(state_grps)); state_grps[0].group_id = SMSM_POWER_MASTER_DEM; state_grps[0].bits_all_set = DEM_MASTER_SMSM_RSA; state_grps[1].group_id = SMSM_MODEM_STATE; state_grps[1].bits_all_set = SMSM_RESET; ret = msm_pm_poll_state(ARRAY_SIZE(state_grps), state_grps); if (ret < 0) { printk(KERN_EMERG "%s(): power collapse entry " "timed out waiting for Modem's response\n", __func__); msm_pm_timeout(); } if (ret == 1) { MSM_PM_DPRINTK( MSM_PM_DEBUG_SUSPEND|MSM_PM_DEBUG_POWER_COLLAPSE, KERN_INFO, "%s(): msm_pm_poll_state detected Modem reset\n", __func__); goto power_collapse_early_exit; } /* DEM Master in RSA */ MSM_PM_DEBUG_PRINT_STATE("msm_pm_power_collapse(): PWRC RSA"); ret = msm_pm_irq_extns->enter_sleep2(true, from_idle); if (ret < 0) { MSM_PM_DPRINTK( MSM_PM_DEBUG_SUSPEND|MSM_PM_DEBUG_POWER_COLLAPSE, KERN_INFO, "%s(): msm_irq_enter_sleep2 aborted, %d\n", __func__, ret); goto power_collapse_early_exit; } msm_pm_config_hw_before_power_down(); MSM_PM_DEBUG_PRINT_STATE("msm_pm_power_collapse(): pre power down"); saved_acpuclk_rate = acpuclk_power_collapse(); MSM_PM_DPRINTK(MSM_PM_DEBUG_CLOCK, KERN_INFO, "%s(): change clock rate (old rate = %lu)\n", __func__, saved_acpuclk_rate); if (saved_acpuclk_rate == 0) { msm_pm_config_hw_after_power_up(); goto power_collapse_early_exit; } msm_pm_boot_config_before_pc(smp_processor_id(), virt_to_phys(msm_pm_collapse_exit)); #ifdef CONFIG_VFP if (from_idle) vfp_pm_suspend(); #endif #ifdef CONFIG_CACHE_L2X0 if (!cpu_is_msm8625()) l2cc_suspend(); else apps_power_collapse = 1; #endif collapsed = msm_pm_collapse(); /* * TBD: Currently recognise the MODEM early exit * path by reading the MPA5_GDFS_CNT_VAL register. */ if (cpu_is_msm8625()) { /* * on system reset, default value of MPA5_GDFS_CNT_VAL * is = 0x0, later modem reprogram this value to * 0x00030004. Once APPS did a power collapse and * coming out of it expected value of this register * always be 0x00030004. Incase if APPS sees the value * as 0x00030002 consider this case as a modem early * exit. */ val = __raw_readl(MSM_CFG_CTL_BASE + 0x38); if (val != 0x00030002) power_collapsed = 1; else modem_early_exit = 1; } #ifdef CONFIG_CACHE_L2X0 if (!cpu_is_msm8625()) l2cc_resume(); else apps_power_collapse = 0; #endif msm_pm_boot_config_after_pc(smp_processor_id()); if (collapsed) { #ifdef CONFIG_VFP if (from_idle) vfp_pm_resume(); #endif cpu_init(); local_fiq_enable(); } MSM_PM_DPRINTK(MSM_PM_DEBUG_SUSPEND | MSM_PM_DEBUG_POWER_COLLAPSE, KERN_INFO, "%s(): msm_pm_collapse returned %d\n", __func__, collapsed); MSM_PM_DPRINTK(MSM_PM_DEBUG_CLOCK, KERN_INFO, "%s(): restore clock rate to %lu\n", __func__, saved_acpuclk_rate); if (acpuclk_set_rate(smp_processor_id(), saved_acpuclk_rate, SETRATE_PC) < 0) printk(KERN_ERR "%s(): failed to restore clock rate(%lu)\n", __func__, saved_acpuclk_rate); msm_pm_irq_extns->exit_sleep1(msm_pm_smem_data->irq_mask, msm_pm_smem_data->wakeup_reason, msm_pm_smem_data->pending_irqs); msm_pm_config_hw_after_power_up(); MSM_PM_DEBUG_PRINT_STATE("msm_pm_power_collapse(): post power up"); memset(state_grps, 0, sizeof(state_grps)); state_grps[0].group_id = SMSM_POWER_MASTER_DEM; state_grps[0].bits_any_set = DEM_MASTER_SMSM_RSA | DEM_MASTER_SMSM_PWRC_EARLY_EXIT; state_grps[1].group_id = SMSM_MODEM_STATE; state_grps[1].bits_all_set = SMSM_RESET; ret = msm_pm_poll_state(ARRAY_SIZE(state_grps), state_grps); if (ret < 0) { printk(KERN_EMERG "%s(): power collapse exit " "timed out waiting for Modem's response\n", __func__); msm_pm_timeout(); } if (ret == 1) { MSM_PM_DPRINTK( MSM_PM_DEBUG_SUSPEND|MSM_PM_DEBUG_POWER_COLLAPSE, KERN_INFO, "%s(): msm_pm_poll_state detected Modem reset\n", __func__); goto power_collapse_early_exit; } /* Sanity check */ if (collapsed && !modem_early_exit) { BUG_ON(!(state_grps[0].value_read & DEM_MASTER_SMSM_RSA)); } else { BUG_ON(!(state_grps[0].value_read & DEM_MASTER_SMSM_PWRC_EARLY_EXIT)); goto power_collapse_early_exit; } /* Enter WFPI */ smsm_change_state(SMSM_APPS_DEM, DEM_SLAVE_SMSM_PWRC | DEM_SLAVE_SMSM_PWRC_SUSPEND, DEM_SLAVE_SMSM_WFPI); MSM_PM_DEBUG_PRINT_STATE("msm_pm_power_collapse(): WFPI"); memset(state_grps, 0, sizeof(state_grps)); state_grps[0].group_id = SMSM_POWER_MASTER_DEM; state_grps[0].bits_all_set = DEM_MASTER_SMSM_RUN; state_grps[1].group_id = SMSM_MODEM_STATE; state_grps[1].bits_all_set = SMSM_RESET; ret = msm_pm_poll_state(ARRAY_SIZE(state_grps), state_grps); if (ret < 0) { printk(KERN_EMERG "%s(): power collapse WFPI " "timed out waiting for Modem's response\n", __func__); msm_pm_timeout(); } if (ret == 1) { MSM_PM_DPRINTK( MSM_PM_DEBUG_SUSPEND|MSM_PM_DEBUG_POWER_COLLAPSE, KERN_INFO, "%s(): msm_pm_poll_state detected Modem reset\n", __func__); ret = -EAGAIN; goto power_collapse_restore_gpio_bail; } /* DEM Master == RUN */ MSM_PM_DEBUG_PRINT_STATE("msm_pm_power_collapse(): WFPI RUN"); MSM_PM_DEBUG_PRINT_SLEEP_INFO(); msm_pm_irq_extns->exit_sleep2(msm_pm_smem_data->irq_mask, msm_pm_smem_data->wakeup_reason, msm_pm_smem_data->pending_irqs); msm_pm_irq_extns->exit_sleep3(msm_pm_smem_data->irq_mask, msm_pm_smem_data->wakeup_reason, msm_pm_smem_data->pending_irqs); msm_gpio_exit_sleep(); msm_sirc_exit_sleep(); smsm_change_state(SMSM_APPS_DEM, DEM_SLAVE_SMSM_WFPI, DEM_SLAVE_SMSM_RUN); MSM_PM_DEBUG_PRINT_STATE("msm_pm_power_collapse(): RUN"); smd_sleep_exit(); if (cpu_is_msm8625()) { ret = msm_spm_set_low_power_mode(MSM_SPM_MODE_CLOCK_GATING, false); WARN_ON(ret); } /* Call CPR resume only for "idlePC" case */ if (msm_cpr_ops && from_idle) msm_cpr_ops->cpr_resume(); return 0; power_collapse_early_exit: /* Enter PWRC_EARLY_EXIT */ smsm_change_state(SMSM_APPS_DEM, DEM_SLAVE_SMSM_PWRC | DEM_SLAVE_SMSM_PWRC_SUSPEND, DEM_SLAVE_SMSM_PWRC_EARLY_EXIT); MSM_PM_DEBUG_PRINT_STATE("msm_pm_power_collapse(): EARLY_EXIT"); memset(state_grps, 0, sizeof(state_grps)); state_grps[0].group_id = SMSM_POWER_MASTER_DEM; state_grps[0].bits_all_set = DEM_MASTER_SMSM_PWRC_EARLY_EXIT; state_grps[1].group_id = SMSM_MODEM_STATE; state_grps[1].bits_all_set = SMSM_RESET; ret = msm_pm_poll_state(ARRAY_SIZE(state_grps), state_grps); MSM_PM_DEBUG_PRINT_STATE("msm_pm_power_collapse(): EARLY_EXIT EE"); if (ret < 0) { printk(KERN_EMERG "%s(): power collapse EARLY_EXIT " "timed out waiting for Modem's response\n", __func__); msm_pm_timeout(); } if (ret == 1) { MSM_PM_DPRINTK( MSM_PM_DEBUG_SUSPEND|MSM_PM_DEBUG_POWER_COLLAPSE, KERN_INFO, "%s(): msm_pm_poll_state detected Modem reset\n", __func__); } /* DEM Master == RESET or PWRC_EARLY_EXIT */ ret = -EAGAIN; power_collapse_restore_gpio_bail: msm_gpio_exit_sleep(); msm_sirc_exit_sleep(); /* Enter RUN */ smsm_change_state(SMSM_APPS_DEM, DEM_SLAVE_SMSM_PWRC | DEM_SLAVE_SMSM_PWRC_SUSPEND | DEM_SLAVE_SMSM_PWRC_EARLY_EXIT, DEM_SLAVE_SMSM_RUN); MSM_PM_DEBUG_PRINT_STATE("msm_pm_power_collapse(): RUN"); if (collapsed) smd_sleep_exit(); /* Call CPR resume only for "idlePC" case */ if (msm_cpr_ops && from_idle) msm_cpr_ops->cpr_resume(); power_collapse_bail: if (cpu_is_msm8625()) { ret = msm_spm_set_low_power_mode(MSM_SPM_MODE_CLOCK_GATING, false); WARN_ON(ret); } return ret; }
/* Time Slave State Bits */ #define SLAVE_TIME_REQUEST 0x0400 #define SLAVE_TIME_POLL 0x0800 #define SLAVE_TIME_INIT 0x1000 uint32_t *smem_clock; uint32_t smem_clock_val; uint32_t state; smem_clock = smem_alloc(SMEM_SMEM_SLOW_CLOCK_VALUE, sizeof(uint32_t)); if (smem_clock == NULL) { printk(KERN_ERR "no smem clock\n"); return 0; } state = smsm_get_state(SMSM_MODEM_STATE); if ((state & SMSM_INIT) == 0) { printk(KERN_ERR "smsm not initialized\n"); return 0; } time_start(data); while ((state = smsm_get_state(SMSM_TIME_MASTER_DEM)) & MASTER_TIME_PENDING) { if (time_expired(data)) { printk(KERN_INFO "get_smem_clock: timeout 1 still " "invalid state %x\n", state); return 0; } } smsm_change_state(SMSM_APPS_DEM, SLAVE_TIME_POLL | SLAVE_TIME_INIT, SLAVE_TIME_REQUEST); time_start(data); while (!((state = smsm_get_state(SMSM_TIME_MASTER_DEM)) & MASTER_TIME_PENDING)) { if (time_expired(data)) { printk(KERN_INFO "get_smem_clock: timeout 2 still " "invalid state %x\n", state); smem_clock_val = 0; goto sync_sclk_exit; } } smsm_change_state(SMSM_APPS_DEM, SLAVE_TIME_REQUEST, SLAVE_TIME_POLL); time_start(data); do { smem_clock_val = *smem_clock; } while (smem_clock_val == 0 && !time_expired(data)); state = smsm_get_state(SMSM_TIME_MASTER_DEM); if (smem_clock_val) { if (update != NULL) update(data, smem_clock_val); if (msm_timer_debug_mask & MSM_TIMER_DEBUG_SYNC) printk(KERN_INFO "get_smem_clock: state %x clock %u\n", state, smem_clock_val); } else { printk(KERN_INFO "get_smem_clock: timeout state %x clock %u\n", state, smem_clock_val); } sync_sclk_exit: smsm_change_state(SMSM_APPS_DEM, SLAVE_TIME_REQUEST | SLAVE_TIME_POLL, SLAVE_TIME_INIT); return smem_clock_val; } #else /* CONFIG_MSM_N_WAY_SMSM */ static uint32_t msm_timer_sync_sclk( void (*time_start)(struct msm_timer_sync_data_t *data), bool (*time_expired)(struct msm_timer_sync_data_t *data), void (*update)(struct msm_timer_sync_data_t *data, uint32_t clk_val), struct msm_timer_sync_data_t *data) { uint32_t *smem_clock; uint32_t smem_clock_val; uint32_t last_state; uint32_t state; smem_clock = smem_alloc(SMEM_SMEM_SLOW_CLOCK_VALUE, sizeof(uint32_t)); if (smem_clock == NULL) { printk(KERN_ERR "no smem clock\n"); return 0; } last_state = state = smsm_get_state(SMSM_MODEM_STATE); smem_clock_val = *smem_clock; if (smem_clock_val) { printk(KERN_INFO "get_smem_clock: invalid start state %x " "clock %u\n", state, smem_clock_val); smsm_change_state(SMSM_APPS_STATE, SMSM_TIMEWAIT, SMSM_TIMEINIT); time_start(data); while (*smem_clock != 0 && !time_expired(data)) ; smem_clock_val = *smem_clock; if (smem_clock_val) { printk(KERN_INFO "get_smem_clock: timeout still " "invalid state %x clock %u\n", state, smem_clock_val); return 0; } } time_start(data); smsm_change_state(SMSM_APPS_STATE, SMSM_TIMEINIT, SMSM_TIMEWAIT); do { smem_clock_val = *smem_clock; state = smsm_get_state(SMSM_MODEM_STATE); if (state != last_state) { last_state = state; if (msm_timer_debug_mask & MSM_TIMER_DEBUG_SYNC) printk(KERN_INFO "get_smem_clock: state %x clock %u\n", state, smem_clock_val); } } while (smem_clock_val == 0 && !time_expired(data)); if (smem_clock_val) { if (update != NULL) update(data, smem_clock_val); } else { printk(KERN_INFO "get_smem_clock: timeout state %x clock %u\n", state, smem_clock_val); } smsm_change_state(SMSM_APPS_STATE, SMSM_TIMEWAIT, SMSM_TIMEINIT); time_start(data); while (*smem_clock != 0 && !time_expired(data)) ; if (*smem_clock) printk(KERN_INFO "get_smem_clock: exit timeout state %x " "clock %u\n", state, *smem_clock); return smem_clock_val; }
static int check_modem_smsm_stat(void) { return (smsm_get_state(SMSM_MODEM_STATE) & SMSM_SYSTEM_PWRDWN_USR); }
static uint32_t msm_timer_sync_sclk( void (*time_start)(struct msm_timer_sync_data_t *data), bool (*time_expired)(struct msm_timer_sync_data_t *data), void (*update)(struct msm_timer_sync_data_t *data, uint32_t clk_val), struct msm_timer_sync_data_t *data) { /* Time Master State Bits */ #define MASTER_BITS_PER_CPU 1 #define MASTER_TIME_PENDING \ (0x01UL << (MASTER_BITS_PER_CPU * SMSM_APPS_STATE)) /* Time Slave State Bits */ #define SLAVE_TIME_REQUEST 0x0400 #define SLAVE_TIME_POLL 0x0800 #define SLAVE_TIME_INIT 0x1000 uint32_t *smem_clock; uint32_t smem_clock_val; uint32_t state; smem_clock = smem_alloc(SMEM_SMEM_SLOW_CLOCK_VALUE, sizeof(uint32_t)); if (smem_clock == NULL) { printk(KERN_ERR "no smem clock\n"); return 0; } state = smsm_get_state(SMSM_MODEM_STATE); if ((state & SMSM_INIT) == 0) { printk(KERN_ERR "smsm not initialized\n"); return 0; } time_start(data); while ((state = smsm_get_state(SMSM_TIME_MASTER_DEM)) & MASTER_TIME_PENDING) { if (time_expired(data)) { printk(KERN_INFO "get_smem_clock: timeout 1 still " "invalid state %x\n", state); return 0; } } smsm_change_state(SMSM_APPS_DEM, SLAVE_TIME_POLL | SLAVE_TIME_INIT, SLAVE_TIME_REQUEST); time_start(data); while (!((state = smsm_get_state(SMSM_TIME_MASTER_DEM)) & MASTER_TIME_PENDING)) { if (time_expired(data)) { printk(KERN_INFO "get_smem_clock: timeout 2 still " "invalid state %x\n", state); smem_clock_val = 0; goto sync_sclk_exit; } } smsm_change_state(SMSM_APPS_DEM, SLAVE_TIME_REQUEST, SLAVE_TIME_POLL); time_start(data); do { smem_clock_val = *smem_clock; } while (smem_clock_val == 0 && !time_expired(data)); state = smsm_get_state(SMSM_TIME_MASTER_DEM); if (smem_clock_val) { if (update != NULL) update(data, smem_clock_val); if (msm_timer_debug_mask & MSM_TIMER_DEBUG_SYNC) printk(KERN_INFO "get_smem_clock: state %x clock %u\n", state, smem_clock_val); } else { printk(KERN_INFO "get_smem_clock: timeout state %x clock %u\n", state, smem_clock_val); } sync_sclk_exit: smsm_change_state(SMSM_APPS_DEM, SLAVE_TIME_REQUEST | SLAVE_TIME_POLL, SLAVE_TIME_INIT); return smem_clock_val; }
static void apps_sleep(void) { uint32_t saved_vector[2]; unsigned int sleep_delay; static uint32_t *msm_pm_reset_vector; uint32_t enter_state; uint32_t enter_wait_set = 0; uint32_t enter_wait_clear = 0; uint32_t exit_state; // uint32_t exit_wait_clear = 0; uint32_t exit_wait_any_set = 0; int ret; int collapsed = 0; enter_state = DEM_SLAVE_SMSM_SLEEP; enter_wait_set = DEM_MASTER_SMSM_SLEEP; exit_state = DEM_SLAVE_SMSM_SLEEP_EXIT; exit_wait_any_set = DEM_MASTER_SMSM_SLEEP_EXIT; msm_irq_enter_sleep1(1, 0); msm_gpio_enter_sleep(0); sleep_delay = 192000*5; /* APPS_SLEEP does not allow infinite timeout */ ret = smsm_set_sleep_duration(sleep_delay); printk("smsm_set_sleep_duration result: %d\n", ret); ret = smsm_change_state(PM_SMSM_WRITE_STATE, PM_SMSM_WRITE_RUN, enter_state); printk("smsm_change_state result: %d\n", ret); msm_irq_enter_sleep2(1, 0); // APPS_SLEEP //ret = smsm_change_state(PM_SMSM_WRITE_STATE, PM_SMSM_WRITE_RUN, enter_state); //printk("smsm_change_state result: %d\n", ret); ret = msm_pm_wait_state(enter_wait_set, enter_wait_clear, 0, 0); printk("msm_pm_wait_state result: %d\n", ret); // msm_enter_prep_hw(); writel(1, A11S_PWRDOWN); writel(4, A11S_SECOP); printk("A11S_PWRDOWN: %.8x\n", readl(A11S_PWRDOWN)); printk("A11S_SECOP: %.8x\n", readl(A11S_SECOP)); printk("msm_sleep(): enter " "A11S_CLK_SLEEP_EN %x, A11S_PWRDOWN %x, " "smsm_get_state %x\n", readl(A11S_CLK_SLEEP_EN), readl(A11S_PWRDOWN), smsm_get_state(PM_SMSM_READ_STATE)); magic_num = 0xAAAA1111; writel(magic_num, HTC_POWER_COLLAPSE_MAGIC_NUM); msm_pm_reset_vector = ioremap(0x0, PAGE_SIZE); // smsm_print_sleep_info(0); saved_vector[0] = msm_pm_reset_vector[0]; saved_vector[1] = msm_pm_reset_vector[1]; msm_pm_reset_vector[0] = 0xE51FF004; /* ldr pc, 4 */ msm_pm_reset_vector[1] = virt_to_phys(msm_pm_collapse_exit); printk(KERN_INFO "msm_sleep(): vector %x %x -> " "%x %x\n", saved_vector[0], saved_vector[1], msm_pm_reset_vector[0], msm_pm_reset_vector[1]); collapsed = msm_pm_collapse(); printk("pmmod: collapsed: %d\n", collapsed); };