diff options
Diffstat (limited to 'drivers/net/ipa/ipa_main.c')
-rw-r--r-- | drivers/net/ipa/ipa_main.c | 112 |
1 files changed, 90 insertions, 22 deletions
diff --git a/drivers/net/ipa/ipa_main.c b/drivers/net/ipa/ipa_main.c index 49537fccf6ad..4fb92f771974 100644 --- a/drivers/net/ipa/ipa_main.c +++ b/drivers/net/ipa/ipa_main.c @@ -82,6 +82,23 @@ #define IPA_XO_CLOCK_DIVIDER 192 /* 1 is subtracted where used */ /** + * enum ipa_firmware_loader: How GSI firmware gets loaded + * + * @IPA_LOADER_DEFER: System not ready; try again later + * @IPA_LOADER_SELF: AP loads GSI firmware + * @IPA_LOADER_MODEM: Modem loads GSI firmware, signals when done + * @IPA_LOADER_SKIP: Neither AP nor modem need to load GSI firmware + * @IPA_LOADER_INVALID: GSI firmware loader specification is invalid + */ +enum ipa_firmware_loader { + IPA_LOADER_DEFER, + IPA_LOADER_SELF, + IPA_LOADER_MODEM, + IPA_LOADER_SKIP, + IPA_LOADER_INVALID, +}; + +/** * ipa_setup() - Set up IPA hardware * @ipa: IPA pointer * @@ -646,6 +663,10 @@ static const struct of_device_id ipa_match[] = { .data = &ipa_data_v4_5, }, { + .compatible = "qcom,sm6350-ipa", + .data = &ipa_data_v4_7, + }, + { .compatible = "qcom,sm8350-ipa", .data = &ipa_data_v4_9, }, @@ -696,6 +717,50 @@ static void ipa_validate_build(void) BUILD_BUG_ON(!ipa_aggr_granularity_val(IPA_AGGR_GRANULARITY)); } +static enum ipa_firmware_loader ipa_firmware_loader(struct device *dev) +{ + bool modem_init; + const char *str; + int ret; + + /* Look up the old and new properties by name */ + modem_init = of_property_read_bool(dev->of_node, "modem-init"); + ret = of_property_read_string(dev->of_node, "qcom,gsi-loader", &str); + + /* If the new property doesn't exist, it's legacy behavior */ + if (ret == -EINVAL) { + if (modem_init) + return IPA_LOADER_MODEM; + goto out_self; + } + + /* Any other error on the new property means it's poorly defined */ + if (ret) + return IPA_LOADER_INVALID; + + /* New property value exists; if old one does too, that's invalid */ + if (modem_init) + return IPA_LOADER_INVALID; + + /* Modem loads GSI firmware for "modem" */ + if (!strcmp(str, "modem")) + return IPA_LOADER_MODEM; + + /* No GSI firmware load is needed for "skip" */ + if (!strcmp(str, "skip")) + return IPA_LOADER_SKIP; + + /* Any value other than "self" is an error */ + if (strcmp(str, "self")) + return IPA_LOADER_INVALID; +out_self: + /* We need Trust Zone to load firmware; make sure it's available */ + if (qcom_scm_is_available()) + return IPA_LOADER_SELF; + + return IPA_LOADER_DEFER; +} + /** * ipa_probe() - IPA platform driver probe function * @pdev: Platform device pointer @@ -722,9 +787,9 @@ static void ipa_validate_build(void) static int ipa_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; + enum ipa_firmware_loader loader; const struct ipa_data *data; struct ipa_power *power; - bool modem_init; struct ipa *ipa; int ret; @@ -742,11 +807,16 @@ static int ipa_probe(struct platform_device *pdev) return -EINVAL; } - /* If we need Trust Zone, make sure it's available */ - modem_init = of_property_read_bool(dev->of_node, "modem-init"); - if (!modem_init) - if (!qcom_scm_is_available()) - return -EPROBE_DEFER; + if (!data->modem_route_count) { + dev_err(dev, "modem_route_count cannot be zero\n"); + return -EINVAL; + } + + loader = ipa_firmware_loader(dev); + if (loader == IPA_LOADER_INVALID) + return -EINVAL; + if (loader == IPA_LOADER_DEFER) + return -EPROBE_DEFER; /* The clock and interconnects might not be ready when we're * probed, so might return -EPROBE_DEFER. @@ -766,6 +836,7 @@ static int ipa_probe(struct platform_device *pdev) dev_set_drvdata(dev, ipa); ipa->power = power; ipa->version = data->version; + ipa->modem_route_count = data->modem_route_count; init_completion(&ipa->completion); ret = ipa_reg_init(ipa); @@ -782,18 +853,15 @@ static int ipa_probe(struct platform_device *pdev) goto err_mem_exit; /* Result is a non-zero mask of endpoints that support filtering */ - ipa->filter_map = ipa_endpoint_init(ipa, data->endpoint_count, - data->endpoint_data); - if (!ipa->filter_map) { - ret = -EINVAL; + ret = ipa_endpoint_init(ipa, data->endpoint_count, data->endpoint_data); + if (ret) goto err_gsi_exit; - } ret = ipa_table_init(ipa); if (ret) goto err_endpoint_exit; - ret = ipa_smp2p_init(ipa, modem_init); + ret = ipa_smp2p_init(ipa, loader == IPA_LOADER_MODEM); if (ret) goto err_table_exit; @@ -808,20 +876,20 @@ static int ipa_probe(struct platform_device *pdev) dev_info(dev, "IPA driver initialized"); - /* If the modem is doing early initialization, it will trigger a - * call to ipa_setup() when it has finished. In that case we're - * done here. + /* If the modem is loading GSI firmware, it will trigger a call to + * ipa_setup() when it has finished. In that case we're done here. */ - if (modem_init) + if (loader == IPA_LOADER_MODEM) goto done; - /* Otherwise we need to load the firmware and have Trust Zone validate - * and install it. If that succeeds we can proceed with setup. - */ - ret = ipa_firmware_load(dev); - if (ret) - goto err_deconfig; + if (loader == IPA_LOADER_SELF) { + /* The AP is loading GSI firmware; do so now */ + ret = ipa_firmware_load(dev); + if (ret) + goto err_deconfig; + } /* Otherwise loader == IPA_LOADER_SKIP */ + /* GSI firmware is loaded; proceed to setup */ ret = ipa_setup(ipa); if (ret) goto err_deconfig; |