static irqreturn_t mdm_status_change(int irq, void *dev_id) { int value; struct esoc_clink *esoc; struct mdm_ctrl *mdm = (struct mdm_ctrl *)dev_id; struct device *dev; if (!mdm) return IRQ_HANDLED; dev = mdm->dev; esoc = mdm->esoc; value = gpio_get_value(MDM_GPIO(mdm, MDM2AP_STATUS)); if (value == 0 && mdm->ready) { dev_err(dev, "unexpected reset external modem\n"); esoc_clink_evt_notify(ESOC_UNEXPECTED_RESET, esoc); } else if (value == 1) { cancel_delayed_work(&mdm->mdm2ap_status_check_work); dev_info(dev, "status = 1: mdm is now ready\n"); mdm->ready = true; queue_work(mdm->mdm_queue, &mdm->mdm_status_work); if (mdm->get_restart_reason) queue_work(mdm->mdm_queue, &mdm->restart_reason_work); } return IRQ_HANDLED; }
static irqreturn_t mdm_errfatal(int irq, void *dev_id) { struct mdm_ctrl *mdm = (struct mdm_ctrl *)dev_id; struct esoc_clink *esoc; struct device *dev; if (!mdm) goto no_mdm_irq; dev = mdm->dev; if (!mdm->ready) goto mdm_pwroff_irq; esoc = mdm->esoc; if(!gpio_get_value(MDM_GPIO(mdm, MDM2AP_ERRFATAL)) || !gpio_get_value(MDM_GPIO(mdm, MDM2AP_VDDMIN))) { dev_err(dev, "%s: ignore IRQ errfatal: %d, vddmin: %d\n", __func__, gpio_get_value(MDM_GPIO(mdm, MDM2AP_ERRFATAL)), gpio_get_value(MDM_GPIO(mdm, MDM2AP_VDDMIN))); return IRQ_HANDLED; } dev_err(dev, "%s: mdm sent errfatal interrupt\n", __func__); dev_err(dev, "%s: ep0_timeout: %d\n", __func__, ep0_timeout_cnt); exynos_pcie_dump_link_down_status(0); /* disable irq ?*/ esoc_clink_evt_notify(ESOC_ERR_FATAL, esoc); mdm_fatal_debug_gpio_show(mdm); return IRQ_HANDLED; mdm_pwroff_irq: dev_info(dev, "errfatal irq when in pwroff\n"); no_mdm_irq: return IRQ_HANDLED; }
static void mdm2ap_status_check(struct work_struct *work) { struct mdm_ctrl *mdm = container_of(work, struct mdm_ctrl, mdm2ap_status_check_work.work); struct device *dev = mdm->dev; struct esoc_clink *esoc = mdm->esoc; if (gpio_get_value(MDM_GPIO(mdm, MDM2AP_STATUS)) == 0) { dev_dbg(dev, "MDM2AP_STATUS did not go high\n"); esoc_clink_evt_notify(ESOC_UNEXPECTED_RESET, esoc); } }
static irqreturn_t mdm_errfatal(int irq, void *dev_id) { struct mdm_ctrl *mdm = (struct mdm_ctrl *)dev_id; struct esoc_clink *esoc; struct device *dev; if (!mdm) goto no_mdm_irq; dev = mdm->dev; if (!mdm->ready) goto mdm_pwroff_irq; esoc = mdm->esoc; dev_err(dev, "%s: mdm sent errfatal interrupt\n", __func__); /* disable irq ?*/ esoc_clink_evt_notify(ESOC_ERR_FATAL, esoc); return IRQ_HANDLED; mdm_pwroff_irq: dev_info(dev, "errfatal irq when in pwroff\n"); no_mdm_irq: return IRQ_HANDLED; }
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 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; }