diff --git a/drivers/gpu/msm/adreno.c b/drivers/gpu/msm/adreno.c index e72a85b5985f..9e6b0907268c 100644 --- a/drivers/gpu/msm/adreno.c +++ b/drivers/gpu/msm/adreno.c @@ -907,31 +907,46 @@ static int adreno_of_parse_pwrlevels(struct adreno_device *adreno_dev, pwr->num_pwrlevels = 0; for_each_child_of_node(node, child) { - unsigned int index, freq = 0; + u32 index, freq = 0, voltage, bus; struct kgsl_pwrlevel *level; - if (of_property_read_u32(child, "reg", &index)) { - dev_err(device->dev, - "%pOF: powerlevel index not found\n", child); - of_node_put(child); - return -EINVAL; + ret = of_property_read_u32(child, "reg", &index); + if (ret) { + dev_err(device->dev, "%pOF: powerlevel index not found\n", + child); + goto out; } - if (of_property_read_u32(child, "qcom,gpu-freq", &freq)) { - dev_err(device->dev, - "%pOF: Unable to read qcom,gpu-freq\n", child); - of_node_put(child); - return -EINVAL; + ret = of_property_read_u32(child, "qcom,gpu-freq", &freq); + if (ret) { + dev_err(device->dev, "%pOF: Unable to read qcom,gpu-freq\n", + child); + goto out; } /* Ignore "zero" powerlevels */ if (!freq) continue; + ret = of_property_read_u32(child, "qcom,level", &voltage); + if (ret) { + dev_err(device->dev, "%pOF: Unable to read qcom,level\n", + child); + goto out; + } + + ret = kgsl_of_property_read_ddrtype(child, "qcom,bus-freq", + &bus); + if (ret) { + dev_err(device->dev, "%pOF:Unable to read qcom,bus-freq\n", + child); + goto out; + } + + if (index >= KGSL_MAX_PWRLEVELS) { - dev_err(device->dev, - "%pOF: Pwrlevel index %d is out of range\n", - child, index); + dev_err(device->dev, "%pOF: Pwrlevel index %d is out of range\n", + child, index); continue; } @@ -941,20 +956,12 @@ static int adreno_of_parse_pwrlevels(struct adreno_device *adreno_dev, level = &pwr->pwrlevels[index]; level->gpu_freq = freq; + level->bus_freq = bus; + level->voltage_level = voltage; of_property_read_u32(child, "qcom,acd-level", &level->acd_level); - ret = kgsl_of_property_read_ddrtype(child, - "qcom,bus-freq", &level->bus_freq); - if (ret) { - dev_err(device->dev, - "%pOF: Couldn't read the bus frequency for power level %d\n", - child, index); - of_node_put(child); - return ret; - } - level->bus_min = level->bus_freq; kgsl_of_property_read_ddrtype(child, "qcom,bus-min", &level->bus_min); @@ -965,6 +972,9 @@ static int adreno_of_parse_pwrlevels(struct adreno_device *adreno_dev, } return 0; +out: + of_node_put(child); + return ret; } static void adreno_of_get_initial_pwrlevel(struct adreno_device *adreno_dev, diff --git a/drivers/gpu/msm/kgsl_gmu.c b/drivers/gpu/msm/kgsl_gmu.c index 12acda62c364..cca5e2ff240c 100644 --- a/drivers/gpu/msm/kgsl_gmu.c +++ b/drivers/gpu/msm/kgsl_gmu.c @@ -690,45 +690,22 @@ static int rpmh_arc_votes_init(struct kgsl_device *device, { unsigned int num_freqs; u16 vlvl_tbl[MAX_GX_LEVELS]; - unsigned int *freq_tbl; int i; - struct dev_pm_opp *opp; if (type == GMU_ARC_VOTE) return rpmh_gmu_arc_votes_init(gmu, pri_rail, sec_rail); num_freqs = gmu->num_gpupwrlevels; - freq_tbl = gmu->gpu_freqs; - if (num_freqs > pri_rail->num || num_freqs > MAX_GX_LEVELS) { + if (num_freqs > pri_rail->num) { dev_err(&gmu->pdev->dev, "Defined more GPU DCVS levels than RPMh can support\n"); return -EINVAL; } memset(vlvl_tbl, 0, sizeof(vlvl_tbl)); - - /* Get the values from OPP API */ - for (i = 0; i < num_freqs; i++) { - /* Hardcode VLVL 0 because it is not present in OPP */ - if (freq_tbl[i] == 0) { - vlvl_tbl[i] = 0; - continue; - } - - opp = dev_pm_opp_find_freq_exact(&device->pdev->dev, - freq_tbl[i], true); - - if (IS_ERR(opp)) { - dev_err(&gmu->pdev->dev, - "Failed to find opp freq %d for GPU\n", - freq_tbl[i]); - return PTR_ERR(opp); - } - - vlvl_tbl[i] = dev_pm_opp_get_voltage(opp); - dev_pm_opp_put(opp); - } + for (i = 0; i < num_freqs; i++) + vlvl_tbl[i] = gmu->pwrlevels[i].level; return setup_volt_dependency_tbl(gmu->rpmh_votes.gx_votes, pri_rail, sec_rail, vlvl_tbl, num_freqs); @@ -1205,7 +1182,7 @@ static int gmu_probe(struct kgsl_device *device, struct device_node *node) struct kgsl_hfi *hfi; struct kgsl_pwrctrl *pwr = &device->pwrctrl; struct adreno_device *adreno_dev = ADRENO_DEVICE(device); - int i = 0, ret = -ENXIO, index = 0; + int i = 0, ret = -ENXIO, index; gmu = kzalloc(sizeof(struct gmu_device), GFP_KERNEL); @@ -1275,12 +1252,21 @@ static int gmu_probe(struct kgsl_device *device, struct device_node *node) tasklet_init(&hfi->tasklet, hfi_receiver, (unsigned long) gmu); hfi->kgsldev = device; - /* Add a dummy level for "off" that the GMU expects */ - gmu->gpu_freqs[index++] = 0; + if (WARN(pwr->num_pwrlevels + 1 > ARRAY_SIZE(gmu->pwrlevels), + "Too many GPU powerlevels for the GMU HFI\n")) { + ret = -EINVAL; + goto error; + } + + /* Add a dummy level for "off" because the GMU expects it */ + gmu->pwrlevels[0].freq = 0; + gmu->pwrlevels[0].level = 0; /* GMU power levels are in ascending order */ - for (i = pwr->num_pwrlevels - 1; i >= 0; i--) - gmu->gpu_freqs[index++] = pwr->pwrlevels[i].gpu_freq; + for (index = 1, i = pwr->num_pwrlevels - 1; i >= 0; i--, index++) { + gmu->pwrlevels[index].freq = pwr->pwrlevels[i].gpu_freq; + gmu->pwrlevels[index].level = pwr->pwrlevels[i].voltage_level; + } gmu->num_gpupwrlevels = pwr->num_pwrlevels + 1; diff --git a/drivers/gpu/msm/kgsl_gmu.h b/drivers/gpu/msm/kgsl_gmu.h index 1db0bbef5463..6f62f63c2c7f 100644 --- a/drivers/gpu/msm/kgsl_gmu.h +++ b/drivers/gpu/msm/kgsl_gmu.h @@ -158,7 +158,6 @@ struct icc_path; * @dump_mem: pointer to GMU debug dump memory * @gmu_log: gmu event log memory * @hfi: HFI controller - * @gpu_freqs: GPU frequency table with lowest freq at index 0 * @num_gpupwrlevels: number GPU frequencies in GPU freq table * @num_bwlevel: number of GPU BW levels * @num_cnocbwlevel: number CNOC BW levels @@ -194,7 +193,13 @@ struct gmu_device { struct gmu_memdesc *dump_mem; struct gmu_memdesc *gmu_log; struct kgsl_hfi hfi; - unsigned int gpu_freqs[MAX_GX_LEVELS]; + /** @pwrlevels: Array of GMU power levels */ + struct { + /** @freq: GPU frequency */ + unsigned long freq; + /** @level: Voltage level */ + u32 level; + } pwrlevels[MAX_GX_LEVELS]; unsigned int num_gpupwrlevels; unsigned int num_bwlevels; unsigned int num_cnocbwlevels; diff --git a/drivers/gpu/msm/kgsl_hfi.c b/drivers/gpu/msm/kgsl_hfi.c index 864d1033248c..0ef1ec54e6ee 100644 --- a/drivers/gpu/msm/kgsl_hfi.c +++ b/drivers/gpu/msm/kgsl_hfi.c @@ -437,7 +437,7 @@ static int hfi_send_dcvstbl_v1(struct gmu_device *gmu) for (i = 0; i < gmu->num_gpupwrlevels; i++) { cmd.gx_votes[i].vote = gmu->rpmh_votes.gx_votes[i]; /* Divide by 1000 to convert to kHz */ - cmd.gx_votes[i].freq = gmu->gpu_freqs[i] / 1000; + cmd.gx_votes[i].freq = gmu->pwrlevels[i].freq / 1000; } cmd.cx_votes[0].vote = gmu->rpmh_votes.cx_votes[0]; @@ -483,7 +483,7 @@ static int hfi_send_dcvstbl(struct gmu_device *gmu) /* Hardcode this to the max threshold since it is not used */ cmd.gx_votes[i].acd = 0xFFFFFFFF; /* Divide by 1000 to convert to kHz */ - cmd.gx_votes[i].freq = gmu->gpu_freqs[i] / 1000; + cmd.gx_votes[i].freq = gmu->pwrlevels[i].freq / 1000; } cmd.cx_votes[0].vote = gmu->rpmh_votes.cx_votes[0]; diff --git a/drivers/gpu/msm/kgsl_pwrctrl.h b/drivers/gpu/msm/kgsl_pwrctrl.h index 894b4de212b5..d3d10b7aad02 100644 --- a/drivers/gpu/msm/kgsl_pwrctrl.h +++ b/drivers/gpu/msm/kgsl_pwrctrl.h @@ -69,6 +69,8 @@ struct kgsl_pwrlevel { unsigned int bus_min; unsigned int bus_max; unsigned int acd_level; + /** @voltage_level: Voltage level used by the GMU to vote RPMh */ + u32 voltage_level; }; /**