diff --git a/drivers/net/wireless/cnss2/bus.c b/drivers/net/wireless/cnss2/bus.c index 211451e536ee..4a42a75f8b8f 100644 --- a/drivers/net/wireless/cnss2/bus.c +++ b/drivers/net/wireless/cnss2/bus.c @@ -19,18 +19,39 @@ enum cnss_dev_bus_type cnss_get_dev_bus_type(struct device *dev) return CNSS_BUS_NONE; } -enum cnss_dev_bus_type cnss_get_bus_type(unsigned long device_id) +enum cnss_dev_bus_type cnss_get_bus_type(struct cnss_plat_data *plat_priv) { - switch (device_id) { + int ret; + struct device *dev; + enum cnss_dev_bus_type bus_type = CNSS_BUS_NONE; + + if (plat_priv->is_converged_dt) { + dev = &plat_priv->plat_dev->dev; + ret = of_property_read_u32(dev->of_node, "qcom,bus-type", + &bus_type); + if (!ret && bus_type <= CNSS_BUS_USB) + cnss_pr_dbg("Got bus type[%u] from dt\n", bus_type); + else + cnss_pr_err("No bus type for converged dt\n"); + + return bus_type; + } + + /* Get bus type according to device id if it's not converged DT */ + switch (plat_priv->device_id) { case QCA6174_DEVICE_ID: case QCA6290_DEVICE_ID: case QCA6390_DEVICE_ID: + case QCN7605_DEVICE_ID: case QCA6490_DEVICE_ID: - return CNSS_BUS_PCI; + bus_type = CNSS_BUS_PCI; + break; default: - cnss_pr_err("Unknown device_id: 0x%lx\n", device_id); - return CNSS_BUS_NONE; + cnss_pr_err("Unknown device: 0x%lx\n", plat_priv->device_id); + break; } + + return bus_type; } void *cnss_bus_dev_to_bus_priv(struct device *dev) @@ -544,3 +565,26 @@ int cnss_bus_get_iova_ipa(struct cnss_plat_data *plat_priv, u64 *addr, return -EINVAL; } } + +int cnss_bus_get_msi_assignment(struct cnss_plat_data *plat_priv, + char *msi_name, + int *num_vectors, + u32 *user_base_data, + u32 *base_vector) +{ + if (!plat_priv) + return -ENODEV; + + switch (plat_priv->bus_type) { + case CNSS_BUS_PCI: + return cnss_pci_get_user_msi_assignment(plat_priv->bus_priv, + msi_name, + num_vectors, + user_base_data, + base_vector); + default: + cnss_pr_err("Unsupported bus type: %d\n", + plat_priv->bus_type); + return -EINVAL; + } +} diff --git a/drivers/net/wireless/cnss2/bus.h b/drivers/net/wireless/cnss2/bus.h index 0673615d9fba..6c0cec926ad9 100644 --- a/drivers/net/wireless/cnss2/bus.h +++ b/drivers/net/wireless/cnss2/bus.h @@ -15,13 +15,15 @@ #define QCA6290_DEVICE_ID 0x1100 #define QCA6390_VENDOR_ID 0x17CB #define QCA6390_DEVICE_ID 0x1101 +#define QCN7605_VENDOR_ID 0x17CB +#define QCN7605_DEVICE_ID 0x1102 #define QCA6490_VENDOR_ID 0x17CB #define QCA6490_DEVICE_ID 0x1103 #define WCN7850_VENDOR_ID 0x17CB #define WCN7850_DEVICE_ID 0x1107 enum cnss_dev_bus_type cnss_get_dev_bus_type(struct device *dev); -enum cnss_dev_bus_type cnss_get_bus_type(unsigned long device_id); +enum cnss_dev_bus_type cnss_get_bus_type(struct cnss_plat_data *plat_priv); void *cnss_bus_dev_to_bus_priv(struct device *dev); struct cnss_plat_data *cnss_bus_dev_to_plat_priv(struct device *dev); int cnss_bus_init(struct cnss_plat_data *plat_priv); @@ -62,4 +64,9 @@ int cnss_bus_debug_reg_write(struct cnss_plat_data *plat_priv, u32 offset, int cnss_bus_get_iova(struct cnss_plat_data *plat_priv, u64 *addr, u64 *size); int cnss_bus_get_iova_ipa(struct cnss_plat_data *plat_priv, u64 *addr, u64 *size); +int cnss_bus_get_msi_assignment(struct cnss_plat_data *plat_priv, + char *msi_name, + int *num_vectors, + u32 *user_base_data, + u32 *base_vector); #endif /* _CNSS_BUS_H */ diff --git a/drivers/net/wireless/cnss2/main.c b/drivers/net/wireless/cnss2/main.c index c20a0f305a21..111dd924b918 100644 --- a/drivers/net/wireless/cnss2/main.c +++ b/drivers/net/wireless/cnss2/main.c @@ -301,6 +301,9 @@ int cnss_wlan_enable(struct device *dev, if (mode == CNSS_WALTEST || mode == CNSS_CCPM) goto skip_cfg; + if (plat_priv->device_id == QCN7605_DEVICE_ID) + config->send_msi_ce = true; + ret = cnss_wlfw_wlan_cfg_send_sync(plat_priv, config, host_version); if (ret) goto out; @@ -435,11 +438,17 @@ static int cnss_fw_mem_ready_hdlr(struct cnss_plat_data *plat_priv) cnss_wlfw_bdf_dnld_send_sync(plat_priv, CNSS_BDF_REGDB); + if (plat_priv->device_id == QCN7605_DEVICE_ID) + plat_priv->ctrl_params.bdf_type = CNSS_BDF_BIN; + ret = cnss_wlfw_bdf_dnld_send_sync(plat_priv, plat_priv->ctrl_params.bdf_type); if (ret) goto out; + if (plat_priv->device_id == QCN7605_DEVICE_ID) + return 0; + ret = cnss_bus_load_m3(plat_priv); if (ret) goto out; @@ -1596,8 +1605,13 @@ static int cnss_cold_boot_cal_done_hdlr(struct cnss_plat_data *plat_priv, cnss_wlfw_wlan_mode_send_sync(plat_priv, CNSS_OFF); cnss_bus_free_qdss_mem(plat_priv); cnss_release_antenna_sharing(plat_priv); + if (plat_priv->device_id == QCN7605_DEVICE_ID) + goto skip_shutdown; + cnss_bus_dev_shutdown(plat_priv); msleep(COLD_BOOT_CAL_SHUTDOWN_DELAY_MS); + +skip_shutdown: complete(&plat_priv->cal_complete); clear_bit(CNSS_IN_COLD_BOOT_CAL, &plat_priv->driver_state); set_bit(CNSS_COLD_BOOT_CAL_DONE, &plat_priv->driver_state); @@ -2183,7 +2197,7 @@ static int cnss_register_ramdump_v1(struct cnss_plat_data *plat_priv) dev = &plat_priv->plat_dev->dev; ramdump_info = &plat_priv->ramdump_info; - if (of_property_read_u32(dev->of_node, "qcom,wlan-ramdump-dynamic", + if (of_property_read_u32(plat_priv->dev_node, "qcom,wlan-ramdump-dynamic", &ramdump_size) == 0) { ramdump_info->ramdump_va = dma_alloc_coherent(dev, ramdump_size, @@ -2261,13 +2275,13 @@ static int cnss_register_ramdump_v2(struct cnss_plat_data *plat_priv) struct cnss_ramdump_info_v2 *info_v2; struct cnss_dump_data *dump_data; struct msm_dump_entry dump_entry; - struct device *dev = &plat_priv->plat_dev->dev; u32 ramdump_size = 0; info_v2 = &plat_priv->ramdump_info_v2; dump_data = &info_v2->dump_data; - if (of_property_read_u32(dev->of_node, "qcom,wlan-ramdump-dynamic", + if (of_property_read_u32(plat_priv->dev_node, + "qcom,wlan-ramdump-dynamic", &ramdump_size) == 0) info_v2->ramdump_size = ramdump_size; @@ -2334,6 +2348,7 @@ int cnss_register_ramdump(struct cnss_plat_data *plat_priv) break; case QCA6290_DEVICE_ID: case QCA6390_DEVICE_ID: + case QCN7605_DEVICE_ID: case QCA6490_DEVICE_ID: case WCN7850_DEVICE_ID: ret = cnss_register_ramdump_v2(plat_priv); @@ -2354,6 +2369,7 @@ void cnss_unregister_ramdump(struct cnss_plat_data *plat_priv) break; case QCA6290_DEVICE_ID: case QCA6390_DEVICE_ID: + case QCN7605_DEVICE_ID: case QCA6490_DEVICE_ID: case WCN7850_DEVICE_ID: cnss_unregister_ramdump_v2(plat_priv); @@ -2477,7 +2493,7 @@ int cnss_minidump_remove_region(struct cnss_plat_data *plat_priv, * For different interconnect path configured in device tree setup voting data * for list of bandwidth requirements. * - * Result: 0 for success. -EINVAL if not configured + * Result: 0 for success. -ENOMEM if cannot allocate memory */ static int cnss_register_bus_scale(struct cnss_plat_data *plat_priv) { @@ -2491,8 +2507,8 @@ static int cnss_register_bus_scale(struct cnss_plat_data *plat_priv) "qcom,icc-path-count", &plat_priv->icc.path_count); if (ret) { - cnss_pr_err("Platform Bus Interconnect path not configured\n"); - return -EINVAL; + cnss_pr_dbg("Platform Bus Interconnect path not configured\n"); + return 0; } ret = of_property_read_u32(plat_priv->plat_dev->dev.of_node, "qcom,bus-bw-cfg-count", @@ -2967,6 +2983,7 @@ static const struct platform_device_id cnss_platform_id_table[] = { { .name = "qca6390", .driver_data = QCA6390_DEVICE_ID, }, { .name = "qca6490", .driver_data = QCA6490_DEVICE_ID, }, { .name = "wcn7850", .driver_data = WCN7850_DEVICE_ID, }, + { .name = "qcaconv", .driver_data = 0}, { }, }; @@ -2986,6 +3003,9 @@ static const struct of_device_id cnss_of_match_table[] = { { .compatible = "qcom,cnss-wcn7850", .data = (void *)&cnss_platform_id_table[4]}, + { + .compatible = "qcom,cnss-qca-converged", + .data = (void *)&cnss_platform_id_table[5]}, { }, }; MODULE_DEVICE_TABLE(of, cnss_of_match_table); @@ -2997,6 +3017,12 @@ cnss_use_nv_mac(struct cnss_plat_data *plat_priv) "use-nv-mac"); } +static inline bool +cnss_is_converged_dt(struct cnss_plat_data *plat_priv) +{ + return of_property_read_bool(plat_priv->plat_dev->dev.of_node, + "qcom,converged-dt"); +} static int cnss_probe(struct platform_device *plat_dev) { int ret = 0; @@ -3028,7 +3054,9 @@ static int cnss_probe(struct platform_device *plat_dev) plat_priv->plat_dev = plat_dev; plat_priv->device_id = device_id->driver_data; - plat_priv->bus_type = cnss_get_bus_type(plat_priv->device_id); + plat_priv->is_converged_dt = cnss_is_converged_dt(plat_priv); + plat_priv->dev_node = plat_priv->plat_dev->dev.of_node; + plat_priv->bus_type = cnss_get_bus_type(plat_priv); plat_priv->use_nv_mac = cnss_use_nv_mac(plat_priv); plat_priv->use_fw_path_with_prefix = cnss_use_fw_path_with_prefix(plat_priv); diff --git a/drivers/net/wireless/cnss2/main.h b/drivers/net/wireless/cnss2/main.h index e4be44a44e84..4c0e2e9ee098 100644 --- a/drivers/net/wireless/cnss2/main.h +++ b/drivers/net/wireless/cnss2/main.h @@ -54,6 +54,7 @@ enum cnss_dev_bus_type { CNSS_BUS_NONE = -1, CNSS_BUS_PCI, + CNSS_BUS_USB, }; struct cnss_vreg_cfg { @@ -493,6 +494,8 @@ struct cnss_plat_data { struct cnss_dms_data dms; int power_up_error; u32 hw_trc_override; + u32 is_converged_dt; + struct device_node *dev_node; }; #ifdef CONFIG_ARCH_QCOM @@ -558,5 +561,5 @@ int cnss_enable_int_pow_amp_vreg(struct cnss_plat_data *plat_priv); int cnss_get_tcs_info(struct cnss_plat_data *plat_priv); unsigned int cnss_get_timeout(struct cnss_plat_data *plat_priv, enum cnss_timeout_type); - +int cnss_dev_specific_power_on(struct cnss_plat_data *plat_priv); #endif /* _CNSS_MAIN_H */ diff --git a/drivers/net/wireless/cnss2/pci.c b/drivers/net/wireless/cnss2/pci.c index def4116e18d8..a0b3ad1d1855 100644 --- a/drivers/net/wireless/cnss2/pci.c +++ b/drivers/net/wireless/cnss2/pci.c @@ -7,6 +7,7 @@ #include #include #include +#include #include #include #include @@ -43,6 +44,7 @@ #define QCA6390_PATH_PREFIX "qca6390/" #define QCA6490_PATH_PREFIX "qca6490/" #define WCN7850_PATH_PREFIX "wcn7850/" +#define QCN7605_PATH_PREFIX "qcn7605/" #define DEFAULT_M3_FILE_NAME "m3.bin" #define DEFAULT_FW_FILE_NAME "amss.bin" #define FW_V2_FILE_NAME "amss20.bin" @@ -2594,6 +2596,7 @@ int cnss_pci_dev_powerup(struct cnss_pci_data *pci_priv) break; case QCA6290_DEVICE_ID: case QCA6390_DEVICE_ID: + case QCN7605_DEVICE_ID: case QCA6490_DEVICE_ID: case WCN7850_DEVICE_ID: ret = cnss_qca6290_powerup(pci_priv); @@ -2622,6 +2625,7 @@ int cnss_pci_dev_shutdown(struct cnss_pci_data *pci_priv) break; case QCA6290_DEVICE_ID: case QCA6390_DEVICE_ID: + case QCN7605_DEVICE_ID: case QCA6490_DEVICE_ID: case WCN7850_DEVICE_ID: ret = cnss_qca6290_shutdown(pci_priv); @@ -2650,6 +2654,7 @@ int cnss_pci_dev_crash_shutdown(struct cnss_pci_data *pci_priv) break; case QCA6290_DEVICE_ID: case QCA6390_DEVICE_ID: + case QCN7605_DEVICE_ID: case QCA6490_DEVICE_ID: case WCN7850_DEVICE_ID: cnss_qca6290_crash_shutdown(pci_priv); @@ -2678,6 +2683,7 @@ int cnss_pci_dev_ramdump(struct cnss_pci_data *pci_priv) break; case QCA6290_DEVICE_ID: case QCA6390_DEVICE_ID: + case QCN7605_DEVICE_ID: case QCA6490_DEVICE_ID: case WCN7850_DEVICE_ID: ret = cnss_qca6290_ramdump(pci_priv); @@ -3980,18 +3986,24 @@ static int cnss_pci_init_smmu(struct cnss_pci_data *pci_priv) struct pci_dev *pci_dev = pci_priv->pci_dev; struct cnss_plat_data *plat_priv = pci_priv->plat_priv; struct device_node *of_node; + struct resource res_tmp; struct resource *res; const char *iommu_dma_type; u32 addr_win[2]; int ret = 0; + int index; of_node = of_parse_phandle(pci_dev->dev.of_node, "qcom,iommu-group", 0); - if (!of_node) + if (!of_node) { + cnss_pr_err("No iommu group configuration\n"); return ret; + } cnss_pr_dbg("Initializing SMMU\n"); pci_priv->iommu_domain = iommu_get_domain_for_dev(&pci_dev->dev); + if (!pci_priv->iommu_domain) + cnss_pr_err("No iommu domain found\n"); ret = of_property_read_string(of_node, "qcom,iommu-dma", &iommu_dma_type); if (!ret && !strcmp("fastmap", iommu_dma_type)) { @@ -4005,8 +4017,7 @@ static int cnss_pci_init_smmu(struct cnss_pci_data *pci_priv) addr_win, ARRAY_SIZE(addr_win)); if (ret) { cnss_pr_err("Invalid SMMU size window, err = %d\n", ret); - of_node_put(of_node); - return ret; + goto out; } pci_priv->smmu_iova_start = addr_win[0]; @@ -4015,8 +4026,28 @@ static int cnss_pci_init_smmu(struct cnss_pci_data *pci_priv) &pci_priv->smmu_iova_start, pci_priv->smmu_iova_len); - res = platform_get_resource_byname(plat_priv->plat_dev, IORESOURCE_MEM, - "smmu_iova_ipa"); + if (plat_priv->is_converged_dt) { + index = of_property_match_string(plat_priv->dev_node, "reg-names", + "smmu_iova_ipa"); + if (index < 0) { + cnss_pr_err("failed to find reg smmu_iova_ipa\n"); + ret = index; + goto out; + } + + ret = of_address_to_resource(plat_priv->dev_node, index, &res_tmp); + if (ret) { + cnss_pr_err("failed to get resource\n"); + goto out; + } + + res = &res_tmp; + } else { + res = platform_get_resource_byname(plat_priv->plat_dev, + IORESOURCE_MEM, + "smmu_iova_ipa"); + } + if (res) { pci_priv->smmu_iova_ipa_start = res->start; pci_priv->smmu_iova_ipa_current = res->start; @@ -4029,10 +4060,10 @@ static int cnss_pci_init_smmu(struct cnss_pci_data *pci_priv) pci_priv->iommu_geometry = of_property_read_bool(of_node, "qcom,iommu-geometry"); cnss_pr_dbg("iommu_geometry: %d\n", pci_priv->iommu_geometry); - +out: of_node_put(of_node); - return 0; + return ret; } static void cnss_pci_deinit_smmu(struct cnss_pci_data *pci_priv) @@ -4299,6 +4330,19 @@ static void cnss_pci_disable_msi(struct cnss_pci_data *pci_priv) pci_free_irq_vectors(pci_priv->pci_dev); } +int cnss_pci_get_user_msi_assignment(struct cnss_pci_data *pci_priv, + char *user_name, + int *num_vectors, + u32 *user_base_data, + u32 *base_vector) +{ + return cnss_get_user_msi_assignment(&pci_priv->pci_dev->dev, + user_name, + num_vectors, + user_base_data, + base_vector); +} + int cnss_get_user_msi_assignment(struct device *dev, char *user_name, int *num_vectors, u32 *user_base_data, u32 *base_vector) @@ -4380,9 +4424,9 @@ u32 cnss_pci_get_wake_msi(struct cnss_pci_data *pci_priv) if (!pci_priv) return -ENODEV; - ret = cnss_get_user_msi_assignment(&pci_priv->pci_dev->dev, - WAKE_MSI_NAME, &num_vectors, - &user_base_data, &base_vector); + ret = cnss_pci_get_user_msi_assignment(pci_priv, + WAKE_MSI_NAME, &num_vectors, + &user_base_data, &base_vector); if (ret) { cnss_pr_err("WAKE MSI is not valid\n"); return 0; @@ -4930,6 +4974,10 @@ void cnss_pci_add_fw_prefix_name(struct cnss_pci_data *pci_priv, } switch (pci_priv->device_id) { + case QCN7605_DEVICE_ID: + scnprintf(prefix_name, MAX_FIRMWARE_NAME_LEN, + QCN7605_PATH_PREFIX "%s", name); + break; case QCA6390_DEVICE_ID: scnprintf(prefix_name, MAX_FIRMWARE_NAME_LEN, QCA6390_PATH_PREFIX "%s", name); @@ -5129,9 +5177,9 @@ static int cnss_pci_get_mhi_msi(struct cnss_pci_data *pci_priv) u32 user_base_data, base_vector; int *irq; - ret = cnss_get_user_msi_assignment(&pci_priv->pci_dev->dev, - MHI_MSI_NAME, &num_vectors, - &user_base_data, &base_vector); + ret = cnss_pci_get_user_msi_assignment(pci_priv, + MHI_MSI_NAME, &num_vectors, + &user_base_data, &base_vector); if (ret) return ret; @@ -5245,7 +5293,7 @@ static int cnss_pci_register_mhi(struct cnss_pci_data *pci_priv) mhi_ctrl->priv_data = pci_priv; mhi_ctrl->dev = &pci_dev->dev; - mhi_ctrl->of_node = (&plat_priv->plat_dev->dev)->of_node; + mhi_ctrl->of_node = plat_priv->dev_node; mhi_ctrl->dev_id = pci_priv->device_id; mhi_ctrl->domain = pci_domain_nr(pci_dev->bus); mhi_ctrl->bus = pci_dev->bus->number; @@ -5284,7 +5332,12 @@ static int cnss_pci_register_mhi(struct cnss_pci_data *pci_priv) mhi_ctrl->rddm_size = pci_priv->plat_priv->ramdump_info_v2.ramdump_size; if (!mhi_ctrl->rddm_size) mhi_ctrl->rddm_size = RAMDUMP_SIZE_DEFAULT; - mhi_ctrl->sbl_size = SZ_512K; + + if (pci_priv->device_id == QCN7605_DEVICE_ID) + mhi_ctrl->sbl_size = SZ_256K; + else + mhi_ctrl->sbl_size = SZ_512K; + mhi_ctrl->seg_len = SZ_512K; mhi_ctrl->fbc_download = true; mhi_ctrl->rddm_supported = true; @@ -5512,6 +5565,52 @@ static struct dev_pm_domain cnss_pm_domain = { } }; +static int cnss_pci_get_dev_cfg_node(struct cnss_plat_data *plat_priv) +{ + struct device_node *child; + u32 id, i; + int id_n, ret; + + if (!plat_priv->is_converged_dt) + return 0; + + if (!plat_priv->device_id) { + cnss_pr_err("Invalid device id\n"); + return -EINVAL; + } + + for_each_available_child_of_node(plat_priv->plat_dev->dev.of_node, + child) { + if (strcmp(child->name, "chip_cfg")) + continue; + + id_n = of_property_count_u32_elems(child, "supported-ids"); + if (id_n <= 0) { + cnss_pr_err("Device id is NOT set\n"); + return -EINVAL; + } + + for (i = 0; i < id_n; i++) { + ret = of_property_read_u32_index(child, + "supported-ids", + i, &id); + if (ret) { + cnss_pr_err("Failed to read supported ids\n"); + return -EINVAL; + } + + if (id == plat_priv->device_id) { + plat_priv->dev_node = child; + cnss_pr_dbg("got node[%s@%d] for device[0x%x]\n", + child->name, i, id); + return 0; + } + } + } + + return -EINVAL; +} + static int cnss_pci_probe(struct pci_dev *pci_dev, const struct pci_device_id *id) { @@ -5544,6 +5643,16 @@ static int cnss_pci_probe(struct pci_dev *pci_dev, if (plat_priv->use_pm_domain) dev->pm_domain = &cnss_pm_domain; + ret = cnss_pci_get_dev_cfg_node(plat_priv); + if (ret) { + cnss_pr_err("Failed to get device cfg node, err = %d\n", ret); + goto reset_ctx; + } + + ret = cnss_dev_specific_power_on(plat_priv); + if (ret) + goto reset_ctx; + cnss_pci_of_reserved_mem_device_init(pci_priv); ret = cnss_register_subsys(plat_priv); @@ -5583,6 +5692,7 @@ static int cnss_pci_probe(struct pci_dev *pci_dev, break; case QCA6290_DEVICE_ID: case QCA6390_DEVICE_ID: + case QCN7605_DEVICE_ID: case QCA6490_DEVICE_ID: case WCN7850_DEVICE_ID: cnss_pci_set_wlaon_pwr_ctrl(pci_priv, false, false, false); @@ -5671,6 +5781,7 @@ static const struct pci_device_id cnss_pci_id_table[] = { { QCA6174_VENDOR_ID, QCA6174_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, { QCA6290_VENDOR_ID, QCA6290_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, { QCA6390_VENDOR_ID, QCA6390_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { QCN7605_VENDOR_ID, QCN7605_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID}, { QCA6490_VENDOR_ID, QCA6490_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, { WCN7850_VENDOR_ID, WCN7850_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, { 0 } diff --git a/drivers/net/wireless/cnss2/pci.h b/drivers/net/wireless/cnss2/pci.h index de9f31bcf86f..acd323bad6b8 100644 --- a/drivers/net/wireless/cnss2/pci.h +++ b/drivers/net/wireless/cnss2/pci.h @@ -248,5 +248,9 @@ int cnss_pci_debug_reg_write(struct cnss_pci_data *pci_priv, u32 offset, int cnss_pci_get_iova(struct cnss_pci_data *pci_priv, u64 *addr, u64 *size); int cnss_pci_get_iova_ipa(struct cnss_pci_data *pci_priv, u64 *addr, u64 *size); - +int cnss_pci_get_user_msi_assignment(struct cnss_pci_data *pci_priv, + char *user_name, + int *num_vectors, + u32 *user_base_data, + u32 *base_vector); #endif /* _CNSS_PCI_H */ diff --git a/drivers/net/wireless/cnss2/power.c b/drivers/net/wireless/cnss2/power.c index 00b42685d3fa..6936999a4b9c 100644 --- a/drivers/net/wireless/cnss2/power.c +++ b/drivers/net/wireless/cnss2/power.c @@ -56,6 +56,7 @@ static struct cnss_clk_cfg cnss_clk_list[] = { #define XO_CLK_GPIO "qcom,xo-clk-gpio" #define WLAN_EN_ACTIVE "wlan_en_active" #define WLAN_EN_SLEEP "wlan_en_sleep" +#define WLAN_VREGS_PROP "wlan_vregs" #define BOOTSTRAP_DELAY 1000 #define WLAN_ENABLE_DELAY 1000 @@ -97,7 +98,7 @@ static int cnss_get_vreg_single(struct cnss_plat_data *plat_priv, snprintf(prop_name, MAX_PROP_SIZE, "qcom,%s-config", vreg->cfg.name); - prop = of_get_property(dev->of_node, prop_name, &len); + prop = of_get_property(plat_priv->dev_node, prop_name, &len); if (!prop || len != (5 * sizeof(__be32))) { cnss_pr_dbg("Property %s %s, use default\n", prop_name, prop ? "invalid format" : "doesn't exist"); @@ -269,18 +270,51 @@ static int cnss_get_vreg(struct cnss_plat_data *plat_priv, int i; struct cnss_vreg_info *vreg; struct device *dev = &plat_priv->plat_dev->dev; + int id_n; - if (!list_empty(vreg_list)) { + if (!list_empty(&plat_priv->vreg_list) && + !plat_priv->is_converged_dt) { cnss_pr_dbg("Vregs have already been updated\n"); return 0; } - for (i = 0; i < vreg_list_size; i++) { + if (plat_priv->is_converged_dt) { + id_n = of_property_count_strings(plat_priv->dev_node, + WLAN_VREGS_PROP); + if (id_n <= 0) { + if (id_n == -ENODATA) { + cnss_pr_dbg("No additional vregs for: %s:%lx\n", + plat_priv->dev_node->name, + plat_priv->device_id); + return 0; + } + + cnss_pr_err("property %s is invalid or missed: %s:%lx\n", + WLAN_VREGS_PROP, plat_priv->dev_node->name, + plat_priv->device_id); + return -EINVAL; + } + } else { + id_n = vreg_list_size; + } + + for (i = 0; i < id_n; i++) { vreg = devm_kzalloc(dev, sizeof(*vreg), GFP_KERNEL); if (!vreg) return -ENOMEM; - memcpy(&vreg->cfg, &vreg_cfg[i], sizeof(vreg->cfg)); + if (plat_priv->is_converged_dt) { + ret = of_property_read_string_index(plat_priv->dev_node, + WLAN_VREGS_PROP, i, + &vreg->cfg.name); + if (ret) { + cnss_pr_err("Failed to read vreg ids\n"); + return ret; + } + } else { + memcpy(&vreg->cfg, &vreg_cfg[i], sizeof(vreg->cfg)); + } + ret = cnss_get_vreg_single(plat_priv, vreg); if (ret != 0) { if (ret == -ENODEV) { @@ -1146,3 +1180,18 @@ int cnss_enable_int_pow_amp_vreg(struct cnss_plat_data *plat_priv) cnss_pr_dbg("Setup S3E TCS Addr: %x Data: %d\n", addr_val, data_val); return 0; } + +int cnss_dev_specific_power_on(struct cnss_plat_data *plat_priv) +{ + int ret; + + if (!plat_priv->is_converged_dt) + return 0; + + ret = cnss_get_vreg_type(plat_priv, CNSS_VREG_PRIM); + if (ret) + return ret; + + plat_priv->powered_on = false; + return cnss_power_on_device(plat_priv); +} diff --git a/drivers/net/wireless/cnss2/qmi.c b/drivers/net/wireless/cnss2/qmi.c index 7f8f80aed681..f683ca607040 100644 --- a/drivers/net/wireless/cnss2/qmi.c +++ b/drivers/net/wireless/cnss2/qmi.c @@ -30,6 +30,7 @@ #define DEBUG_STR "debug" #define HW_V1_NUMBER "v1" #define HW_V2_NUMBER "v2" +#define CE_MSI_NAME "CE" #define QMI_WLFW_TIMEOUT_MS (plat_priv->ctrl_params.qmi_timeout) #define QMI_WLFW_TIMEOUT_JF msecs_to_jiffies(QMI_WLFW_TIMEOUT_MS) @@ -1277,7 +1278,7 @@ int cnss_wlfw_wlan_cfg_send_sync(struct cnss_plat_data *plat_priv, struct wlfw_wlan_cfg_req_msg_v01 *req; struct wlfw_wlan_cfg_resp_msg_v01 *resp; struct qmi_txn txn; - u32 i; + u32 i, ce_id, num_vectors, user_base_data, base_vector; int ret = 0; if (!plat_priv) @@ -1323,7 +1324,17 @@ int cnss_wlfw_wlan_cfg_send_sync(struct cnss_plat_data *plat_priv, req->svc_cfg[i].pipe_dir = config->ce_svc_cfg[i].pipe_dir; req->svc_cfg[i].pipe_num = config->ce_svc_cfg[i].pipe_num; } - + if (config->num_shadow_reg_cfg) { + req->shadow_reg_valid = 1; + if (config->num_shadow_reg_cfg > + QMI_WLFW_MAX_NUM_SHADOW_REG_V01) + req->shadow_reg_len = QMI_WLFW_MAX_NUM_SHADOW_REG_V01; + else + req->shadow_reg_len = config->num_shadow_reg_cfg; + memcpy(req->shadow_reg, config->shadow_reg_cfg, + sizeof(struct wlfw_shadow_reg_cfg_s_v01) + * req->shadow_reg_len); + } req->shadow_reg_v2_valid = 1; if (config->num_shadow_reg_v2_cfg > QMI_WLFW_MAX_NUM_SHADOW_REG_V2_V01) @@ -1334,6 +1345,30 @@ int cnss_wlfw_wlan_cfg_send_sync(struct cnss_plat_data *plat_priv, memcpy(req->shadow_reg_v2, config->shadow_reg_v2_cfg, sizeof(struct wlfw_shadow_reg_v2_cfg_s_v01) * req->shadow_reg_v2_len); + if (config->rri_over_ddr_cfg_valid) { + req->rri_over_ddr_cfg_valid = 1; + req->rri_over_ddr_cfg.base_addr_low = + config->rri_over_ddr_cfg.base_addr_low; + req->rri_over_ddr_cfg.base_addr_high = + config->rri_over_ddr_cfg.base_addr_high; + } + if (config->send_msi_ce) { + ret = cnss_bus_get_msi_assignment(plat_priv, + CE_MSI_NAME, + &num_vectors, + &user_base_data, + &base_vector); + if (!ret) { + req->msi_cfg_valid = 1; + req->msi_cfg_len = QMI_WLFW_MAX_NUM_CE_V01; + for (ce_id = 0; ce_id < QMI_WLFW_MAX_NUM_CE_V01; + ce_id++) { + req->msi_cfg[ce_id].ce_id = ce_id; + req->msi_cfg[ce_id].msi_vector = + (ce_id % num_vectors) + base_vector; + } + } + } ret = qmi_txn_init(&plat_priv->qmi_wlfw, &txn, wlfw_wlan_cfg_resp_msg_v01_ei, resp); diff --git a/include/net/cnss2.h b/include/net/cnss2.h index 149487b56b06..626604be782e 100644 --- a/include/net/cnss2.h +++ b/include/net/cnss2.h @@ -149,6 +149,7 @@ struct cnss_wlan_enable_cfg { struct cnss_shadow_reg_v2_cfg *shadow_reg_v2_cfg; bool rri_over_ddr_cfg_valid; struct cnss_rri_over_ddr_cfg rri_over_ddr_cfg; + bool send_msi_ce; }; enum cnss_driver_mode {