static int idpram_pre_suspend(struct idpram_link_pm_data *pm_data) { int timeout_ret = 0; int suspend_retry = 2; u16 intr_out = INT_CMD(INT_MASK_CMD_PDA_SLEEP); pm_data->pm_states = IDPRAM_PM_SUSPEND_PREPARE; pm_data->last_pm_mailbox = 0; idpram_write_lock(pm_data, 1); gpio_set_value(pm_data->mdata->gpio_mbx_intr, 1); /* prevent PDA_ACTIVE ststus is low */ gpio_set_value(pm_data->mdata->gpio_pda_active, 1); if (!atomic_read(&pm_data->read_lock)) { do { init_completion(&pm_data->idpram_down); dpram_write_command(pm_data->dpld, intr_out); mif_err("MIF: idpram sent PDA_SLEEP Mailbox(0x%X)\n", intr_out); timeout_ret = wait_for_completion_timeout(&pm_data->idpram_down, (HZ/5)); mif_err("MIF: suspend_enter cnt = %d\n", suspend_retry); } while (!timeout_ret && suspend_retry--); switch (pm_data->last_pm_mailbox) { case INT_CMD(INT_MASK_CMD_DPRAM_DOWN): break; /* if nack or other interrup, hold wakelock for DPM resume*/ case INT_CMD(INT_MASK_CMD_DPRAM_DOWN_NACK): mif_err("MIF: idpram dpram down get NACK\n"); default: mif_err("MIF: CP dpram Down not ready! intr=0x%X\n", dpram_readh(&pm_data->dpld->dpram->mbx_cp2ap)); wake_lock_timeout(&pm_data->hold_wlock, msecs_to_jiffies(500)); idpram_write_lock(pm_data, 0); return 0; } /* * Because, if dpram was powered down, cp dpram random intr was * ocurred. so, fixed by muxing cp dpram intr pin to GPIO output * high,.. */ gpio_set_value(pm_data->mdata->gpio_mbx_intr, 1); s3c_gpio_cfgpin(pm_data->mdata->gpio_mbx_intr, S3C_GPIO_OUTPUT); pm_data->pm_states = IDPRAM_PM_DPRAM_POWER_DOWN; return 0; } else { mif_err("MIF: idpram hold read_lock\n"); return -EBUSY; } }
static void s5p_idpram_try_resume(struct work_struct *work) { struct idpram_pm_data *pm_data; struct dpram_link_device *dpld; struct link_device *ld; unsigned long delay; u16 cmd; mif_info("+++\n"); pm_data = container_of(work, struct idpram_pm_data, resume_dwork.work); dpld = container_of(pm_data, struct dpram_link_device, pm_data); ld = &dpld->ld; if (pm_data->last_msg == INT_CMD(INT_CMD_IDPRAM_RESUME_REQ)) { pm_data->last_msg = 0; s5p_idpram_set_pm_lock(dpld, 0); wake_unlock(&pm_data->hold_wlock); delay = msecs_to_jiffies(10); schedule_delayed_work(&pm_data->tx_dwork, delay); mif_info("%s resumed\n", ld->name); goto exit; } if (pm_data->resume_try_cnt++ < MAX_RESUME_TRY_CNT) { mif_info("%s not resumed yet\n", ld->name); cmd = INT_CMD(INT_CMD_IDPRAM_RESUME_REQ); mif_info("send IDPRAM_RESUME_REQ (0x%X)\n", cmd); dpld->send_intr(dpld, cmd); delay = msecs_to_jiffies(200); schedule_delayed_work(&pm_data->resume_dwork, delay); } else { struct io_device *iod; mif_err("ERR! %s resume T-I-M-E-O-U-T\n", ld->name); iod = link_get_iod_with_format(ld, IPC_FMT); if (iod) iod->modem_state_changed(iod, STATE_CRASH_EXIT); wake_unlock(&pm_data->hold_wlock); /* hold wakelock until uevnet sent to rild */ wake_lock_timeout(&pm_data->hold_wlock, HZ*7); s5p_idpram_set_pm_lock(dpld, 0); } exit: mif_info("---\n"); }
static void idpram_powerup_start(struct idpram_link_pm_data *pm_data) { pr_info("MIF: <%s>\n", __func__); pm_data->last_pm_mailbox = INT_CMD(INT_MASK_CMD_PDA_WAKEUP); pm_data->pm_states = IDPRAM_PM_ACTIVE; }
void dpram_force_cp_crash(struct link_device *ld) { int ret; struct dpram_link_device *dpld = to_dpram_link_device(ld); pr_info("MIF: <%s+>", __func__); /* 1. set the magic number to 0x554C 2. send mbx cmd 0x000F 3. wait for completon 4. CP responds with cmd = 0xCF 5. call panic("CP Crashed"); */ dpram_write_magic_code(dpld, 0x554C); dpram_write_command(dpld, INT_CMD(0x000F)); init_completion(&dpld->cp_crash_done); ret = wait_for_completion_interruptible_timeout( &dpld->cp_crash_done, 20 * HZ); if (!ret) { pr_err("MIF: CP didn't ack MBX_CMD_PHONE_RESET\n"); dpram_write_magic_code(dpld, DP_MAGIC_CODE); } pr_info("MIF: <%s->", __func__); }
static int dpram_trigger_force_cp_crash(struct dpram_link_device *dpld) { struct link_device *ld = &dpld->ld; int ret; int cnt = 5000; if (ld->mode == LINK_MODE_ULOAD) { mif_err("%s: CP crash is already in progress\n", ld->name); return 0; } ld->mode = LINK_MODE_ULOAD; mif_err("%s: called by %pf\n", ld->name, __builtin_return_address(0)); dpram_wake_up(dpld); send_intr(dpld, INT_CMD(INT_CMD_CRASH_EXIT)); while (cnt--) { ret = try_wait_for_completion(&dpld->crash_start_complete); if (ret) break; udelay(1000); } if (!ret) { mif_info("%s: ERR! No CRASH_EXIT ACK from CP\n", ld->name); dpram_trigger_crash(dpld); } return 0; }
static void cmd_phone_start_handler(struct dpram_link_device *dpld) { struct link_device *ld = &dpld->ld; struct io_device *iod = NULL; mif_info("%s: Recv 0xC8 (CP_START)\n", ld->name); dpram_init_ipc(dpld); iod = link_get_iod_with_format(ld, IPC_FMT); if (!iod) { mif_info("%s: ERR! no iod\n", ld->name); return; } if (dpld->ext_op && dpld->ext_op->cp_start_handler) dpld->ext_op->cp_start_handler(dpld); if (ld->mc->phone_state != STATE_ONLINE) { mif_info("%s: phone_state: %d -> ONLINE\n", ld->name, ld->mc->phone_state); iod->modem_state_changed(iod, STATE_ONLINE); } mif_info("%s: Send 0xC2 (INIT_END)\n", ld->name); send_intr(dpld, INT_CMD(INT_CMD_INIT_END)); }
static void idpram_power_down(struct idpram_link_pm_data *pm_data) { pr_info("MIF: <%s>\n", __func__); pm_data->last_pm_mailbox = INT_CMD(INT_MASK_CMD_DPRAM_DOWN); complete(&pm_data->idpram_down); }
static int idpram_resume_check(struct idpram_link_pm_data *pm_data) { /* check last pm mailbox */ mif_info("MIF: idpram %s, last_pm_mailbox=%x\n", __func__, pm_data->last_pm_mailbox); if (pm_data->last_pm_mailbox == INT_CMD(INT_MASK_CMD_PDA_WAKEUP)) { pm_data->last_pm_mailbox = 0; return 0; } dpram_write_command(pm_data->dpld, INT_CMD(INT_MASK_CMD_PDA_WAKEUP)); mif_info("MIF: idpram sent PDA_WAKEUP Mailbox(0x%x)\n", INT_CMD(INT_MASK_CMD_PDA_WAKEUP)); return -1; }
static void s5p_idpram_power_up(struct dpram_link_device *dpld) { struct idpram_pm_data *pm_data = &dpld->pm_data; mif_info("+++\n"); pm_data->last_msg = INT_CMD(INT_CMD_IDPRAM_RESUME_REQ); pm_data->pm_state = IDPRAM_PM_ACTIVE; mif_info("---\n"); }
static void s5p_idpram_power_down(struct dpram_link_device *dpld) { struct idpram_pm_data *pm_data = &dpld->pm_data; mif_info("+++\n"); pm_data->last_msg = INT_CMD(INT_CMD_IDPRAM_SUSPEND_ACK); complete(&pm_data->down_cmpl); mif_info("---\n"); }
static void qsc6085_start_handler(struct dpram_link_device *dpld) { struct link_device *ld = &dpld->ld; struct io_device *iod; mif_info("recv 0xC8 (CP_START)\n"); mif_info("send 0xC1 (INIT_START)\n"); dpld->send_intr(dpld, INT_CMD(INT_CMD_INIT_START)); dpld->reset_dpram_ipc(dpld); iod = link_get_iod_with_format(ld, IPC_FMT); if (!iod) { mif_err("ERR! no iod\n"); return; } iod->modem_state_changed(iod, STATE_ONLINE); mif_info("send 0xC2 (INIT_END)\n"); dpld->send_intr(dpld, INT_CMD(INT_CMD_INIT_END)); }
static int cbp71_force_crash_exit(struct modem_ctl *mc) { struct link_device *ld = get_current_link(mc->iod); struct dpram_link_device *dpld = to_dpram_link_device(ld); mif_err("force_crash_exit\n"); mif_err("<%s>\n", mc->bootd->name); dpld->dpctl->send_intr(INT_CMD(INT_CMD_ERR_DISPLAY)); mc->iod->modem_state_changed(mc->iod, STATE_CRASH_EXIT); return 0; }
static int trigger_force_cp_crash(struct dpram_link_device *dpld) { struct link_device *ld = &dpld->ld; if (ld->mode == LINK_MODE_ULOAD) { mif_err("%s: CP crash is already in progress\n", ld->mc->name); return 0; } ld->mode = LINK_MODE_ULOAD; mif_err("%s: called by %pf\n", ld->name, __builtin_return_address(0)); dpram_wake_up(dpld); send_intr(dpld, INT_CMD(INT_CMD_CRASH_EXIT)); mif_add_timer(&dpld->crash_ack_timer, FORCE_CRASH_ACK_TIMEOUT, handle_no_crash_ack, (unsigned long)dpld); return 0; }
static int s5p_idpram_prepare_suspend(struct dpram_link_device *dpld) { struct link_device *ld = &dpld->ld; struct idpram_pm_data *pm_data = &dpld->pm_data; struct modem_ctl *mc = dpld->ld.mc; struct completion *cmpl; unsigned long timeout; unsigned long rest; int cnt = 0; u16 cmd = INT_CMD(INT_CMD_IDPRAM_SUSPEND_REQ); mif_info("+++\n"); pm_data->pm_state = IDPRAM_PM_SUSPEND_PREPARE; pm_data->last_msg = 0; s5p_idpram_set_pm_lock(dpld, 1); /* * Because, if dpram was powered down, cp dpram random intr was * ocurred. so, fixed by muxing cp dpram intr pin to GPIO output * high,.. */ gpio_set_value(dpld->gpio_int2cp, 1); s3c_gpio_cfgpin(dpld->gpio_int2cp, S3C_GPIO_OUTPUT); /* prevent PDA_ACTIVE status is low */ gpio_set_value(mc->gpio_pda_active, 1); cmpl = &pm_data->down_cmpl; timeout = IDPRAM_SUSPEND_REQ_TIMEOUT; cnt = 0; do { init_completion(cmpl); mif_info("send IDPRAM_SUSPEND_REQ (0x%X)\n", cmd); dpld->send_intr(dpld, cmd); rest = wait_for_completion_timeout(cmpl, timeout); if (rest == 0) { cnt++; mif_err("timeout!!! (count = %d)\n", cnt); if (cnt >= 3) { mif_err("ERR! no response from CP\n"); break; } } } while (rest == 0); switch (pm_data->last_msg) { case INT_CMD(INT_CMD_IDPRAM_SUSPEND_ACK): mif_info("recv IDPRAM_SUSPEND_ACK (0x%X)\n", pm_data->last_msg); pm_data->pm_state = IDPRAM_PM_DPRAM_POWER_DOWN; break; default: mif_err("ERR! %s down or not ready!!! (intr 0x%04X)\n", ld->name, dpld->recv_intr(dpld)); timeout = msecs_to_jiffies(500); wake_lock_timeout(&pm_data->hold_wlock, timeout); s5p_idpram_set_pm_lock(dpld, 0); break; } mif_info("---\n"); return 0; }
static void cmd_req_active_handler(struct dpram_link_device *dpld) { send_intr(dpld, INT_CMD(INT_CMD_RES_ACTIVE)); }
static void qsc6085_req_active_handler(struct dpram_link_device *dpld) { struct modem_ctl *mc = dpld->ld.mc; mif_info("pda_active = %d\n", gpio_get_value(mc->gpio_pda_active)); dpld->send_intr(dpld, INT_CMD(INT_CMD_RES_ACTIVE)); }
static void idpram_power_down_nack(struct idpram_link_pm_data *pm_data) { pm_data->last_pm_mailbox = INT_CMD(INT_MASK_CMD_DPRAM_DOWN_NACK); complete(&pm_data->idpram_down); mif_debug("MIF: <%s>\n", __func__); }
static int idpram_pre_suspend(struct idpram_link_pm_data *pm_data) { int timeout_ret = 0; int suspend_retry = 3; u16 intr_out = INT_CMD(INT_MASK_CMD_PDA_SLEEP); struct io_device *iod = dpram_find_iod_by_format(pm_data->dpld, IPC_RAMDUMP); pr_info("MIF: <%s+>\n", __func__); /* 1. write magic number=0x554C 2. send phone reset cmd=0x000F 3. collect the modem ramdump 4. modem reset 5. modem on */ #if defined(ENABLE_FORCED_CP_CRASH) dpram_force_cp_crash(&pm_data->dpld->ld); fp = mif_open_file("/sdcard/ramdump1.data"); if (!fp) pr_err("MIF: <%s> file pointer is NULL\n", __func__); dpram_start_ramdump(&pm_data->dpld->ld, iod); for (; iod->ramdump_size;) dpram_read_ramdump(&pm_data->dpld->ld, iod); dpram_stop_ramdump(&pm_data->dpld->ld, iod); mif_close_file(fp); iod->mc->ops.modem_reset(iod->mc); iod->mc->ops.modem_on(iod->mc); pr_info("MIF: <%s->\n", __func__); return 0; #endif pm_data->pm_states = IDPRAM_PM_SUSPEND_PREPARE; pm_data->last_pm_mailbox = 0; idpram_write_lock(pm_data, 1); gpio_set_value(pm_data->mdata->gpio_mbx_intr, 1); /* prevent PDA_ACTIVE status is low */ gpio_set_value(pm_data->mdata->gpio_pda_active, 1); if (!atomic_read(&pm_data->read_lock)) { do { init_completion(&pm_data->idpram_down); dpram_write_command(pm_data->dpld, intr_out); pr_info("MIF: sending cmd = 0x%X\n", intr_out); timeout_ret = wait_for_completion_timeout(&pm_data->idpram_down, PDA_SLEEP_CMD_TIMEOUT); if (!timeout_ret) pr_err("MIF: timeout!. retry cnt = %d\n", \ suspend_retry); } while (!timeout_ret && --suspend_retry); if (!timeout_ret && !suspend_retry) pr_err("MIF: no response for PDA_SLEEP cmd\n"); pr_info("MIF: last responce from cp = 0x%X\n", \ pm_data->last_pm_mailbox); switch (pm_data->last_pm_mailbox) { case INT_CMD(INT_MASK_CMD_DPRAM_DOWN): pr_info("MIF: INT_MASK_CMD_DPRAM_DOWN\n"); break; /* if nack or other interrup, hold wakelock for DPM resume */ #ifndef CONFIG_CDMA_MODEM_QSC6085 case INT_CMD(INT_MASK_CMD_DPRAM_DOWN_NACK): pr_info("MIF: INT_MASK_CMD_DPRAM_DOWN_NACK\n"); break; #endif default: pr_err("MIF: idpram down or not ready!! intr = 0x%X\n", dpram_readh(&pm_data->dpld->dpram->mbx_cp2ap)); wake_lock_timeout(&pm_data->hold_wlock, msecs_to_jiffies(500)); idpram_write_lock(pm_data, 0); /* 1. Flash a modem which crashes when AP sends cmd=PDA_SLEEP 2. collect the modem ramdump 3. modem reset 4. modem on */ #if defined(CP_CRASHES_ON_PDA_SLEEP_CMD) fp = mif_open_file("/sdcard/ramdump2.data"); if (!fp) pr_err("MIF: <%s> fp is NULL\n", __func__); dpram_start_ramdump(&pm_data->dpld->ld, iod); for (; iod->ramdump_size;) dpram_read_ramdump(&pm_data->dpld->ld, iod); dpram_stop_ramdump(&pm_data->dpld->ld, iod); mif_close_file(fp); iod->mc->ops.modem_reset(iod->mc); iod->mc->ops.modem_on(iod->mc); #endif pr_info("MIF: <%s->\n", __func__); return 0; } /* * Because, if dpram was powered down, cp dpram random intr was * ocurred. so, fixed by muxing cp dpram intr pin to GPIO output * high,.. */ gpio_set_value(pm_data->mdata->gpio_mbx_intr, 1); s3c_gpio_cfgpin(pm_data->mdata->gpio_mbx_intr, S3C_GPIO_OUTPUT); pm_data->pm_states = IDPRAM_PM_DPRAM_POWER_DOWN; pr_info("MIF: <%s->\n", __func__); return 0; } else { pr_err("MIF: hold read_lock failed\n"); return -EBUSY; } }