int kgsl_devfreq_target(struct device *dev, unsigned long *freq, u32 flags) { struct kgsl_device *device = dev_get_drvdata(dev); struct kgsl_pwrctrl *pwr; int level, i, b; unsigned long cur_freq; if (device == NULL) return -ENODEV; if (freq == NULL) return -EINVAL; if (!device->pwrscale.enabled) return 0; pwr = &device->pwrctrl; kgsl_mutex_lock(&device->mutex, &device->mutex_owner); cur_freq = kgsl_pwrctrl_active_freq(pwr); level = pwr->active_pwrlevel; if (*freq != cur_freq) { level = pwr->max_pwrlevel; for (i = pwr->min_pwrlevel; i >= pwr->max_pwrlevel; i--) if (*freq <= pwr->pwrlevels[i].gpu_freq) { level = i; break; } } else if (flags && pwr->bus_control) { b = pwr->bus_mod; if ((flags & DEVFREQ_FLAG_FAST_HINT) && (pwr->bus_mod != FAST_BUS)) pwr->bus_mod = (pwr->bus_mod == SLOW_BUS) ? 0 : FAST_BUS; else if ((flags & DEVFREQ_FLAG_SLOW_HINT) && (pwr->bus_mod != SLOW_BUS)) pwr->bus_mod = (pwr->bus_mod == FAST_BUS) ? 0 : SLOW_BUS; if (pwr->bus_mod != b) kgsl_pwrctrl_buslevel_update(device, true); } if ((pwr->constraint.type != KGSL_CONSTRAINT_NONE) && (!time_after(jiffies, pwr->constraint.expires)) && (level >= pwr->constraint.hint.pwrlevel.level)) *freq = cur_freq; else { kgsl_pwrctrl_pwrlevel_change(device, level); pwr->constraint.type = KGSL_CONSTRAINT_NONE; pwr->constraint.expires = 0; *freq = kgsl_pwrctrl_active_freq(pwr); } kgsl_mutex_unlock(&device->mutex, &device->mutex_owner); return 0; }
/* * kgsl_devfreq_target - devfreq_dev_profile.target callback * @dev: see devfreq.h * @freq: see devfreq.h * @flags: see devfreq.h * * This function expects the device mutex to be unlocked. */ int kgsl_devfreq_target(struct device *dev, unsigned long *freq, u32 flags) { struct kgsl_device *device = dev_get_drvdata(dev); struct kgsl_pwrctrl *pwr; int level, i, b; unsigned long cur_freq; if (device == NULL) return -ENODEV; if (freq == NULL) return -EINVAL; if (!device->pwrscale.enabled) return 0; pwr = &device->pwrctrl; kgsl_mutex_lock(&device->mutex, &device->mutex_owner); cur_freq = kgsl_pwrctrl_active_freq(pwr); level = pwr->active_pwrlevel; if (*freq != cur_freq) { level = pwr->max_pwrlevel; for (i = pwr->min_pwrlevel; i >= pwr->max_pwrlevel; i--) if (*freq <= pwr->pwrlevels[i].gpu_freq) { level = i; break; } } else if (flags && pwr->bus_control) { /* * Signal for faster or slower bus. If KGSL isn't already * running at the desired speed for the given level, modify * its vote. */ b = pwr->bus_mod; if ((flags & DEVFREQ_FLAG_FAST_HINT) && (pwr->bus_mod != FAST_BUS)) pwr->bus_mod = (pwr->bus_mod == SLOW_BUS) ? 0 : FAST_BUS; else if ((flags & DEVFREQ_FLAG_SLOW_HINT) && (pwr->bus_mod != SLOW_BUS)) pwr->bus_mod = (pwr->bus_mod == FAST_BUS) ? 0 : SLOW_BUS; if (pwr->bus_mod != b) kgsl_pwrctrl_buslevel_update(device, true); } kgsl_pwrctrl_pwrlevel_change(device, level); *freq = kgsl_pwrctrl_active_freq(pwr); kgsl_mutex_unlock(&device->mutex, &device->mutex_owner); return 0; }
/* * kgsl_busmon_target - devfreq_dev_profile.target callback * @dev: see devfreq.h * @freq: see devfreq.h * @flags: see devfreq.h * * This function expects the device mutex to be unlocked. */ int kgsl_busmon_target(struct device *dev, unsigned long *freq, u32 flags) { struct kgsl_device *device = dev_get_drvdata(dev); struct kgsl_pwrctrl *pwr; struct kgsl_pwrlevel *pwr_level; int level, b; u32 bus_flag; if (device == NULL) return -ENODEV; if (freq == NULL) return -EINVAL; if (!device->pwrscale.enabled) return 0; pwr = &device->pwrctrl; if (!pwr->bus_control) return 0; mutex_lock(&device->mutex); level = pwr->active_pwrlevel; pwr_level = &pwr->pwrlevels[level]; bus_flag = device->pwrscale.bus_profile.flag; device->pwrscale.bus_profile.flag = 0; /* * Bus devfreq governor has calculated its recomendations * when gpu was running with *freq frequency. * If the gpu frequency is different now it's better to * ignore the call */ if (pwr_level->gpu_freq != *freq) { mutex_unlock(&device->mutex); return 0; } b = pwr->bus_mod; if ((bus_flag & DEVFREQ_FLAG_FAST_HINT) && ((pwr_level->bus_freq + pwr->bus_mod) < pwr_level->bus_max)) pwr->bus_mod++; else if ((bus_flag & DEVFREQ_FLAG_SLOW_HINT) && ((pwr_level->bus_freq + pwr->bus_mod) > pwr_level->bus_min)) pwr->bus_mod--; if (pwr->bus_mod != b) kgsl_pwrctrl_buslevel_update(device, true); mutex_unlock(&device->mutex); return 0; }
int kgsl_devfreq_target(struct device *dev, unsigned long *freq, u32 flags) { struct kgsl_device *device = dev_get_drvdata(dev); struct kgsl_pwrctrl *pwr; int level, i, b; unsigned long cur_freq; if (device == NULL) return -ENODEV; if (freq == NULL) return -EINVAL; if (!device->pwrscale.enabled) return 0; pwr = &device->pwrctrl; mutex_lock(&device->mutex); cur_freq = kgsl_pwrctrl_active_freq(pwr); level = pwr->active_pwrlevel; if (*freq != cur_freq) { level = pwr->max_pwrlevel; for (i = pwr->min_pwrlevel; i >= pwr->max_pwrlevel; i--) if (*freq <= pwr->pwrlevels[i].gpu_freq) { level = i; break; } } else if (flags && pwr->bus_control) { b = pwr->bus_mod; if ((flags & DEVFREQ_FLAG_FAST_HINT) && (pwr->bus_mod != FAST_BUS)) pwr->bus_mod = (pwr->bus_mod == SLOW_BUS) ? 0 : FAST_BUS; else if ((flags & DEVFREQ_FLAG_SLOW_HINT) && (pwr->bus_mod != SLOW_BUS)) pwr->bus_mod = (pwr->bus_mod == FAST_BUS) ? 0 : SLOW_BUS; if (pwr->bus_mod != b) kgsl_pwrctrl_buslevel_update(device, true); } kgsl_pwrctrl_pwrlevel_change(device, level); *freq = kgsl_pwrctrl_active_freq(pwr); mutex_unlock(&device->mutex); return 0; }
/* * kgsl_devfreq_target - devfreq_dev_profile.target callback * @dev: see devfreq.h * @freq: see devfreq.h * @flags: see devfreq.h * * This function expects the device mutex to be unlocked. */ int kgsl_devfreq_target(struct device *dev, unsigned long *freq, u32 flags) { struct kgsl_device *device = dev_get_drvdata(dev); struct kgsl_pwrctrl *pwr; int level, i, b; unsigned long cur_freq; if (device == NULL) return -ENODEV; if (freq == NULL) return -EINVAL; if (!device->pwrscale.enabled) return 0; pwr = &device->pwrctrl; if (flags & DEVFREQ_FLAG_WAKEUP_MAXFREQ) { /* * The GPU is about to get suspended, * but it needs to be at the max power level when waking up */ pwr->wakeup_maxpwrlevel = 1; return 0; } kgsl_mutex_lock(&device->mutex, &device->mutex_owner); cur_freq = kgsl_pwrctrl_active_freq(pwr); level = pwr->active_pwrlevel; if (*freq != cur_freq) { level = pwr->max_pwrlevel; for (i = pwr->min_pwrlevel; i >= pwr->max_pwrlevel; i--) if (*freq <= pwr->pwrlevels[i].gpu_freq) { level = i; break; } } else if (flags && pwr->bus_control) { /* * Signal for faster or slower bus. If KGSL isn't already * running at the desired speed for the given level, modify * its vote. */ b = pwr->bus_mod; if ((flags & DEVFREQ_FLAG_FAST_HINT) && (pwr->bus_mod != FAST_BUS)) pwr->bus_mod = (pwr->bus_mod == SLOW_BUS) ? 0 : FAST_BUS; else if ((flags & DEVFREQ_FLAG_SLOW_HINT) && (pwr->bus_mod != SLOW_BUS)) pwr->bus_mod = (pwr->bus_mod == FAST_BUS) ? 0 : SLOW_BUS; if (pwr->bus_mod != b) kgsl_pwrctrl_buslevel_update(device, true); } /* * The power constraints need an entire interval to do their magic, so * skip changing the powerlevel if the time hasn't expired yet and the * new level is less than the constraint */ if ((pwr->constraint.type != KGSL_CONSTRAINT_NONE) && (!time_after(jiffies, pwr->constraint.expires)) && (level >= pwr->constraint.hint.pwrlevel.level)) *freq = cur_freq; else { /* Change the power level */ kgsl_pwrctrl_pwrlevel_change(device, level); /*Invalidate the constraint set */ pwr->constraint.type = KGSL_CONSTRAINT_NONE; pwr->constraint.expires = 0; *freq = kgsl_pwrctrl_active_freq(pwr); } kgsl_mutex_unlock(&device->mutex, &device->mutex_owner); return 0; }