diff --git a/drivers/usb/dwc3/dwc3-msm.c b/drivers/usb/dwc3/dwc3-msm.c index 857d730166a6..10b1ad1f0823 100644 --- a/drivers/usb/dwc3/dwc3-msm.c +++ b/drivers/usb/dwc3/dwc3-msm.c @@ -303,6 +303,13 @@ enum msm_usb_irq { USB_MAX_IRQ }; +enum icc_paths { + USB_DDR, + USB_IPA, + DDR_USB, + USB_MAX_PATH +}; + enum bus_vote { BUS_VOTE_NONE, BUS_VOTE_NOMINAL, @@ -315,7 +322,7 @@ static const char * const icc_path_names[] = { "usb-ddr", "usb-ipa", "ddr-usb", }; -static const struct { +static struct { u32 avg, peak; } bus_vote_values[BUS_VOTE_MAX][3] = { /* usb_ddr avg/peak, usb_ipa avg/peak, apps_usb avg/peak */ @@ -3948,6 +3955,68 @@ static ssize_t bus_vote_store(struct device *dev, } static DEVICE_ATTR_RW(bus_vote); +static int dwc3_msm_interconnect_vote_populate(struct dwc3_msm *mdwc) +{ + int ret_nom = 0, i = 0, j = 0, count = 0; + int ret_svs = 0, ret = 0; + u32 *vv_nom, *vv_svs; + + count = of_property_count_strings(mdwc->dev->of_node, + "interconnect-names"); + if (count < 0) { + dev_err(mdwc->dev, "No interconnects found.\n"); + return -EINVAL; + } + + /* 2 signifies the two types of values avg & peak */ + vv_nom = kzalloc(count * 2 * sizeof(*vv_nom), GFP_KERNEL); + if (!vv_nom) + return -ENOMEM; + + vv_svs = kzalloc(count * 2 * sizeof(*vv_svs), GFP_KERNEL); + if (!vv_svs) + return -ENOMEM; + + /* of_property_read_u32_array returns 0 on success */ + ret_nom = of_property_read_u32_array(mdwc->dev->of_node, + "qcom,interconnect-values-nom", + vv_nom, count * 2); + if (ret_nom) { + dev_err(mdwc->dev, "Nominal values not found.\n"); + ret = ret_nom; + goto icc_err; + } + + ret_svs = of_property_read_u32_array(mdwc->dev->of_node, + "qcom,interconnect-values-svs", + vv_svs, count * 2); + if (ret_svs) { + dev_err(mdwc->dev, "Svs values not found.\n"); + ret = ret_svs; + goto icc_err; + } + + for (i = USB_DDR; i < count && i < USB_MAX_PATH; i++) { + /* Updating votes NOMINAL */ + bus_vote_values[BUS_VOTE_NOMINAL][i].avg + = vv_nom[j]; + bus_vote_values[BUS_VOTE_NOMINAL][i].peak + = vv_nom[j+1]; + /* Updating votes SVS */ + bus_vote_values[BUS_VOTE_SVS][i].avg + = vv_svs[j]; + bus_vote_values[BUS_VOTE_SVS][i].peak + = vv_svs[j+1]; + j += 2; + } +icc_err: + /* freeing the temporary resource */ + kfree(vv_nom); + kfree(vv_svs); + + return ret; +} + static int dwc_dpdm_cb(struct notifier_block *nb, unsigned long evt, void *p) { struct dwc3_msm *mdwc = container_of(nb, struct dwc3_msm, dpdm_nb); @@ -4319,6 +4388,10 @@ static int dwc3_msm_probe(struct platform_device *pdev) goto put_dwc3; } + ret = dwc3_msm_interconnect_vote_populate(mdwc); + if (ret) + dev_err(&pdev->dev, "Dynamic voting failed\n"); + /* use default as nominal bus voting */ mdwc->default_bus_vote = BUS_VOTE_NOMINAL; ret = of_property_read_u32(node, "qcom,default-bus-vote",