diff --git a/drivers/gpu/msm/adreno_a6xx.c b/drivers/gpu/msm/adreno_a6xx.c index 2f72f59e44a4..6e05a801c2a4 100644 --- a/drivers/gpu/msm/adreno_a6xx.c +++ b/drivers/gpu/msm/adreno_a6xx.c @@ -698,6 +698,40 @@ void a6xx_start(struct adreno_device *adreno_dev) } } +/* Offsets into the MX/CX mapped register regions */ +#define RDPM_MX_OFFSET 0xf00 +#define RDPM_CX_OFFSET 0xf18 + +void a6xx_rdpm_mx_freq_update(struct a6xx_gmu_device *gmu, + u32 freq) +{ + if (gmu->rdpm_mx_virt) { + writel_relaxed(freq/1000, + (gmu->rdpm_mx_virt + RDPM_MX_OFFSET)); + + /* + * ensure previous writes post before this one, + * i.e. act like normal writel() + */ + wmb(); + } +} + +void a6xx_rdpm_cx_freq_update(struct a6xx_gmu_device *gmu, + u32 freq) +{ + if (gmu->rdpm_cx_virt) { + writel_relaxed(freq/1000, + (gmu->rdpm_cx_virt + RDPM_CX_OFFSET)); + + /* + * ensure previous writes post before this one, + * i.e. act like normal writel() + */ + wmb(); + } +} + void a6xx_unhalt_sqe(struct adreno_device *adreno_dev) { struct kgsl_device *device = KGSL_DEVICE(adreno_dev); diff --git a/drivers/gpu/msm/adreno_a6xx.h b/drivers/gpu/msm/adreno_a6xx.h index d6e0bd47204b..4c28695cbbf8 100644 --- a/drivers/gpu/msm/adreno_a6xx.h +++ b/drivers/gpu/msm/adreno_a6xx.h @@ -433,4 +433,22 @@ int a6xx_perfcounter_update(struct adreno_device *adreno_dev, extern const struct adreno_perfcounters adreno_a630_perfcounters; extern const struct adreno_perfcounters adreno_a6xx_perfcounters; extern const struct adreno_perfcounters adreno_a6xx_legacy_perfcounters; + +/** + * a6xx_rdpm_mx_freq_update - Update the mx frequency + * @gmu: An Adreno GMU handle + * @freq: Frequency in KHz + * + * This function communicates GPU mx frequency(in Mhz) changes to rdpm. + */ +void a6xx_rdpm_mx_freq_update(struct a6xx_gmu_device *gmu, u32 freq); + +/** + * a6xx_rdpm_cx_freq_update - Update the cx frequency + * @gmu: An Adreno GMU handle + * @freq: Frequency in KHz + * + * This function communicates GPU cx frequency(in Mhz) changes to rdpm. + */ +void a6xx_rdpm_cx_freq_update(struct a6xx_gmu_device *gmu, u32 freq); #endif diff --git a/drivers/gpu/msm/adreno_a6xx_gmu.c b/drivers/gpu/msm/adreno_a6xx_gmu.c index 98eae815411e..19235c5bbeeb 100644 --- a/drivers/gpu/msm/adreno_a6xx_gmu.c +++ b/drivers/gpu/msm/adreno_a6xx_gmu.c @@ -1092,6 +1092,9 @@ static int a6xx_gmu_gfx_rail_on(struct adreno_device *adreno_dev) gmu_core_regwrite(device, A6XX_GMU_MX_VOTE_IDX, ARC_VOTE_GET_SEC(default_opp)); + a6xx_rdpm_mx_freq_update(gmu, + gmu->hfi.dcvs_table.gx_votes[perf_idx].freq); + return a6xx_gmu_oob_set(device, oob_boot_slumber); } @@ -1781,6 +1784,8 @@ void a6xx_gmu_suspend(struct adreno_device *adreno_dev) if (ADRENO_QUIRK(adreno_dev, ADRENO_QUIRK_CX_GDSC)) regulator_set_mode(gmu->cx_gdsc, REGULATOR_MODE_NORMAL); + a6xx_rdpm_cx_freq_update(gmu, 0); + dev_err(&gmu->pdev->dev, "Suspended GMU\n"); device->state = KGSL_STATE_NONE; @@ -1843,6 +1848,10 @@ static int a6xx_gmu_dcvs_set(struct adreno_device *adreno_dev, } } + if (req.freq != INVALID_DCVS_IDX) + a6xx_rdpm_mx_freq_update(gmu, + gmu->hfi.dcvs_table.gx_votes[req.freq].freq); + return ret; } @@ -2156,6 +2165,8 @@ int a6xx_gmu_enable_clks(struct adreno_device *adreno_dev) struct kgsl_device *device = KGSL_DEVICE(adreno_dev); int ret; + a6xx_rdpm_cx_freq_update(gmu, GMU_FREQUENCY / 1000); + ret = a6xx_gmu_clk_set_rate(gmu, "gmu_clk", GMU_FREQUENCY); if (ret) { dev_err(&gmu->pdev->dev, "Unable to set the GMU clock\n"); @@ -2278,6 +2289,8 @@ gdsc_off: if (!a6xx_cx_regulator_disable_wait(gmu->cx_gdsc, device, 5000)) dev_err(&gmu->pdev->dev, "GMU CX gdsc off timeout\n"); + a6xx_rdpm_cx_freq_update(gmu, 0); + return ret; } @@ -2357,6 +2370,8 @@ gdsc_off: if (!a6xx_cx_regulator_disable_wait(gmu->cx_gdsc, device, 5000)) dev_err(&gmu->pdev->dev, "GMU CX gdsc off timeout\n"); + a6xx_rdpm_cx_freq_update(gmu, 0); + return ret; } @@ -2541,6 +2556,24 @@ static int a6xx_gmu_reg_probe(struct adreno_device *adreno_dev) return 0; } +static void a6xx_gmu_rdpm_probe(struct a6xx_gmu_device *gmu, + struct kgsl_device *device) +{ + struct resource *res; + + res = platform_get_resource_byname(device->pdev, IORESOURCE_MEM, + "rdpm_cx"); + if (res) + gmu->rdpm_cx_virt = devm_ioremap(&device->pdev->dev, + res->start, resource_size(res)); + + res = platform_get_resource_byname(device->pdev, IORESOURCE_MEM, + "rdpm_mx"); + if (res) + gmu->rdpm_mx_virt = devm_ioremap(&device->pdev->dev, + res->start, resource_size(res)); +} + static int a6xx_gmu_regulators_probe(struct a6xx_gmu_device *gmu, struct platform_device *pdev) { @@ -2660,6 +2693,9 @@ int a6xx_gmu_probe(struct kgsl_device *device, } } + /* Setup any rdpm register ranges */ + a6xx_gmu_rdpm_probe(gmu, device); + /* Set up GMU regulators */ ret = a6xx_gmu_regulators_probe(gmu, pdev); if (ret) @@ -2790,6 +2826,8 @@ static int a6xx_gmu_power_off(struct adreno_device *adreno_dev) ret = a6xx_rscc_sleep_sequence(adreno_dev); + a6xx_rdpm_mx_freq_update(gmu, 0); + /* Now that we are done with GMU and GPU, Clear the GBIF */ if (!adreno_is_a630(adreno_dev)) ret = a6xx_halt_gbif(adreno_dev); @@ -2804,6 +2842,8 @@ static int a6xx_gmu_power_off(struct adreno_device *adreno_dev) if (!a6xx_cx_regulator_disable_wait(gmu->cx_gdsc, device, 5000)) dev_err(&gmu->pdev->dev, "GMU CX gdsc off timeout\n"); + a6xx_rdpm_cx_freq_update(gmu, 0); + device->state = KGSL_STATE_NONE; return ret; diff --git a/drivers/gpu/msm/adreno_a6xx_gmu.h b/drivers/gpu/msm/adreno_a6xx_gmu.h index ca301e31aa10..130f0a617150 100644 --- a/drivers/gpu/msm/adreno_a6xx_gmu.h +++ b/drivers/gpu/msm/adreno_a6xx_gmu.h @@ -201,6 +201,10 @@ struct a6xx_gmu_device { void __iomem *rscc_virt; /** @domain: IOMMU domain for the kernel context */ struct iommu_domain *domain; + /** @rdpm_cx_virt: Pointer where the RDPM CX block is mapped */ + void __iomem *rdpm_cx_virt; + /** @rdpm_mx_virt: Pointer where the RDPM MX block is mapped */ + void __iomem *rdpm_mx_virt; }; /* Helper function to get to a6xx gmu device from adreno device */ diff --git a/drivers/gpu/msm/adreno_a6xx_hwsched.c b/drivers/gpu/msm/adreno_a6xx_hwsched.c index 39006d55f29a..f83b63497408 100644 --- a/drivers/gpu/msm/adreno_a6xx_hwsched.c +++ b/drivers/gpu/msm/adreno_a6xx_hwsched.c @@ -220,6 +220,8 @@ gdsc_off: if (!a6xx_cx_regulator_disable_wait(gmu->cx_gdsc, device, 5000)) dev_err(&gmu->pdev->dev, "GMU CX gdsc off timeout\n"); + a6xx_rdpm_cx_freq_update(gmu, 0); + return ret; } @@ -281,6 +283,8 @@ gdsc_off: if (!a6xx_cx_regulator_disable_wait(gmu->cx_gdsc, device, 5000)) dev_err(&gmu->pdev->dev, "GMU CX gdsc off timeout\n"); + a6xx_rdpm_cx_freq_update(gmu, 0); + return ret; } @@ -365,6 +369,8 @@ static int a6xx_hwsched_gmu_power_off(struct adreno_device *adreno_dev) ret = a6xx_rscc_sleep_sequence(adreno_dev); + a6xx_rdpm_mx_freq_update(gmu, 0); + /* Now that we are done with GMU and GPU, Clear the GBIF */ ret = a6xx_halt_gbif(adreno_dev); @@ -378,6 +384,8 @@ static int a6xx_hwsched_gmu_power_off(struct adreno_device *adreno_dev) if (!a6xx_cx_regulator_disable_wait(gmu->cx_gdsc, device, 5000)) dev_err(&gmu->pdev->dev, "GMU CX gdsc off timeout\n"); + a6xx_rdpm_cx_freq_update(gmu, 0); + return ret; error: @@ -776,6 +784,10 @@ static int a6xx_hwsched_dcvs_set(struct adreno_device *adreno_dev, } + if (req.freq != INVALID_DCVS_IDX) + a6xx_rdpm_mx_freq_update(gmu, + gmu->hfi.dcvs_table.gx_votes[req.freq].freq); + return ret; }