static void mdm_set_hsic_ready(struct esoc_clink *esoc) { struct mdm_ctrl *mdm = get_esoc_clink_data(esoc); gpio_set_value(MDM_GPIO(mdm, AP2MDM_HSIC_READY), 0); msleep(10); gpio_set_value(MDM_GPIO(mdm, AP2MDM_HSIC_READY), 1); }
static int mdm_get_status(u32 *status, struct esoc_clink *esoc) { struct mdm_ctrl *mdm = get_esoc_clink_data(esoc); if (gpio_get_value(MDM_GPIO(mdm, MDM2AP_STATUS)) == 0) *status = 0; else *status = 1; return 0; }
static void mdm_notify(enum esoc_notify notify, struct esoc_clink *esoc) { bool status_down; uint64_t timeout; uint64_t now; struct mdm_ctrl *mdm = get_esoc_clink_data(esoc); struct device *dev = mdm->dev; switch (notify) { case ESOC_IMG_XFER_DONE: dev_info(dev, "%s ESOC_IMG_XFER_DONE\n", __func__); if (gpio_get_value(MDM_GPIO(mdm, MDM2AP_STATUS)) == 0) schedule_delayed_work(&mdm->mdm2ap_status_check_work, msecs_to_jiffies(MDM2AP_STATUS_TIMEOUT_MS)); break; case ESOC_BOOT_DONE: esoc_clink_evt_notify(ESOC_RUN_STATE, esoc); break; case ESOC_IMG_XFER_RETRY: mdm->init = 1; mdm_toggle_soft_reset(mdm); break; case ESOC_IMG_XFER_FAIL: esoc_clink_evt_notify(ESOC_BOOT_FAIL, esoc); break; case ESOC_UPGRADE_AVAILABLE: break; case ESOC_DEBUG_DONE: mdm->debug_fail = false; mdm_update_gpio_configs(mdm, GPIO_UPDATE_BOOTING_CONFIG); complete(&mdm->debug_done); break; case ESOC_DEBUG_FAIL: mdm->debug_fail = true; complete(&mdm->debug_done); break; case ESOC_PRIMARY_CRASH: mdm_disable_irqs(mdm); status_down = false; dev_info(dev, "signal apq err fatal for graceful restart\n"); gpio_set_value(MDM_GPIO(mdm, AP2MDM_ERRFATAL), 1); timeout = local_clock(); do_div(timeout, NSEC_PER_MSEC); timeout += MDM_MODEM_TIMEOUT; do { if (gpio_get_value(MDM_GPIO(mdm, MDM2AP_STATUS)) == 0) { status_down = true; break; } now = local_clock(); do_div(now, NSEC_PER_MSEC); } while (!time_after64(now, timeout)); if (!status_down) { dev_err(mdm->dev, "%s MDM2AP status did not go low\n", __func__); gpio_direction_output(MDM_GPIO(mdm, AP2MDM_SOFT_RESET), !!mdm->soft_reset_inverted); /* * allow PS hold assert to be detected. * pmic requires 6ms for crash reset case. */ mdelay(6); gpio_direction_output(MDM_GPIO(mdm, AP2MDM_SOFT_RESET), !mdm->soft_reset_inverted); } break; case ESOC_PRIMARY_REBOOT: dev_info(mdm->dev, "Triggering mdm cold reset"); mdm->ready = 0; gpio_direction_output(MDM_GPIO(mdm, AP2MDM_SOFT_RESET), !!mdm->soft_reset_inverted); mdelay(300); gpio_direction_output(MDM_GPIO(mdm, AP2MDM_SOFT_RESET), !mdm->soft_reset_inverted); break; }; return; }
static int mdm_cmd_exe(enum esoc_cmd cmd, struct esoc_clink *esoc) { int ret; unsigned long end_time; bool status_down = false; struct mdm_ctrl *mdm = get_esoc_clink_data(esoc); struct device *dev = mdm->dev; switch (cmd) { case ESOC_PWR_ON: gpio_set_value(MDM_GPIO(mdm, AP2MDM_ERRFATAL), 0); mdm_enable_irqs(mdm); mdm->init = 1; mdm_do_first_power_on(mdm); break; case ESOC_PWR_OFF: mdm_disable_irqs(mdm); mdm->debug = 0; mdm->ready = false; ret = sysmon_send_shutdown(mdm->sysmon_subsys_id); device_lock(dev); if (ret) dev_err(mdm->dev, "Graceful shutdown fail, ret = %d\n", ret); else { dev_info(mdm->dev, "Waiting for status gpio go low\n"); status_down = false; end_time = jiffies + msecs_to_jiffies(10000); while (time_before(jiffies, end_time)) { if (gpio_get_value(MDM_GPIO(mdm, MDM2AP_STATUS)) == 0) { dev_dbg(dev, "Status went low\n"); status_down = true; break; } msleep(100); } if (status_down) dev_info(dev, "shutdown successful\n"); else dev_err(mdm->dev, "graceful poff ipc fail\n"); } /* * Force a shutdown of the mdm. This is required in order * to prevent the mdm from immediately powering back on * after the shutdown */ gpio_set_value(MDM_GPIO(mdm, AP2MDM_STATUS), 0); esoc_clink_queue_request(ESOC_REQ_SHUTDOWN, esoc); mdm_power_down(mdm); mdm_update_gpio_configs(mdm, GPIO_UPDATE_BOOTING_CONFIG); device_unlock(dev); break; case ESOC_RESET: mdm_toggle_soft_reset(mdm); break; case ESOC_PREPARE_DEBUG: /* * disable all irqs except request irq (pblrdy) * force a reset of the mdm by signaling * an APQ crash, wait till mdm is ready for ramdumps. */ mdm->ready = false; cancel_delayed_work(&mdm->mdm2ap_status_check_work); gpio_set_value(MDM_GPIO(mdm, AP2MDM_ERRFATAL), 1); dev_info(mdm->dev, "set ap2mdm errfatal to force reset\n"); msleep(mdm->ramdump_delay_ms); break; case ESOC_EXE_DEBUG: mdm->debug = 1; mdm_toggle_soft_reset(mdm); /* * wait for ramdumps to be collected * then power down the mdm and switch gpios to booting * config */ if (!wait_for_completion_timeout(&mdm->debug_done, msecs_to_jiffies(mdm->dump_timeout_ms))) { dev_err(mdm->dev, "ramdump collection timedout\n"); mdm->debug = 0; return -ETIMEDOUT; } if (mdm->debug_fail) { dev_err(mdm->dev, "unable to collect ramdumps\n"); mdm->debug = 0; return -EIO; } dev_dbg(mdm->dev, "ramdump collection done\n"); mdm->debug = 0; init_completion(&mdm->debug_done); break; case ESOC_EXIT_DEBUG: /* * Deassert APQ to mdm err fatal * Power on the mdm */ gpio_set_value(MDM_GPIO(mdm, AP2MDM_ERRFATAL), 0); dev_dbg(mdm->dev, "exiting debug state after power on\n"); mdm->get_restart_reason = true; break; default: return -EINVAL; }; return 0; }
static void mdm_notify(enum esoc_notify notify, struct esoc_clink *esoc) { bool status_down; uint64_t timeout; uint64_t now; struct mdm_ctrl *mdm = get_esoc_clink_data(esoc); struct device *dev = mdm->dev; int ret; int max_spin = 20; switch (notify) { case ESOC_IMG_XFER_DONE: dev_info(dev, "%s ESOC_IMG_XFER_DONE\n", __func__); if (gpio_get_value(MDM_GPIO(mdm, MDM2AP_STATUS)) == 0) schedule_delayed_work(&mdm->mdm2ap_status_check_work, msecs_to_jiffies(MDM2AP_STATUS_TIMEOUT_MS)); break; case ESOC_BOOT_DONE: esoc_clink_evt_notify(ESOC_RUN_STATE, esoc); break; case ESOC_IMG_XFER_RETRY: mdm->init = 1; mdm_toggle_soft_reset(mdm); break; case ESOC_IMG_XFER_FAIL: esoc_clink_evt_notify(ESOC_INVALID_STATE, esoc); break; case ESOC_BOOT_FAIL: esoc_clink_evt_notify(ESOC_INVALID_STATE, esoc); break; case ESOC_UPGRADE_AVAILABLE: break; case ESOC_DEBUG_DONE: mdm->debug_fail = false; mdm_update_gpio_configs(mdm, GPIO_UPDATE_BOOTING_CONFIG); complete(&mdm->debug_done); break; case ESOC_DEBUG_FAIL: mdm->debug_fail = true; complete(&mdm->debug_done); break; case ESOC_PRIMARY_CRASH: mdm_disable_irqs(mdm); status_down = false; dev_info(dev, "signal apq err fatal for graceful restart\n"); gpio_set_value(MDM_GPIO(mdm, AP2MDM_ERRFATAL), 1); gpio_set_value(MDM_GPIO(mdm, AP2MDM_VDDMIN), 1); timeout = local_clock(); do_div(timeout, NSEC_PER_MSEC); timeout += MDM_MODEM_TIMEOUT; do { if (gpio_get_value(MDM_GPIO(mdm, MDM2AP_STATUS)) == 0) { status_down = true; break; } now = local_clock(); do_div(now, NSEC_PER_MSEC); } while (!time_after64(now, timeout)); if (!status_down) { dev_err(mdm->dev, "%s MDM2AP status did not go low\n", __func__); gpio_direction_output(MDM_GPIO(mdm, AP2MDM_SOFT_RESET), !!mdm->soft_reset_inverted); /* * allow PS hold assert to be detected. * pmic requires 6ms for crash reset case. */ mdelay(6); gpio_direction_output(MDM_GPIO(mdm, AP2MDM_SOFT_RESET), !mdm->soft_reset_inverted); } break; case ESOC_PRIMARY_REBOOT: exynos_pcie_disable_irq(0); mdm_disable_irqs(mdm); dev_info(mdm->dev, "Triggering mdm cold reset"); mdm->ready = 0; while (gpio_get_value(MDM_GPIO(mdm, MDM2AP_STATUS)) && max_spin--) { msleep(100); dev_info(mdm->dev, "gpio_get_value(MDM2AP_STATUS) : %d\n", gpio_get_value(MDM_GPIO(mdm, MDM2AP_STATUS))); } gpio_direction_output(MDM_GPIO(mdm, AP2MDM_SOFT_RESET), !!mdm->soft_reset_inverted); mdelay(300); gpio_direction_output(MDM_GPIO(mdm, AP2MDM_SOFT_RESET), !mdm->soft_reset_inverted); break; case ESOC_DIAG_DISABLE: dev_info(mdm->dev, "Send diag_disable noti\n"); ret = sysmon_send_diag_disable_noti(mdm->sysmon_subsys_id); if (ret < 0) dev_err(mdm->dev, "sending diag_disable noti is failed, ret = %d\n", ret); else dev_info(mdm->dev, "sending diag_disable noti is succeed.\n"); break; case ESOC_FORCE_CPCRASH: dev_err(mdm->dev, "Force CP Crash\n"); gpio_set_value(MDM_GPIO(mdm, AP2MDM_ERRFATAL), 1); gpio_set_value(MDM_GPIO(mdm, AP2MDM_VDDMIN), 1); break; case ESOC_CP_SILENT_RESET: dev_err(mdm->dev, "Force CP Silent Reset\n"); set_silent_reset(); gpio_set_value(MDM_GPIO(mdm, AP2MDM_ERRFATAL), 1); gpio_set_value(MDM_GPIO(mdm, AP2MDM_VDDMIN), 1); break; }; return; }