Loading drivers/gpu/msm/adreno_a6xx.c +16 −145 Original line number Diff line number Diff line Loading @@ -1151,62 +1151,6 @@ static void a6xx_sptprac_disable(struct adreno_device *adreno_dev) dev_err(&gmu->pdev->dev, "power off SPTPRAC fail\n"); } /* * a6xx_hm_enable() - Power on HM and turn on clock * @adreno_dev: Pointer to Adreno device */ static int a6xx_hm_enable(struct adreno_device *adreno_dev) { int ret; struct kgsl_device *device = KGSL_DEVICE(adreno_dev); struct kgsl_pwrctrl *pwr = &device->pwrctrl; struct gmu_device *gmu = &device->gmu; if (regulator_is_enabled(gmu->gx_gdsc)) return 0; ret = regulator_enable(gmu->gx_gdsc); if (ret) { dev_err(&gmu->pdev->dev, "Failed to turn on GPU HM HS\n"); return ret; } ret = clk_set_rate(pwr->grp_clks[0], pwr->pwrlevels[pwr->default_pwrlevel]. gpu_freq); if (ret) return ret; return clk_prepare_enable(pwr->grp_clks[0]); } /* * a6xx_hm_disable() - Turn off HM clock and power off * @adreno_dev: Pointer to Adreno device */ static int a6xx_hm_disable(struct adreno_device *adreno_dev) { struct kgsl_device *device = KGSL_DEVICE(adreno_dev); struct kgsl_pwrctrl *pwr = &device->pwrctrl; struct gmu_device *gmu = &device->gmu; if (!regulator_is_enabled(gmu->gx_gdsc)) return 0; /* Ensure that retention is on */ kgsl_gmu_regrmw(device, A6XX_GPU_CC_GX_GDSCR, 0, A6XX_RETAIN_FF_ENABLE_ENABLE_MASK); clk_disable_unprepare(pwr->grp_clks[0]); clk_set_rate(pwr->grp_clks[0], pwr->pwrlevels[pwr->num_pwrlevels - 1]. gpu_freq); return regulator_disable(gmu->gx_gdsc); } #define SPTPRAC_POWER_OFF BIT(2) #define SP_CLK_OFF BIT(4) #define GX_GDSC_POWER_OFF BIT(6) Loading Loading @@ -1257,62 +1201,6 @@ static bool a6xx_sptprac_is_on(struct adreno_device *adreno_dev) return !(val & (SPTPRAC_POWER_OFF | SP_CLK_OFF)); } /* * a6xx_hm_sptprac_enable() - Turn on HM and SPTPRAC * @device: Pointer to KGSL device */ static int a6xx_hm_sptprac_enable(struct kgsl_device *device) { int ret = 0; struct gmu_device *gmu = &device->gmu; /* If GMU does not control HM we must */ if (gmu->idle_level < GPU_HW_IFPC) { ret = a6xx_hm_enable(ADRENO_DEVICE(device)); if (ret) { dev_err(&gmu->pdev->dev, "Failed to power on GPU HM\n"); return ret; } } /* If GMU does not control SPTPRAC we must */ if (gmu->idle_level < GPU_HW_SPTP_PC) { ret = a6xx_sptprac_enable(ADRENO_DEVICE(device)); if (ret) { a6xx_hm_disable(ADRENO_DEVICE(device)); return ret; } } return ret; } /* * a6xx_hm_sptprac_disable() - Turn off SPTPRAC and HM * @device: Pointer to KGSL device */ static int a6xx_hm_sptprac_disable(struct kgsl_device *device) { int ret = 0; struct gmu_device *gmu = &device->gmu; /* If GMU does not control SPTPRAC we must */ if (gmu->idle_level < GPU_HW_SPTP_PC) a6xx_sptprac_disable(ADRENO_DEVICE(device)); /* If GMU does not control HM we must */ if (gmu->idle_level < GPU_HW_IFPC) { ret = a6xx_hm_disable(ADRENO_DEVICE(device)); if (ret) dev_err(&gmu->pdev->dev, "Failed to power off GPU HM\n"); } return ret; } /* * a6xx_gfx_rail_on() - request GMU to power GPU at given OPP. * @device: Pointer to KGSL device Loading Loading @@ -1363,6 +1251,9 @@ static int a6xx_notify_slumber(struct kgsl_device *device) /* Disable the power counter so that the GMU is not busy */ kgsl_gmu_regwrite(device, A6XX_GMU_CX_GMU_POWER_COUNTER_ENABLE, 0); /* Turn off SPTPRAC before GMU turns off GX */ a6xx_sptprac_disable(adreno_dev); if (!ADRENO_QUIRK(adreno_dev, ADRENO_QUIRK_HFI_USE_REG)) { ret = hfi_notify_slumber(gmu, perf_idx, bus_level); return ret; Loading Loading @@ -1398,7 +1289,6 @@ static int a6xx_rpmh_power_on_gpu(struct kgsl_device *device) { struct gmu_device *gmu = &device->gmu; struct device *dev = &gmu->pdev->dev; int ret = 0; /* RSC wake sequence */ kgsl_gmu_regwrite(device, A6XX_GMU_RSCC_CONTROL_REQ, BIT(1)); Loading @@ -1424,13 +1314,10 @@ static int a6xx_rpmh_power_on_gpu(struct kgsl_device *device) kgsl_gmu_regwrite(device, A6XX_GMU_RSCC_CONTROL_REQ, 0); /* Turn on the HM and SPTP head switches */ ret = a6xx_hm_sptprac_enable(device); /* Enable the power counter because it was disabled before slumber */ kgsl_gmu_regwrite(device, A6XX_GMU_CX_GMU_POWER_COUNTER_ENABLE, 1); return ret; return 0; error_rsc: dev_err(dev, "GPU RSC sequence stuck in waking up GPU\n"); return -EINVAL; Loading @@ -1440,10 +1327,7 @@ static int a6xx_rpmh_power_off_gpu(struct kgsl_device *device) { struct gmu_device *gmu = &device->gmu; const struct adreno_device *adreno_dev = ADRENO_DEVICE(device); int val, ret = 0; /* Turn off the SPTP and HM head switches */ ret = a6xx_hm_sptprac_disable(device); int val; /* RSC sleep sequence */ kgsl_gmu_regwrite(device, A6XX_RSCC_TIMESTAMP_UNIT1_EN_DRV0, 1); Loading Loading @@ -1472,7 +1356,7 @@ static int a6xx_rpmh_power_off_gpu(struct kgsl_device *device) /* FIXME: v2 has different procedure to trigger sequence */ return ret; return 0; } #define KMASK(start, n) (GENMASK((start + n), (start))) Loading Loading @@ -1564,25 +1448,12 @@ static int a6xx_gmu_fw_start(struct kgsl_device *device, case GMU_RESET: /* fall through */ case GMU_COLD_BOOT: /* Turn on the HM and SPTP head switches */ ret = a6xx_hm_sptprac_enable(device); if (ret) return ret; /* Turn on TCM retention */ kgsl_gmu_regwrite(device, A6XX_GMU_GENERAL_7, 1); if (!test_and_set_bit(GMU_BOOT_INIT_DONE, &gmu->flags)) { if (!test_and_set_bit(GMU_BOOT_INIT_DONE, &gmu->flags)) _load_gmu_rpmh_ucode(device); /* Turn on the HM and SPTP head switches */ ret = a6xx_hm_sptprac_enable(device); if (ret) return ret; } else if (boot_state == GMU_RESET) { ret = a6xx_hm_sptprac_enable(device); if (ret) return ret; } else { else if (boot_state != GMU_RESET) { ret = a6xx_rpmh_power_on_gpu(device); if (ret) return ret; Loading Loading @@ -1646,6 +1517,12 @@ static int a6xx_gmu_fw_start(struct kgsl_device *device, } } if (gmu->idle_level < GPU_HW_SPTP_PC) { ret = a6xx_sptprac_enable(adreno_dev); if (ret) return ret; } ret = a6xx_gmu_hfi_start(device); if (ret) return ret; Loading Loading @@ -1953,13 +1830,7 @@ static int a6xx_gmu_suspend(struct kgsl_device *device) /* Check no outstanding RPMh voting */ a6xx_complete_rpmh_votes(device); if (gmu->idle_level < GPU_HW_IFPC) { /* HM GDSC is controlled by KGSL */ ret = a6xx_hm_disable(ADRENO_DEVICE(device)); if (ret) dev_err(&gmu->pdev->dev, "suspend: fail: power off GPU HM\n"); } else if (gmu->gx_gdsc) { if (gmu->gx_gdsc) { if (regulator_is_enabled(gmu->gx_gdsc)) { /* Switch gx gdsc control from GMU to CPU * force non-zero reference count in clk driver Loading drivers/gpu/msm/kgsl_gmu.c +65 −63 Original line number Diff line number Diff line Loading @@ -505,7 +505,11 @@ static int rpmh_arc_cmds(struct gmu_device *gmu, } cmd_db_get_aux_data(res_id, (uint8_t *)arc->val, len); arc->num = len >> 1; for (arc->num = 1; arc->num <= MAX_GX_LEVELS; arc->num++) { if (arc->num == MAX_GX_LEVELS || arc->val[arc->num - 1] >= arc->val[arc->num]) break; } return 0; } Loading @@ -528,35 +532,42 @@ static int setup_volt_dependency_tbl(struct arc_vote_desc *votes, { int i, j, k; uint16_t cur_vlvl; bool found_match; /* i tracks current KGSL GPU frequency table entry * j tracks second rail voltage table entry * k tracks primary rail voltage table entry */ for (i = 0, k = 0; i < num_entries; k++) { if (pri_rail->val[k] != vlvl[i]) { if (k >= pri_rail->num) return -EINVAL; continue; } for (i = 0; i < num_entries; i++) { found_match = false; /* Look for a primary rail voltage that matches a VLVL level */ for (k = 0; k < pri_rail->num; k++) { if (pri_rail->val[k] == vlvl[i]) { votes[i].pri_idx = k; votes[i].vlvl = vlvl[i]; cur_vlvl = vlvl[i]; found_match = true; break; } } /* If we did not find a matching VLVL level then abort */ if (!found_match) return -EINVAL; /* find index of second rail vlvl array element that * its vlvl >= current vlvl of primary rail /* * Look for a secondary rail index whose VLVL value * is greater than or equal to the VLVL value of the * corresponding index of the primary rail */ for (j = 0; j < sec_rail->num; j++) { if (sec_rail->val[j] >= cur_vlvl) { if (sec_rail->val[j] >= cur_vlvl || j + 1 == sec_rail->num) { votes[i].sec_idx = j; break; } } if (j == sec_rail->num) votes[i].sec_idx = j; i++; } return 0; } Loading @@ -575,26 +586,25 @@ static int rpmh_arc_votes_init(struct gmu_device *gmu, struct rpmh_arc_vals *sec_rail, unsigned int type) { struct device *dev; struct kgsl_device *device = container_of(gmu, struct kgsl_device, gmu); unsigned int num_freqs; struct arc_vote_desc *votes; unsigned int vlvl_tbl[MAX_GX_LEVELS]; unsigned int *freq_tbl; int i, ret; /* * FIXME: remove below two arrays after OPP VLVL query API ready * struct dev_pm_opp *opp; */ uint16_t gpu_vlvl[] = {0, 128, 256, 384}; uint16_t cx_vlvl[] = {0, 48, 256}; struct dev_pm_opp *opp; if (type == GPU_ARC_VOTE) { num_freqs = gmu->num_gpupwrlevels; votes = gmu->rpmh_votes.gx_votes; freq_tbl = gmu->gmu_freqs; freq_tbl = gmu->gpu_freqs; dev = &device->pdev->dev; } else if (type == GMU_ARC_VOTE) { num_freqs = gmu->num_gmupwrlevels; votes = gmu->rpmh_votes.cx_votes; freq_tbl = gmu->gpu_freqs; freq_tbl = gmu->gmu_freqs; dev = &gmu->pdev->dev; } else { return -EINVAL; } Loading @@ -606,26 +616,25 @@ static int rpmh_arc_votes_init(struct gmu_device *gmu, return -EINVAL; } /* * FIXME: Find a core's voltage VLVL value based on its frequency * using OPP framework, waiting for David Colin, ETA Jan. */ memset(vlvl_tbl, 0, sizeof(vlvl_tbl)); for (i = 0; i < num_freqs; i++) { /* * opp = dev_pm_opp_find_freq_exact(&gmu->pdev->dev, * freq_tbl[i], true); * if (IS_ERR(opp)) { * dev_err(&gmu->pdev->dev, * "Failed to find opp freq %d of %s\n", * freq_tbl[i], debug_strs[type]); * return PTR_ERR(opp); * } * vlvl_tbl[i] = dev_pm_opp_get_voltage(opp); */ if (type == GPU_ARC_VOTE) vlvl_tbl[i] = gpu_vlvl[i]; else vlvl_tbl[i] = cx_vlvl[i]; /* Hardcode VLVL for 0 because it is not registered in OPP */ if (freq_tbl[i] == 0) { vlvl_tbl[i] = 0; continue; } /* Otherwise get the value from the OPP API */ opp = dev_pm_opp_find_freq_exact(dev, freq_tbl[i], true); if (IS_ERR(opp)) { dev_err(&gmu->pdev->dev, "Failed to find opp freq %d of %s\n", freq_tbl[i], debug_strs[type]); return PTR_ERR(opp); } /* Values from OPP framework are offset by 1 */ vlvl_tbl[i] = dev_pm_opp_get_voltage(opp) - 1; } ret = setup_volt_dependency_tbl(votes, Loading Loading @@ -1130,6 +1139,7 @@ int gmu_probe(struct kgsl_device *device) goto error; gmu->num_gpupwrlevels = pwr->num_pwrlevels; gmu->wakeup_pwrlevel = pwr->default_pwrlevel; for (i = 0; i < gmu->num_gpupwrlevels; i++) { int j = gmu->num_gpupwrlevels - 1 - i; Loading Loading @@ -1337,12 +1347,11 @@ static int gmu_suspend(struct kgsl_device *device) /* To be called to power on both GPU and GMU */ int gmu_start(struct kgsl_device *device) { int ret = 0, perf_idx; int ret = 0; struct adreno_device *adreno_dev = ADRENO_DEVICE(device); struct adreno_gpudev *gpudev = ADRENO_GPU_DEVICE(adreno_dev); struct kgsl_pwrctrl *pwr = &device->pwrctrl; struct gmu_device *gmu = &device->gmu; int bus_level = pwr->pwrlevels[pwr->default_pwrlevel].bus_freq; switch (device->state) { case KGSL_STATE_INIT: Loading @@ -1351,13 +1360,9 @@ int gmu_start(struct kgsl_device *device) gmu_enable_gdsc(gmu); gmu_enable_clks(gmu); /* Convert to RPMh frequency index */ perf_idx = gmu->num_gpupwrlevels - pwr->default_pwrlevel - 1; /* Vote for 300MHz DDR for GMU to init */ ret = msm_bus_scale_client_update_request(gmu->pcl, bus_level); pwr->pwrlevels[pwr->default_pwrlevel].bus_freq); if (ret) { dev_err(&gmu->pdev->dev, "Failed to allocate gmu b/w\n"); Loading @@ -1376,7 +1381,8 @@ int gmu_start(struct kgsl_device *device) goto error_gpu; /* Send default DCVS level */ ret = gmu_dcvs_set(gmu, perf_idx, bus_level); ret = gmu_dcvs_set(gmu, pwr->default_pwrlevel, pwr->pwrlevels[pwr->default_pwrlevel].bus_freq); if (ret) goto error_gpu; Loading @@ -1388,8 +1394,6 @@ int gmu_start(struct kgsl_device *device) gmu_enable_gdsc(gmu); gmu_enable_clks(gmu); perf_idx = gmu->num_gpupwrlevels - gmu->wakeup_pwrlevel - 1; ret = gpudev->rpmh_gpu_pwrctrl(adreno_dev, GMU_FW_START, GMU_WARM_BOOT, 0); if (ret) Loading @@ -1402,7 +1406,9 @@ int gmu_start(struct kgsl_device *device) goto error_gpu; if (gmu->wakeup_pwrlevel != pwr->default_pwrlevel) { ret = gmu_dcvs_set(gmu, perf_idx, bus_level); ret = gmu_dcvs_set(gmu, gmu->wakeup_pwrlevel, pwr->pwrlevels[gmu->wakeup_pwrlevel] .bus_freq); if (ret) goto error_gpu; gmu->wakeup_pwrlevel = pwr->default_pwrlevel; Loading @@ -1415,11 +1421,6 @@ int gmu_start(struct kgsl_device *device) gmu_enable_gdsc(gmu); gmu_enable_clks(gmu); perf_idx = gmu->num_gpupwrlevels - pwr->active_pwrlevel - 1; bus_level = pwr->pwrlevels[pwr->active_pwrlevel].bus_freq; ret = gpudev->rpmh_gpu_pwrctrl( adreno_dev, GMU_FW_START, GMU_RESET, 0); if (ret) Loading @@ -1432,7 +1433,9 @@ int gmu_start(struct kgsl_device *device) goto error_gpu; /* Send DCVS level prior to reset*/ ret = gmu_dcvs_set(gmu, perf_idx, bus_level); ret = gmu_dcvs_set(gmu, pwr->active_pwrlevel, pwr->pwrlevels[pwr->active_pwrlevel] .bus_freq); if (ret) goto error_gpu; Loading @@ -1441,9 +1444,8 @@ int gmu_start(struct kgsl_device *device) OOB_CPINIT_CHECK_MASK, OOB_CPINIT_CLEAR_MASK); } else { } else gmu_fast_boot(device); } break; default: break; Loading drivers/gpu/msm/kgsl_pwrctrl.c +12 −5 Original line number Diff line number Diff line Loading @@ -253,23 +253,30 @@ static int kgsl_clk_set_rate(struct kgsl_device *device, { struct gmu_device *gmu = &device->gmu; struct kgsl_pwrctrl *pwr = &device->pwrctrl; struct kgsl_pwrlevel *pl = &pwr->pwrlevels[pwrlevel]; int ret = 0; /* GMU scales GPU freq */ if (kgsl_gmu_isenabled(device)) { /* If GMU has not been started, save it */ if (!(gmu->flags & GMU_HFI_ON)) { /* In slumber the clock is off so we are done */ if (pwrlevel == (gmu->num_gpupwrlevels - 1)) return 0; gmu->wakeup_pwrlevel = pwrlevel; return 0; } /* If the GMU is on we cannot vote for the lowest level */ if (pwrlevel == (gmu->num_gpupwrlevels - 1)) { WARN(1, "Cannot set 0 GPU frequency with GMU\n"); return -EINVAL; } ret = gmu_dcvs_set(gmu, pwrlevel, INVALID_DCVS_IDX); } else { } else /* Linux clock driver scales GPU freq */ struct kgsl_pwrlevel *Pl = &pwr->pwrlevels[pwrlevel]; ret = clk_set_rate(pwr->grp_clks[0], Pl->gpu_freq); } ret = clk_set_rate(pwr->grp_clks[0], pl->gpu_freq); if (ret) KGSL_PWR_ERR(device, "GPU clk freq set failure\n"); Loading Loading
drivers/gpu/msm/adreno_a6xx.c +16 −145 Original line number Diff line number Diff line Loading @@ -1151,62 +1151,6 @@ static void a6xx_sptprac_disable(struct adreno_device *adreno_dev) dev_err(&gmu->pdev->dev, "power off SPTPRAC fail\n"); } /* * a6xx_hm_enable() - Power on HM and turn on clock * @adreno_dev: Pointer to Adreno device */ static int a6xx_hm_enable(struct adreno_device *adreno_dev) { int ret; struct kgsl_device *device = KGSL_DEVICE(adreno_dev); struct kgsl_pwrctrl *pwr = &device->pwrctrl; struct gmu_device *gmu = &device->gmu; if (regulator_is_enabled(gmu->gx_gdsc)) return 0; ret = regulator_enable(gmu->gx_gdsc); if (ret) { dev_err(&gmu->pdev->dev, "Failed to turn on GPU HM HS\n"); return ret; } ret = clk_set_rate(pwr->grp_clks[0], pwr->pwrlevels[pwr->default_pwrlevel]. gpu_freq); if (ret) return ret; return clk_prepare_enable(pwr->grp_clks[0]); } /* * a6xx_hm_disable() - Turn off HM clock and power off * @adreno_dev: Pointer to Adreno device */ static int a6xx_hm_disable(struct adreno_device *adreno_dev) { struct kgsl_device *device = KGSL_DEVICE(adreno_dev); struct kgsl_pwrctrl *pwr = &device->pwrctrl; struct gmu_device *gmu = &device->gmu; if (!regulator_is_enabled(gmu->gx_gdsc)) return 0; /* Ensure that retention is on */ kgsl_gmu_regrmw(device, A6XX_GPU_CC_GX_GDSCR, 0, A6XX_RETAIN_FF_ENABLE_ENABLE_MASK); clk_disable_unprepare(pwr->grp_clks[0]); clk_set_rate(pwr->grp_clks[0], pwr->pwrlevels[pwr->num_pwrlevels - 1]. gpu_freq); return regulator_disable(gmu->gx_gdsc); } #define SPTPRAC_POWER_OFF BIT(2) #define SP_CLK_OFF BIT(4) #define GX_GDSC_POWER_OFF BIT(6) Loading Loading @@ -1257,62 +1201,6 @@ static bool a6xx_sptprac_is_on(struct adreno_device *adreno_dev) return !(val & (SPTPRAC_POWER_OFF | SP_CLK_OFF)); } /* * a6xx_hm_sptprac_enable() - Turn on HM and SPTPRAC * @device: Pointer to KGSL device */ static int a6xx_hm_sptprac_enable(struct kgsl_device *device) { int ret = 0; struct gmu_device *gmu = &device->gmu; /* If GMU does not control HM we must */ if (gmu->idle_level < GPU_HW_IFPC) { ret = a6xx_hm_enable(ADRENO_DEVICE(device)); if (ret) { dev_err(&gmu->pdev->dev, "Failed to power on GPU HM\n"); return ret; } } /* If GMU does not control SPTPRAC we must */ if (gmu->idle_level < GPU_HW_SPTP_PC) { ret = a6xx_sptprac_enable(ADRENO_DEVICE(device)); if (ret) { a6xx_hm_disable(ADRENO_DEVICE(device)); return ret; } } return ret; } /* * a6xx_hm_sptprac_disable() - Turn off SPTPRAC and HM * @device: Pointer to KGSL device */ static int a6xx_hm_sptprac_disable(struct kgsl_device *device) { int ret = 0; struct gmu_device *gmu = &device->gmu; /* If GMU does not control SPTPRAC we must */ if (gmu->idle_level < GPU_HW_SPTP_PC) a6xx_sptprac_disable(ADRENO_DEVICE(device)); /* If GMU does not control HM we must */ if (gmu->idle_level < GPU_HW_IFPC) { ret = a6xx_hm_disable(ADRENO_DEVICE(device)); if (ret) dev_err(&gmu->pdev->dev, "Failed to power off GPU HM\n"); } return ret; } /* * a6xx_gfx_rail_on() - request GMU to power GPU at given OPP. * @device: Pointer to KGSL device Loading Loading @@ -1363,6 +1251,9 @@ static int a6xx_notify_slumber(struct kgsl_device *device) /* Disable the power counter so that the GMU is not busy */ kgsl_gmu_regwrite(device, A6XX_GMU_CX_GMU_POWER_COUNTER_ENABLE, 0); /* Turn off SPTPRAC before GMU turns off GX */ a6xx_sptprac_disable(adreno_dev); if (!ADRENO_QUIRK(adreno_dev, ADRENO_QUIRK_HFI_USE_REG)) { ret = hfi_notify_slumber(gmu, perf_idx, bus_level); return ret; Loading Loading @@ -1398,7 +1289,6 @@ static int a6xx_rpmh_power_on_gpu(struct kgsl_device *device) { struct gmu_device *gmu = &device->gmu; struct device *dev = &gmu->pdev->dev; int ret = 0; /* RSC wake sequence */ kgsl_gmu_regwrite(device, A6XX_GMU_RSCC_CONTROL_REQ, BIT(1)); Loading @@ -1424,13 +1314,10 @@ static int a6xx_rpmh_power_on_gpu(struct kgsl_device *device) kgsl_gmu_regwrite(device, A6XX_GMU_RSCC_CONTROL_REQ, 0); /* Turn on the HM and SPTP head switches */ ret = a6xx_hm_sptprac_enable(device); /* Enable the power counter because it was disabled before slumber */ kgsl_gmu_regwrite(device, A6XX_GMU_CX_GMU_POWER_COUNTER_ENABLE, 1); return ret; return 0; error_rsc: dev_err(dev, "GPU RSC sequence stuck in waking up GPU\n"); return -EINVAL; Loading @@ -1440,10 +1327,7 @@ static int a6xx_rpmh_power_off_gpu(struct kgsl_device *device) { struct gmu_device *gmu = &device->gmu; const struct adreno_device *adreno_dev = ADRENO_DEVICE(device); int val, ret = 0; /* Turn off the SPTP and HM head switches */ ret = a6xx_hm_sptprac_disable(device); int val; /* RSC sleep sequence */ kgsl_gmu_regwrite(device, A6XX_RSCC_TIMESTAMP_UNIT1_EN_DRV0, 1); Loading Loading @@ -1472,7 +1356,7 @@ static int a6xx_rpmh_power_off_gpu(struct kgsl_device *device) /* FIXME: v2 has different procedure to trigger sequence */ return ret; return 0; } #define KMASK(start, n) (GENMASK((start + n), (start))) Loading Loading @@ -1564,25 +1448,12 @@ static int a6xx_gmu_fw_start(struct kgsl_device *device, case GMU_RESET: /* fall through */ case GMU_COLD_BOOT: /* Turn on the HM and SPTP head switches */ ret = a6xx_hm_sptprac_enable(device); if (ret) return ret; /* Turn on TCM retention */ kgsl_gmu_regwrite(device, A6XX_GMU_GENERAL_7, 1); if (!test_and_set_bit(GMU_BOOT_INIT_DONE, &gmu->flags)) { if (!test_and_set_bit(GMU_BOOT_INIT_DONE, &gmu->flags)) _load_gmu_rpmh_ucode(device); /* Turn on the HM and SPTP head switches */ ret = a6xx_hm_sptprac_enable(device); if (ret) return ret; } else if (boot_state == GMU_RESET) { ret = a6xx_hm_sptprac_enable(device); if (ret) return ret; } else { else if (boot_state != GMU_RESET) { ret = a6xx_rpmh_power_on_gpu(device); if (ret) return ret; Loading Loading @@ -1646,6 +1517,12 @@ static int a6xx_gmu_fw_start(struct kgsl_device *device, } } if (gmu->idle_level < GPU_HW_SPTP_PC) { ret = a6xx_sptprac_enable(adreno_dev); if (ret) return ret; } ret = a6xx_gmu_hfi_start(device); if (ret) return ret; Loading Loading @@ -1953,13 +1830,7 @@ static int a6xx_gmu_suspend(struct kgsl_device *device) /* Check no outstanding RPMh voting */ a6xx_complete_rpmh_votes(device); if (gmu->idle_level < GPU_HW_IFPC) { /* HM GDSC is controlled by KGSL */ ret = a6xx_hm_disable(ADRENO_DEVICE(device)); if (ret) dev_err(&gmu->pdev->dev, "suspend: fail: power off GPU HM\n"); } else if (gmu->gx_gdsc) { if (gmu->gx_gdsc) { if (regulator_is_enabled(gmu->gx_gdsc)) { /* Switch gx gdsc control from GMU to CPU * force non-zero reference count in clk driver Loading
drivers/gpu/msm/kgsl_gmu.c +65 −63 Original line number Diff line number Diff line Loading @@ -505,7 +505,11 @@ static int rpmh_arc_cmds(struct gmu_device *gmu, } cmd_db_get_aux_data(res_id, (uint8_t *)arc->val, len); arc->num = len >> 1; for (arc->num = 1; arc->num <= MAX_GX_LEVELS; arc->num++) { if (arc->num == MAX_GX_LEVELS || arc->val[arc->num - 1] >= arc->val[arc->num]) break; } return 0; } Loading @@ -528,35 +532,42 @@ static int setup_volt_dependency_tbl(struct arc_vote_desc *votes, { int i, j, k; uint16_t cur_vlvl; bool found_match; /* i tracks current KGSL GPU frequency table entry * j tracks second rail voltage table entry * k tracks primary rail voltage table entry */ for (i = 0, k = 0; i < num_entries; k++) { if (pri_rail->val[k] != vlvl[i]) { if (k >= pri_rail->num) return -EINVAL; continue; } for (i = 0; i < num_entries; i++) { found_match = false; /* Look for a primary rail voltage that matches a VLVL level */ for (k = 0; k < pri_rail->num; k++) { if (pri_rail->val[k] == vlvl[i]) { votes[i].pri_idx = k; votes[i].vlvl = vlvl[i]; cur_vlvl = vlvl[i]; found_match = true; break; } } /* If we did not find a matching VLVL level then abort */ if (!found_match) return -EINVAL; /* find index of second rail vlvl array element that * its vlvl >= current vlvl of primary rail /* * Look for a secondary rail index whose VLVL value * is greater than or equal to the VLVL value of the * corresponding index of the primary rail */ for (j = 0; j < sec_rail->num; j++) { if (sec_rail->val[j] >= cur_vlvl) { if (sec_rail->val[j] >= cur_vlvl || j + 1 == sec_rail->num) { votes[i].sec_idx = j; break; } } if (j == sec_rail->num) votes[i].sec_idx = j; i++; } return 0; } Loading @@ -575,26 +586,25 @@ static int rpmh_arc_votes_init(struct gmu_device *gmu, struct rpmh_arc_vals *sec_rail, unsigned int type) { struct device *dev; struct kgsl_device *device = container_of(gmu, struct kgsl_device, gmu); unsigned int num_freqs; struct arc_vote_desc *votes; unsigned int vlvl_tbl[MAX_GX_LEVELS]; unsigned int *freq_tbl; int i, ret; /* * FIXME: remove below two arrays after OPP VLVL query API ready * struct dev_pm_opp *opp; */ uint16_t gpu_vlvl[] = {0, 128, 256, 384}; uint16_t cx_vlvl[] = {0, 48, 256}; struct dev_pm_opp *opp; if (type == GPU_ARC_VOTE) { num_freqs = gmu->num_gpupwrlevels; votes = gmu->rpmh_votes.gx_votes; freq_tbl = gmu->gmu_freqs; freq_tbl = gmu->gpu_freqs; dev = &device->pdev->dev; } else if (type == GMU_ARC_VOTE) { num_freqs = gmu->num_gmupwrlevels; votes = gmu->rpmh_votes.cx_votes; freq_tbl = gmu->gpu_freqs; freq_tbl = gmu->gmu_freqs; dev = &gmu->pdev->dev; } else { return -EINVAL; } Loading @@ -606,26 +616,25 @@ static int rpmh_arc_votes_init(struct gmu_device *gmu, return -EINVAL; } /* * FIXME: Find a core's voltage VLVL value based on its frequency * using OPP framework, waiting for David Colin, ETA Jan. */ memset(vlvl_tbl, 0, sizeof(vlvl_tbl)); for (i = 0; i < num_freqs; i++) { /* * opp = dev_pm_opp_find_freq_exact(&gmu->pdev->dev, * freq_tbl[i], true); * if (IS_ERR(opp)) { * dev_err(&gmu->pdev->dev, * "Failed to find opp freq %d of %s\n", * freq_tbl[i], debug_strs[type]); * return PTR_ERR(opp); * } * vlvl_tbl[i] = dev_pm_opp_get_voltage(opp); */ if (type == GPU_ARC_VOTE) vlvl_tbl[i] = gpu_vlvl[i]; else vlvl_tbl[i] = cx_vlvl[i]; /* Hardcode VLVL for 0 because it is not registered in OPP */ if (freq_tbl[i] == 0) { vlvl_tbl[i] = 0; continue; } /* Otherwise get the value from the OPP API */ opp = dev_pm_opp_find_freq_exact(dev, freq_tbl[i], true); if (IS_ERR(opp)) { dev_err(&gmu->pdev->dev, "Failed to find opp freq %d of %s\n", freq_tbl[i], debug_strs[type]); return PTR_ERR(opp); } /* Values from OPP framework are offset by 1 */ vlvl_tbl[i] = dev_pm_opp_get_voltage(opp) - 1; } ret = setup_volt_dependency_tbl(votes, Loading Loading @@ -1130,6 +1139,7 @@ int gmu_probe(struct kgsl_device *device) goto error; gmu->num_gpupwrlevels = pwr->num_pwrlevels; gmu->wakeup_pwrlevel = pwr->default_pwrlevel; for (i = 0; i < gmu->num_gpupwrlevels; i++) { int j = gmu->num_gpupwrlevels - 1 - i; Loading Loading @@ -1337,12 +1347,11 @@ static int gmu_suspend(struct kgsl_device *device) /* To be called to power on both GPU and GMU */ int gmu_start(struct kgsl_device *device) { int ret = 0, perf_idx; int ret = 0; struct adreno_device *adreno_dev = ADRENO_DEVICE(device); struct adreno_gpudev *gpudev = ADRENO_GPU_DEVICE(adreno_dev); struct kgsl_pwrctrl *pwr = &device->pwrctrl; struct gmu_device *gmu = &device->gmu; int bus_level = pwr->pwrlevels[pwr->default_pwrlevel].bus_freq; switch (device->state) { case KGSL_STATE_INIT: Loading @@ -1351,13 +1360,9 @@ int gmu_start(struct kgsl_device *device) gmu_enable_gdsc(gmu); gmu_enable_clks(gmu); /* Convert to RPMh frequency index */ perf_idx = gmu->num_gpupwrlevels - pwr->default_pwrlevel - 1; /* Vote for 300MHz DDR for GMU to init */ ret = msm_bus_scale_client_update_request(gmu->pcl, bus_level); pwr->pwrlevels[pwr->default_pwrlevel].bus_freq); if (ret) { dev_err(&gmu->pdev->dev, "Failed to allocate gmu b/w\n"); Loading @@ -1376,7 +1381,8 @@ int gmu_start(struct kgsl_device *device) goto error_gpu; /* Send default DCVS level */ ret = gmu_dcvs_set(gmu, perf_idx, bus_level); ret = gmu_dcvs_set(gmu, pwr->default_pwrlevel, pwr->pwrlevels[pwr->default_pwrlevel].bus_freq); if (ret) goto error_gpu; Loading @@ -1388,8 +1394,6 @@ int gmu_start(struct kgsl_device *device) gmu_enable_gdsc(gmu); gmu_enable_clks(gmu); perf_idx = gmu->num_gpupwrlevels - gmu->wakeup_pwrlevel - 1; ret = gpudev->rpmh_gpu_pwrctrl(adreno_dev, GMU_FW_START, GMU_WARM_BOOT, 0); if (ret) Loading @@ -1402,7 +1406,9 @@ int gmu_start(struct kgsl_device *device) goto error_gpu; if (gmu->wakeup_pwrlevel != pwr->default_pwrlevel) { ret = gmu_dcvs_set(gmu, perf_idx, bus_level); ret = gmu_dcvs_set(gmu, gmu->wakeup_pwrlevel, pwr->pwrlevels[gmu->wakeup_pwrlevel] .bus_freq); if (ret) goto error_gpu; gmu->wakeup_pwrlevel = pwr->default_pwrlevel; Loading @@ -1415,11 +1421,6 @@ int gmu_start(struct kgsl_device *device) gmu_enable_gdsc(gmu); gmu_enable_clks(gmu); perf_idx = gmu->num_gpupwrlevels - pwr->active_pwrlevel - 1; bus_level = pwr->pwrlevels[pwr->active_pwrlevel].bus_freq; ret = gpudev->rpmh_gpu_pwrctrl( adreno_dev, GMU_FW_START, GMU_RESET, 0); if (ret) Loading @@ -1432,7 +1433,9 @@ int gmu_start(struct kgsl_device *device) goto error_gpu; /* Send DCVS level prior to reset*/ ret = gmu_dcvs_set(gmu, perf_idx, bus_level); ret = gmu_dcvs_set(gmu, pwr->active_pwrlevel, pwr->pwrlevels[pwr->active_pwrlevel] .bus_freq); if (ret) goto error_gpu; Loading @@ -1441,9 +1444,8 @@ int gmu_start(struct kgsl_device *device) OOB_CPINIT_CHECK_MASK, OOB_CPINIT_CLEAR_MASK); } else { } else gmu_fast_boot(device); } break; default: break; Loading
drivers/gpu/msm/kgsl_pwrctrl.c +12 −5 Original line number Diff line number Diff line Loading @@ -253,23 +253,30 @@ static int kgsl_clk_set_rate(struct kgsl_device *device, { struct gmu_device *gmu = &device->gmu; struct kgsl_pwrctrl *pwr = &device->pwrctrl; struct kgsl_pwrlevel *pl = &pwr->pwrlevels[pwrlevel]; int ret = 0; /* GMU scales GPU freq */ if (kgsl_gmu_isenabled(device)) { /* If GMU has not been started, save it */ if (!(gmu->flags & GMU_HFI_ON)) { /* In slumber the clock is off so we are done */ if (pwrlevel == (gmu->num_gpupwrlevels - 1)) return 0; gmu->wakeup_pwrlevel = pwrlevel; return 0; } /* If the GMU is on we cannot vote for the lowest level */ if (pwrlevel == (gmu->num_gpupwrlevels - 1)) { WARN(1, "Cannot set 0 GPU frequency with GMU\n"); return -EINVAL; } ret = gmu_dcvs_set(gmu, pwrlevel, INVALID_DCVS_IDX); } else { } else /* Linux clock driver scales GPU freq */ struct kgsl_pwrlevel *Pl = &pwr->pwrlevels[pwrlevel]; ret = clk_set_rate(pwr->grp_clks[0], Pl->gpu_freq); } ret = clk_set_rate(pwr->grp_clks[0], pl->gpu_freq); if (ret) KGSL_PWR_ERR(device, "GPU clk freq set failure\n"); Loading