Loading Documentation/devicetree/bindings/arm/msm/mdm-modem.txt +1 −1 Original line number Diff line number Diff line Loading @@ -6,7 +6,7 @@ to be reset. Required Properties: - compatible: The bus devices need to be compatible with "qcom,ext-mdm9x55" "qcom,ext-mdm9x55", qcom,ext-sdx50m. Required named gpio properties: - qcom,mdm2ap-errfatal-gpio: gpio for the external modem to indicate to the apps processor Loading drivers/esoc/esoc-mdm-4x.c +131 −0 Original line number Diff line number Diff line Loading @@ -760,6 +760,27 @@ static int mdm_pinctrl_init(struct mdm_ctrl *mdm) return retval; } static void mdm_release_ipc_gpio(struct mdm_ctrl *mdm) { int i; if (!mdm) return; for (i = 0; i < NUM_GPIOS; ++i) if (gpio_is_valid(MDM_GPIO(mdm, i))) gpio_free(MDM_GPIO(mdm, i)); } static void mdm_free_irq(struct mdm_ctrl *mdm) { if (!mdm) return; free_irq(mdm->errfatal_irq, mdm); free_irq(mdm->status_irq, mdm); } static int mdm9x55_setup_hw(struct mdm_ctrl *mdm, const struct mdm_ops *ops, struct platform_device *pdev) Loading Loading @@ -851,6 +872,108 @@ static int mdm9x55_setup_hw(struct mdm_ctrl *mdm, return 0; } static int sdx50m_setup_hw(struct mdm_ctrl *mdm, const struct mdm_ops *ops, struct platform_device *pdev) { int ret; struct device_node *node; struct esoc_clink *esoc; const struct esoc_clink_ops *const clink_ops = ops->clink_ops; const struct mdm_pon_ops *pon_ops = ops->pon_ops; mdm->dev = &pdev->dev; mdm->pon_ops = pon_ops; node = pdev->dev.of_node; esoc = devm_kzalloc(mdm->dev, sizeof(*esoc), GFP_KERNEL); if (IS_ERR_OR_NULL(esoc)) { dev_err(mdm->dev, "cannot allocate esoc device\n"); return PTR_ERR(esoc); } esoc->pdev = pdev; mdm->mdm_queue = alloc_workqueue("mdm_queue", 0, 0); if (!mdm->mdm_queue) { dev_err(mdm->dev, "could not create mdm_queue\n"); return -ENOMEM; } mdm->irq_mask = 0; mdm->ready = false; ret = mdm_dt_parse_gpios(mdm); if (ret) { dev_err(mdm->dev, "Failed to parse DT gpios\n"); goto err_destroy_wrkq; } ret = mdm_pon_dt_init(mdm); if (ret) { dev_err(mdm->dev, "Failed to parse PON DT gpio\n"); goto err_destroy_wrkq; } ret = mdm_pinctrl_init(mdm); if (ret) { dev_err(mdm->dev, "Failed to init pinctrl\n"); goto err_destroy_wrkq; } ret = mdm_pon_setup(mdm); if (ret) { dev_err(mdm->dev, "Failed to setup PON\n"); goto err_destroy_wrkq; } ret = mdm_configure_ipc(mdm, pdev); if (ret) { dev_err(mdm->dev, "Failed to configure the ipc\n"); goto err_release_ipc; } esoc->name = SDX50M_LABEL; mdm->dual_interface = of_property_read_bool(node, "qcom,mdm-dual-link"); esoc->link_name = SDX50M_PCIE; ret = of_property_read_string(node, "qcom,mdm-link-info", &esoc->link_info); if (ret) dev_info(mdm->dev, "esoc link info missing\n"); esoc->clink_ops = clink_ops; esoc->parent = mdm->dev; esoc->owner = THIS_MODULE; esoc->np = pdev->dev.of_node; set_esoc_clink_data(esoc, mdm); ret = esoc_clink_register(esoc); if (ret) { dev_err(mdm->dev, "esoc registration failed\n"); goto err_free_irq; } dev_dbg(mdm->dev, "esoc registration done\n"); init_completion(&mdm->debug_done); INIT_WORK(&mdm->mdm_status_work, mdm_status_fn); INIT_WORK(&mdm->restart_reason_work, mdm_get_restart_reason); INIT_DELAYED_WORK(&mdm->mdm2ap_status_check_work, mdm2ap_status_check); mdm->get_restart_reason = false; mdm->debug_fail = false; mdm->esoc = esoc; mdm->init = 0; return 0; err_free_irq: mdm_free_irq(mdm); err_release_ipc: mdm_release_ipc_gpio(mdm); err_destroy_wrkq: destroy_workqueue(mdm->mdm_queue); return ret; } static struct esoc_clink_ops mdm_cops = { .cmd_exe = mdm_cmd_exe, .get_status = mdm_get_status, Loading @@ -864,9 +987,17 @@ static struct mdm_ops mdm9x55_ops = { .pon_ops = &mdm9x55_pon_ops, }; static struct mdm_ops sdx50m_ops = { .clink_ops = &mdm_cops, .config_hw = sdx50m_setup_hw, .pon_ops = &sdx50m_pon_ops, }; static const struct of_device_id mdm_dt_match[] = { { .compatible = "qcom,ext-mdm9x55", .data = &mdm9x55_ops, }, { .compatible = "qcom,ext-sdx50m", .data = &sdx50m_ops, }, {}, }; MODULE_DEVICE_TABLE(of, mdm_dt_match); Loading drivers/esoc/esoc-mdm-drv.c +4 −0 Original line number Diff line number Diff line Loading @@ -301,6 +301,10 @@ static struct esoc_compat compat_table[] = { .name = "MDM9x55", .data = NULL, }, { .name = "SDX50M", .data = NULL, }, }; static struct esoc_drv esoc_ssr_drv = { Loading drivers/esoc/esoc-mdm-pon.c +89 −0 Original line number Diff line number Diff line Loading @@ -41,6 +41,34 @@ static int mdm9x55_toggle_soft_reset(struct mdm_ctrl *mdm, bool atomic) return 0; } /* This function can be called from atomic context. */ static int sdx50m_toggle_soft_reset(struct mdm_ctrl *mdm, bool atomic) { int soft_reset_direction_assert = 0, soft_reset_direction_de_assert = 1; if (mdm->soft_reset_inverted) { soft_reset_direction_assert = 1; soft_reset_direction_de_assert = 0; } gpio_direction_output(MDM_GPIO(mdm, AP2MDM_SOFT_RESET), soft_reset_direction_assert); /* * Allow PS hold assert to be detected */ if (!atomic) usleep_range(203000, 300000); else /* * The flow falls through this path as a part of the * panic handler, which has to executed atomically. */ mdelay(203); gpio_direction_output(MDM_GPIO(mdm, AP2MDM_SOFT_RESET), soft_reset_direction_de_assert); return 0; } static int mdm4x_do_first_power_on(struct mdm_ctrl *mdm) { int i; Loading Loading @@ -101,6 +129,26 @@ static int mdm9x55_power_down(struct mdm_ctrl *mdm) return 0; } static int sdx50m_power_down(struct mdm_ctrl *mdm) { struct device *dev = mdm->dev; int soft_reset_direction = mdm->soft_reset_inverted ? 1 : 0; /* Assert the soft reset line whether mdm2ap_status went low or not */ gpio_direction_output(MDM_GPIO(mdm, AP2MDM_SOFT_RESET), soft_reset_direction); dev_dbg(dev, "Doing a hard reset\n"); gpio_direction_output(MDM_GPIO(mdm, AP2MDM_SOFT_RESET), soft_reset_direction); /* * Currently, there is a debounce timer on the charm PMIC. It is * necessary to hold the PMIC RESET low for 406ms * for the reset to fully take place. Sleep here to ensure the * reset has occurred before the function exits. */ msleep(406); return 0; } static void mdm9x55_cold_reset(struct mdm_ctrl *mdm) { dev_dbg(mdm->dev, "Triggering mdm cold reset"); Loading @@ -117,6 +165,22 @@ static void mdm9x55_cold_reset(struct mdm_ctrl *mdm) !mdm->soft_reset_inverted); } static void sdx50m_cold_reset(struct mdm_ctrl *mdm) { dev_dbg(mdm->dev, "Triggering mdm cold reset"); gpio_direction_output(MDM_GPIO(mdm, AP2MDM_SOFT_RESET), !!mdm->soft_reset_inverted); /* * The function is executed as a part of the atomic reboot handler. * Hence, go with a busy loop instead of sleep. */ mdelay(334); gpio_direction_output(MDM_GPIO(mdm, AP2MDM_SOFT_RESET), !mdm->soft_reset_inverted); } static int mdm9x55_pon_dt_init(struct mdm_ctrl *mdm) { int val; Loading @@ -140,6 +204,23 @@ static int mdm9x55_pon_dt_init(struct mdm_ctrl *mdm) return -EIO; } static int mdm4x_pon_dt_init(struct mdm_ctrl *mdm) { int val; struct device_node *node = mdm->dev->of_node; enum of_gpio_flags flags = OF_GPIO_ACTIVE_LOW; val = of_get_named_gpio_flags(node, "qcom,ap2mdm-soft-reset-gpio", 0, &flags); if (val >= 0) { MDM_GPIO(mdm, AP2MDM_SOFT_RESET) = val; if (flags & OF_GPIO_ACTIVE_LOW) mdm->soft_reset_inverted = 1; return 0; } else return -EIO; } static int mdm4x_pon_setup(struct mdm_ctrl *mdm) { struct device *dev = mdm->dev; Loading @@ -163,3 +244,11 @@ struct mdm_pon_ops mdm9x55_pon_ops = { .setup = mdm4x_pon_setup, }; struct mdm_pon_ops sdx50m_pon_ops = { .pon = mdm4x_do_first_power_on, .soft_reset = sdx50m_toggle_soft_reset, .poff_force = sdx50m_power_down, .cold_reset = sdx50m_cold_reset, .dt_init = mdm4x_pon_dt_init, .setup = mdm4x_pon_setup, }; drivers/esoc/esoc-mdm.h +3 −0 Original line number Diff line number Diff line Loading @@ -29,6 +29,8 @@ #define MDM_GPIO(mdm, i) (mdm->gpios[i]) #define MDM9x55_LABEL "MDM9x55" #define MDM9x55_PCIE "PCIe" #define SDX50M_LABEL "SDX50M" #define SDX50M_PCIE "PCIe" #define MDM2AP_STATUS_TIMEOUT_MS 120000L #define MDM_MODEM_TIMEOUT 3000 #define DEF_RAMDUMP_TIMEOUT 120000 Loading Loading @@ -146,4 +148,5 @@ static inline int mdm_pon_setup(struct mdm_ctrl *mdm) } extern struct mdm_pon_ops mdm9x55_pon_ops; extern struct mdm_pon_ops sdx50m_pon_ops; #endif Loading
Documentation/devicetree/bindings/arm/msm/mdm-modem.txt +1 −1 Original line number Diff line number Diff line Loading @@ -6,7 +6,7 @@ to be reset. Required Properties: - compatible: The bus devices need to be compatible with "qcom,ext-mdm9x55" "qcom,ext-mdm9x55", qcom,ext-sdx50m. Required named gpio properties: - qcom,mdm2ap-errfatal-gpio: gpio for the external modem to indicate to the apps processor Loading
drivers/esoc/esoc-mdm-4x.c +131 −0 Original line number Diff line number Diff line Loading @@ -760,6 +760,27 @@ static int mdm_pinctrl_init(struct mdm_ctrl *mdm) return retval; } static void mdm_release_ipc_gpio(struct mdm_ctrl *mdm) { int i; if (!mdm) return; for (i = 0; i < NUM_GPIOS; ++i) if (gpio_is_valid(MDM_GPIO(mdm, i))) gpio_free(MDM_GPIO(mdm, i)); } static void mdm_free_irq(struct mdm_ctrl *mdm) { if (!mdm) return; free_irq(mdm->errfatal_irq, mdm); free_irq(mdm->status_irq, mdm); } static int mdm9x55_setup_hw(struct mdm_ctrl *mdm, const struct mdm_ops *ops, struct platform_device *pdev) Loading Loading @@ -851,6 +872,108 @@ static int mdm9x55_setup_hw(struct mdm_ctrl *mdm, return 0; } static int sdx50m_setup_hw(struct mdm_ctrl *mdm, const struct mdm_ops *ops, struct platform_device *pdev) { int ret; struct device_node *node; struct esoc_clink *esoc; const struct esoc_clink_ops *const clink_ops = ops->clink_ops; const struct mdm_pon_ops *pon_ops = ops->pon_ops; mdm->dev = &pdev->dev; mdm->pon_ops = pon_ops; node = pdev->dev.of_node; esoc = devm_kzalloc(mdm->dev, sizeof(*esoc), GFP_KERNEL); if (IS_ERR_OR_NULL(esoc)) { dev_err(mdm->dev, "cannot allocate esoc device\n"); return PTR_ERR(esoc); } esoc->pdev = pdev; mdm->mdm_queue = alloc_workqueue("mdm_queue", 0, 0); if (!mdm->mdm_queue) { dev_err(mdm->dev, "could not create mdm_queue\n"); return -ENOMEM; } mdm->irq_mask = 0; mdm->ready = false; ret = mdm_dt_parse_gpios(mdm); if (ret) { dev_err(mdm->dev, "Failed to parse DT gpios\n"); goto err_destroy_wrkq; } ret = mdm_pon_dt_init(mdm); if (ret) { dev_err(mdm->dev, "Failed to parse PON DT gpio\n"); goto err_destroy_wrkq; } ret = mdm_pinctrl_init(mdm); if (ret) { dev_err(mdm->dev, "Failed to init pinctrl\n"); goto err_destroy_wrkq; } ret = mdm_pon_setup(mdm); if (ret) { dev_err(mdm->dev, "Failed to setup PON\n"); goto err_destroy_wrkq; } ret = mdm_configure_ipc(mdm, pdev); if (ret) { dev_err(mdm->dev, "Failed to configure the ipc\n"); goto err_release_ipc; } esoc->name = SDX50M_LABEL; mdm->dual_interface = of_property_read_bool(node, "qcom,mdm-dual-link"); esoc->link_name = SDX50M_PCIE; ret = of_property_read_string(node, "qcom,mdm-link-info", &esoc->link_info); if (ret) dev_info(mdm->dev, "esoc link info missing\n"); esoc->clink_ops = clink_ops; esoc->parent = mdm->dev; esoc->owner = THIS_MODULE; esoc->np = pdev->dev.of_node; set_esoc_clink_data(esoc, mdm); ret = esoc_clink_register(esoc); if (ret) { dev_err(mdm->dev, "esoc registration failed\n"); goto err_free_irq; } dev_dbg(mdm->dev, "esoc registration done\n"); init_completion(&mdm->debug_done); INIT_WORK(&mdm->mdm_status_work, mdm_status_fn); INIT_WORK(&mdm->restart_reason_work, mdm_get_restart_reason); INIT_DELAYED_WORK(&mdm->mdm2ap_status_check_work, mdm2ap_status_check); mdm->get_restart_reason = false; mdm->debug_fail = false; mdm->esoc = esoc; mdm->init = 0; return 0; err_free_irq: mdm_free_irq(mdm); err_release_ipc: mdm_release_ipc_gpio(mdm); err_destroy_wrkq: destroy_workqueue(mdm->mdm_queue); return ret; } static struct esoc_clink_ops mdm_cops = { .cmd_exe = mdm_cmd_exe, .get_status = mdm_get_status, Loading @@ -864,9 +987,17 @@ static struct mdm_ops mdm9x55_ops = { .pon_ops = &mdm9x55_pon_ops, }; static struct mdm_ops sdx50m_ops = { .clink_ops = &mdm_cops, .config_hw = sdx50m_setup_hw, .pon_ops = &sdx50m_pon_ops, }; static const struct of_device_id mdm_dt_match[] = { { .compatible = "qcom,ext-mdm9x55", .data = &mdm9x55_ops, }, { .compatible = "qcom,ext-sdx50m", .data = &sdx50m_ops, }, {}, }; MODULE_DEVICE_TABLE(of, mdm_dt_match); Loading
drivers/esoc/esoc-mdm-drv.c +4 −0 Original line number Diff line number Diff line Loading @@ -301,6 +301,10 @@ static struct esoc_compat compat_table[] = { .name = "MDM9x55", .data = NULL, }, { .name = "SDX50M", .data = NULL, }, }; static struct esoc_drv esoc_ssr_drv = { Loading
drivers/esoc/esoc-mdm-pon.c +89 −0 Original line number Diff line number Diff line Loading @@ -41,6 +41,34 @@ static int mdm9x55_toggle_soft_reset(struct mdm_ctrl *mdm, bool atomic) return 0; } /* This function can be called from atomic context. */ static int sdx50m_toggle_soft_reset(struct mdm_ctrl *mdm, bool atomic) { int soft_reset_direction_assert = 0, soft_reset_direction_de_assert = 1; if (mdm->soft_reset_inverted) { soft_reset_direction_assert = 1; soft_reset_direction_de_assert = 0; } gpio_direction_output(MDM_GPIO(mdm, AP2MDM_SOFT_RESET), soft_reset_direction_assert); /* * Allow PS hold assert to be detected */ if (!atomic) usleep_range(203000, 300000); else /* * The flow falls through this path as a part of the * panic handler, which has to executed atomically. */ mdelay(203); gpio_direction_output(MDM_GPIO(mdm, AP2MDM_SOFT_RESET), soft_reset_direction_de_assert); return 0; } static int mdm4x_do_first_power_on(struct mdm_ctrl *mdm) { int i; Loading Loading @@ -101,6 +129,26 @@ static int mdm9x55_power_down(struct mdm_ctrl *mdm) return 0; } static int sdx50m_power_down(struct mdm_ctrl *mdm) { struct device *dev = mdm->dev; int soft_reset_direction = mdm->soft_reset_inverted ? 1 : 0; /* Assert the soft reset line whether mdm2ap_status went low or not */ gpio_direction_output(MDM_GPIO(mdm, AP2MDM_SOFT_RESET), soft_reset_direction); dev_dbg(dev, "Doing a hard reset\n"); gpio_direction_output(MDM_GPIO(mdm, AP2MDM_SOFT_RESET), soft_reset_direction); /* * Currently, there is a debounce timer on the charm PMIC. It is * necessary to hold the PMIC RESET low for 406ms * for the reset to fully take place. Sleep here to ensure the * reset has occurred before the function exits. */ msleep(406); return 0; } static void mdm9x55_cold_reset(struct mdm_ctrl *mdm) { dev_dbg(mdm->dev, "Triggering mdm cold reset"); Loading @@ -117,6 +165,22 @@ static void mdm9x55_cold_reset(struct mdm_ctrl *mdm) !mdm->soft_reset_inverted); } static void sdx50m_cold_reset(struct mdm_ctrl *mdm) { dev_dbg(mdm->dev, "Triggering mdm cold reset"); gpio_direction_output(MDM_GPIO(mdm, AP2MDM_SOFT_RESET), !!mdm->soft_reset_inverted); /* * The function is executed as a part of the atomic reboot handler. * Hence, go with a busy loop instead of sleep. */ mdelay(334); gpio_direction_output(MDM_GPIO(mdm, AP2MDM_SOFT_RESET), !mdm->soft_reset_inverted); } static int mdm9x55_pon_dt_init(struct mdm_ctrl *mdm) { int val; Loading @@ -140,6 +204,23 @@ static int mdm9x55_pon_dt_init(struct mdm_ctrl *mdm) return -EIO; } static int mdm4x_pon_dt_init(struct mdm_ctrl *mdm) { int val; struct device_node *node = mdm->dev->of_node; enum of_gpio_flags flags = OF_GPIO_ACTIVE_LOW; val = of_get_named_gpio_flags(node, "qcom,ap2mdm-soft-reset-gpio", 0, &flags); if (val >= 0) { MDM_GPIO(mdm, AP2MDM_SOFT_RESET) = val; if (flags & OF_GPIO_ACTIVE_LOW) mdm->soft_reset_inverted = 1; return 0; } else return -EIO; } static int mdm4x_pon_setup(struct mdm_ctrl *mdm) { struct device *dev = mdm->dev; Loading @@ -163,3 +244,11 @@ struct mdm_pon_ops mdm9x55_pon_ops = { .setup = mdm4x_pon_setup, }; struct mdm_pon_ops sdx50m_pon_ops = { .pon = mdm4x_do_first_power_on, .soft_reset = sdx50m_toggle_soft_reset, .poff_force = sdx50m_power_down, .cold_reset = sdx50m_cold_reset, .dt_init = mdm4x_pon_dt_init, .setup = mdm4x_pon_setup, };
drivers/esoc/esoc-mdm.h +3 −0 Original line number Diff line number Diff line Loading @@ -29,6 +29,8 @@ #define MDM_GPIO(mdm, i) (mdm->gpios[i]) #define MDM9x55_LABEL "MDM9x55" #define MDM9x55_PCIE "PCIe" #define SDX50M_LABEL "SDX50M" #define SDX50M_PCIE "PCIe" #define MDM2AP_STATUS_TIMEOUT_MS 120000L #define MDM_MODEM_TIMEOUT 3000 #define DEF_RAMDUMP_TIMEOUT 120000 Loading Loading @@ -146,4 +148,5 @@ static inline int mdm_pon_setup(struct mdm_ctrl *mdm) } extern struct mdm_pon_ops mdm9x55_pon_ops; extern struct mdm_pon_ops sdx50m_pon_ops; #endif