static void mdm_image_upgrade(struct mdm_modem_drv *mdm_drv, int type) { switch (type) { case APQ_CONTROLLED_UPGRADE: pr_debug("%s APQ controlled modem image upgrade\n", __func__); mdm_drv->mdm_ready = 0; mdm_toggle_soft_reset(mdm_drv); break; case MDM_CONTROLLED_UPGRADE: pr_debug("%s MDM controlled modem image upgrade\n", __func__); mdm_drv->mdm_ready = 0; /* * If we have no image currently present on the modem, then we * would be in PBL, in which case the status gpio would not go * high. */ mdm_drv->disable_status_check = 1; if (GPIO_IS_VALID(mdm_drv->usb_switch_gpio)) { pr_info("%s Switching usb control to MDM\n", __func__); gpio_direction_output(mdm_drv->usb_switch_gpio, 1); } else pr_err("%s usb switch gpio unavailable\n", __func__); break; default: pr_err("%s invalid upgrade type\n", __func__); } }
static void mdm_do_first_power_on(struct mdm_ctrl *mdm) { int i; int pblrdy; struct device *dev = mdm->dev; dev_info(dev, "Powering on modem for the first time\n"); mdm_toggle_soft_reset(mdm); /* Add a delay to allow PON sequence to complete*/ msleep(50); gpio_direction_output(MDM_GPIO(mdm, AP2MDM_STATUS), 1); for (i = 0; i < MDM_PBLRDY_CNT; i++) { pblrdy = gpio_get_value(MDM_GPIO(mdm, MDM2AP_PBLRDY)); if (pblrdy) break; usleep_range(5000, 6000); } dev_info(dev, "pblrdy i:%d\n", i); if (pmdata_gpio_host_ready) { dev_info(dev, "Set qcom,ap2mdm-hostrdy-gpio to 1\n"); gpio_direction_output(pmdata_gpio_host_ready, 1); gpio_set_value(pmdata_gpio_host_ready, 1); } else { dev_info(dev, "Fail to set gpio pin qcom,ap2mdm-hostrdy-gpio\n"); } msleep(200); }
static void mdm_do_soft_power_on(struct mdm_modem_drv *mdm_drv) { int i; int pblrdy; pr_err("%s: soft resetting mdm modem\n", __func__); mdm_peripheral_disconnect(mdm_drv); mdm_toggle_soft_reset(mdm_drv); if (!GPIO_IS_VALID(mdm_drv->mdm2ap_pblrdy)) goto start_mdm_peripheral; for (i = 0; i < MDM_PBLRDY_CNT; i++) { pblrdy = gpio_get_value(mdm_drv->mdm2ap_pblrdy); if (pblrdy) break; usleep_range(5000, 5000); } pr_debug("%s: i:%d\n", __func__, i); start_mdm_peripheral: mdm_peripheral_connect(mdm_drv); msleep(200); }
static void mdm_do_first_power_on(struct mdm_modem_drv *mdm_drv) { int i; int pblrdy; int kpd_direction_assert = 1, kpd_direction_de_assert = 0; if (mdm_drv->pdata->kpd_not_inverted) { kpd_direction_assert = 0; kpd_direction_de_assert = 1; } if (mdm_drv->power_on_count != 1) { pr_err("%s:id %d: Calling fn when power_on_count != 1\n", __func__, mdm_drv->device_id); return; } pr_err("%s:id %d: Powering on modem for the first time\n", __func__, mdm_drv->device_id); mdm_peripheral_disconnect(mdm_drv); /* If this is the first power-up after a panic, the modem may still * be in a power-on state, in which case we need to toggle the gpio * instead of just de-asserting it. No harm done if the modem was * powered down. */ if (!mdm_drv->pdata->no_reset_on_first_powerup) mdm_toggle_soft_reset(mdm_drv); /* If the device has a kpd pwr gpio then toggle it. */ if (GPIO_IS_VALID(mdm_drv->ap2mdm_kpdpwr_n_gpio)) { /* Pull AP2MDM_KPDPWR gpio high and wait for PS_HOLD to settle, * then pull it back low. */ pr_debug("%s:id %d: Pulling AP2MDM_KPDPWR gpio high\n", __func__, mdm_drv->device_id); gpio_direction_output(mdm_drv->ap2mdm_kpdpwr_n_gpio, kpd_direction_assert); msleep(1000); gpio_direction_output(mdm_drv->ap2mdm_kpdpwr_n_gpio, kpd_direction_de_assert); } if (!GPIO_IS_VALID(mdm_drv->mdm2ap_pblrdy)) goto start_mdm_peripheral; for (i = 0; i < MDM_PBLRDY_CNT; i++) { pblrdy = gpio_get_value(mdm_drv->mdm2ap_pblrdy); if (pblrdy) break; usleep_range(5000, 5000); } pr_debug("%s: id %d: pblrdy i:%d\n", __func__, mdm_drv->device_id, i); start_mdm_peripheral: mdm_peripheral_connect(mdm_drv); msleep(200); }
static void mdm_do_soft_power_on(struct mdm_modem_drv *mdm_drv) { #ifdef USE_MDM_MODEM int i; int pblrdy; #endif pr_err("%s: id %d: soft resetting mdm modem\n", __func__, mdm_drv->device_id); mdm_peripheral_disconnect(mdm_drv); mdm_toggle_soft_reset(mdm_drv); #ifdef USE_MDM_MODEM if (!GPIO_IS_VALID(MDM_GPIO(MDM2AP_PBLRDY))) goto start_mdm_peripheral; for (i = 0; i < MDM_PBLRDY_CNT; i++) { pblrdy = gpio_get_value(MDM_GPIO(MDM2AP_PBLRDY)); if (pblrdy) break; usleep_range(5000, 5000); } pr_info("%s: id %d: pblrdy i:%d\n", __func__, mdm_drv->device_id, i); start_mdm_peripheral: #endif mdm_peripheral_connect(mdm_drv); msleep(200); }
static void mdm_image_upgrade(struct mdm_modem_drv *mdm_drv, int type) { switch (type) { case APQ_CONTROLLED_UPGRADE: pr_debug("%s: id %d: APQ controlled modem image upgrade\n", __func__, mdm_drv->device_id); atomic_set(&mdm_drv->mdm_ready, 0); mdm_toggle_soft_reset(mdm_drv); break; case MDM_CONTROLLED_UPGRADE: pr_debug("%s: id %d: MDM controlled modem image upgrade\n", __func__, mdm_drv->device_id); atomic_set(&mdm_drv->mdm_ready, 0); /* * If we have no image currently present on the modem, then we * would be in PBL, in which case the status gpio would not go * high. */ mdm_drv->disable_status_check = 1; if (GPIO_IS_VALID(MDM_GPIO(USB_SW))) { pr_debug("%s: id %d: Switching usb control to MDM\n", __func__, mdm_drv->device_id); gpio_direction_output(MDM_GPIO(USB_SW), 1); } else pr_err("%s: id %d: usb switch gpio unavailable\n", __func__, mdm_drv->device_id); break; default: pr_err("%s: id %d: invalid upgrade type\n", __func__, mdm_drv->device_id); } }
/* This function can be called from atomic context. */ static void mdm_atomic_soft_reset(struct mdm_modem_drv *mdm_drv) { mdm_toggle_soft_reset(mdm_drv); }
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; }
static void mdm_do_first_power_on(struct mdm_modem_drv *mdm_drv) { int i; int pblrdy; if (power_on_count != 1) { pr_err("%s: Calling fn when power_on_count != 1\n", __func__); return; } pr_err("%s: Powering on modem for the first time\n", __func__); gpio_direction_output(mdm_drv->ap2mdm_wakeup_gpio, 0); mdm_peripheral_disconnect(mdm_drv); /* If this is the first power-up after a panic, the modem may still * be in a power-on state, in which case we need to toggle the gpio * instead of just de-asserting it. No harm done if the modem was * powered down. */ mdm_toggle_soft_reset(mdm_drv); /* If the device has a kpd pwr gpio then toggle it. */ if (mdm_drv->ap2mdm_kpdpwr_n_gpio > 0) { /* Pull AP2MDM_KPDPWR gpio high and wait for PS_HOLD to settle, * then pull it back low. */ pr_debug("%s: Pulling AP2MDM_KPDPWR gpio high\n", __func__); gpio_direction_output(mdm_drv->ap2mdm_kpdpwr_n_gpio, 1); msleep(1000); gpio_direction_output(mdm_drv->ap2mdm_kpdpwr_n_gpio, 0); } /* first power charged after 10ms */ usleep_range(10000, 15000); gpio_direction_output(mdm_drv->ap2mdm_status_gpio, 1); #ifdef CONFIG_HSIC_EURONLY_APPLY for (i = 0; i < MDM_PBLRDY_CNT; i++) { pblrdy = gpio_get_value(mdm_drv->mdm2ap_pblrdy); if (pblrdy) break; usleep_range(5000, 5000); } pr_err("%s: i:%d\n", __func__, i); #else if (!mdm_drv->mdm2ap_pblrdy) goto start_mdm_peripheral; for (i = 0; i < MDM_PBLRDY_CNT; i++) { pblrdy = gpio_get_value(mdm_drv->mdm2ap_pblrdy); if (pblrdy) break; usleep_range(5000, 5000); } pr_debug("%s: i:%d\n", __func__, i); #endif start_mdm_peripheral: mdm_peripheral_connect(mdm_drv); msleep(200); }
static void mdm_do_first_power_on(struct mdm_modem_drv *mdm_drv) { #ifdef USE_MDM_MODEM int i; int pblrdy; #endif gpio_direction_output(MDM_GPIO(AP2MDM_SOFT_RESET), 0); gpio_direction_output(MDM_GPIO(AP2MDM_PMIC_PWR_EN), 1); msleep(10); if (mdm_drv->power_on_count != 1) { pr_debug("%s:id %d: Calling fn when power_on_count != 1\n", __func__, mdm_drv->device_id); return; } pr_err("%s \n", __func__); pr_err("%s:id %d: Powering on modem for the first time\n", __func__, mdm_drv->device_id); mdm_peripheral_disconnect(mdm_drv); /* If this is the first power-up after a panic, the modem may still * be in a power-on state, in which case we need to toggle the gpio * instead of just de-asserting it. No harm done if the modem was * powered down. */ if (!mdm_drv->pdata->no_reset_on_first_powerup) mdm_toggle_soft_reset(mdm_drv); /* If the device has a kpd pwr gpio then toggle it. */ if (GPIO_IS_VALID(MDM_GPIO(AP2MDM_KPDPWR))) { // HSLEE qsc en /* Pull AP2MDM_KPDPWR gpio high and wait for PS_HOLD to settle, * then pull it back low. */ pr_err("%s:id %d: Pulling AP2MDM_KPDPWR gpio high\n", __func__, mdm_drv->device_id); gpio_direction_output(MDM_GPIO(AP2MDM_KPDPWR), 1); //gpio_direction_output(MDM_GPIO(AP2MDM_STATUS), 1); msleep(1000); gpio_direction_output(MDM_GPIO(AP2MDM_KPDPWR), 0); }//else gpio_direction_output(MDM_GPIO(AP2MDM_STATUS), 1); msleep(5000); if (!gpio_get_value(MDM_GPIO(MDM2AP_STATUS))) { pr_err("%s: QSC failed. reboot\n", __func__); gpio_direction_output(MDM_GPIO(AP2MDM_STATUS), 0); gpio_direction_output(MDM_GPIO(AP2MDM_PMIC_PWR_EN), 0); msleep(5000); gpio_direction_output(MDM_GPIO(AP2MDM_PMIC_PWR_EN), 1); msleep(10); gpio_direction_output(MDM_GPIO(AP2MDM_KPDPWR), 1); msleep(1000); gpio_direction_output(MDM_GPIO(AP2MDM_KPDPWR), 0); gpio_direction_output(MDM_GPIO(AP2MDM_STATUS), 1); } /* check if qsc is in dload mode */ if (gpio_get_value(MDM_GPIO(MDM2AP_ERRFATAL))) { pr_err("%s: QSC is in dload. reset\n", __func__); gpio_direction_output(MDM_GPIO(AP2MDM_SOFT_RESET), 1); mdelay(10); gpio_direction_output(MDM_GPIO(AP2MDM_SOFT_RESET), 0); } #ifdef USE_MDM_MODEM if (!GPIO_IS_VALID(MDM_GPIO(MDM2AP_PBLRDY))) goto start_mdm_peripheral; for (i = 0; i < MDM_PBLRDY_CNT; i++) { pblrdy = gpio_get_value(MDM_GPIO(MDM2AP_PBLRDY)); if (pblrdy) break; usleep_range(5000, 5000); } pr_info("%s: id %d: pblrdy i:%d\n", __func__, mdm_drv->device_id, i); start_mdm_peripheral: #endif pr_err("%s %d\n", __func__,__LINE__); mdm_peripheral_connect(mdm_drv); msleep(200); }