<commit_before>/* Copyright (c) 2010-2013, The Linux Foundation. All rights reserved.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 and
 * only version 2 as published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 */

#include <linux/export.h>
#include <linux/interrupt.h>
#include <asm/page.h>
#include <linux/pm_runtime.h>
#include <mach/msm_iomap.h>
#include <mach/msm_bus.h>
#include <mach/msm_bus_board.h>
#include <linux/ktime.h>
#include <linux/delay.h>

#include "kgsl.h"
#include "kgsl_pwrscale.h"
#include "kgsl_device.h"
#include "kgsl_trace.h"
#include "kgsl_sharedmem.h"

#define KGSL_PWRFLAGS_POWER_ON 0
#define KGSL_PWRFLAGS_CLK_ON   1
#define KGSL_PWRFLAGS_AXI_ON   2
#define KGSL_PWRFLAGS_IRQ_ON   3

#define UPDATE_BUSY_VAL		1000000
#define UPDATE_BUSY		50

/*
 * Expected delay for post-interrupt processing on A3xx.
 * The delay may be longer, gradually increase the delay
 * to compensate.  If the GPU isn't done by max delay,
 * it's working on something other than just the final
 * command sequence so stop waiting for it to be idle.
 */
#define INIT_UDELAY		200
#define MAX_UDELAY		2000

struct clk_pair {
	const char *name;
	uint map;
};

static struct clk_pair clks[KGSL_MAX_CLKS] = {
	{
		.name = "src_clk",
		.map = KGSL_CLK_SRC,
	},
	{
		.name = "core_clk",
		.map = KGSL_CLK_CORE,
	},
	{
		.name = "iface_clk",
		.map = KGSL_CLK_IFACE,
	},
	{
		.name = "mem_clk",
		.map = KGSL_CLK_MEM,
	},
	{
		.name = "mem_iface_clk",
		.map = KGSL_CLK_MEM_IFACE,
	},
	{
		.name = "alt_mem_iface_clk",
		.map = KGSL_CLK_ALT_MEM_IFACE,
	},
};

static void kgsl_pwrctrl_axi(struct kgsl_device *device, int state);
static void kgsl_pwrctrl_pwrrail(struct kgsl_device *device, int state);

/* Update the elapsed time at a particular clock level
 * if the device is active(on_time = true).Otherwise
 * store it as sleep time.
 */
static void update_clk_statistics(struct kgsl_device *device,
				bool on_time)
{
	struct kgsl_pwrctrl *pwr = &device->pwrctrl;
	struct kgsl_clk_stats *clkstats = &pwr->clk_stats;
	ktime_t elapsed;
	int elapsed_us;
	if (clkstats->start.tv64 == 0)
		clkstats->start = ktime_get();
	clkstats->stop = ktime_get();
	elapsed = ktime_sub(clkstats->stop, clkstats->start);
	elapsed_us = ktime_to_us(elapsed);
	clkstats->elapsed += elapsed_us;
	if (on_time)
		clkstats->clock_time[pwr->active_pwrlevel] += elapsed_us;
	else
		clkstats->clock_time[pwr->num_pwrlevels - 1] += elapsed_us;
	clkstats->start = ktime_get();
}

/*
 * Given a requested power level do bounds checking on the constraints and
 * return the nearest possible level
 */

static inline int _adjust_pwrlevel(struct kgsl_pwrctrl *pwr, int level)
{
	int max_pwrlevel = max_t(int, pwr->thermal_pwrlevel, pwr->max_pwrlevel);
	int min_pwrlevel = max_t(int, pwr->thermal_pwrlevel, pwr->min_pwrlevel);

	if (level < max_pwrlevel)
		return max_pwrlevel;
	if (level > min_pwrlevel)
		return min_pwrlevel;

	return level;
}

void kgsl_pwrctrl_buslevel_update(struct kgsl_device *device,
			bool on)
{
	struct kgsl_pwrctrl *pwr = &device->pwrctrl;
	int cur = pwr->pwrlevels[pwr->active_pwrlevel].bus_freq;
	int buslevel = 0;
	if (!pwr->pcl)
		return;
	/*
	 * If the bus should remain on calculate our request and submit it,
	 * otherwise request bus level 0, off.
	 */
	if (on) {
		buslevel = min_t(int, pwr->pwrlevels[0].bus_freq,
				cur + pwr->bus_mod);
		buslevel = max_t(int, buslevel, 1);
	}
	msm_bus_scale_client_update_request(pwr->pcl, buslevel);
	trace_kgsl_pwrlevel(device, pwr->active_pwrlevel, buslevel);
}
EXPORT_SYMBOL(kgsl_pwrctrl_buslevel_update);

void kgsl_pwrctrl_pwrlevel_change(struct kgsl_device *device,
				unsigned int new_level)
{
	struct kgsl_pwrctrl *pwr = &device->pwrctrl;
	struct kgsl_pwrlevel *pwrlevel;
	int delta, level;

	/* Adjust the power level to the current constraints */
	new_level = _adjust_pwrlevel(pwr, new_level);

	if (new_level == pwr->active_pwrlevel)
		return;

	delta = new_level < pwr->active_pwrlevel ? -1 : 1;

	update_clk_statistics(device, true);

	level = pwr->active_pwrlevel;

	/*
	 * Set the active powerlevel first in case the clocks are off - if we
	 * don't do this then the pwrlevel change won't take effect when the
	 * clocks come back
	 */

	pwr->active_pwrlevel = new_level;
	pwr->bus_mod = 0;
	pwrlevel = &pwr->pwrlevels[pwr->active_pwrlevel];

	if (test_bit(KGSL_PWRFLAGS_AXI_ON, &pwr->power_flags))
		kgsl_pwrctrl_buslevel_update(device, true);

	if (test_bit(KGSL_PWRFLAGS_CLK_ON, &pwr->power_flags) ||
		(device->state == KGSL_STATE_NAP)) {

		/*
		 * Don't shift by more than one level at a time to
		 * avoid glitches.
		 */

		while (level != new_level) {
			level += delta;

			clk_set_rate(pwr->grp_clks[0],
				pwr->pwrlevels[level].gpu_freq);
		}
	}


	trace_kgsl_pwrlevel(device, pwr->active_pwrlevel, pwrlevel->gpu_freq);
}
<commit_msg>msm: kgsl: devfreq_target requests can happen during SLUMBER<commit_after>/* Copyright (c) 2010-2013, The Linux Foundation. All rights reserved.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 and
 * only version 2 as published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 */

#include <linux/export.h>
#include <linux/interrupt.h>
#include <asm/page.h>
#include <linux/pm_runtime.h>
#include <mach/msm_iomap.h>
#include <mach/msm_bus.h>
#include <mach/msm_bus_board.h>
#include <linux/ktime.h>
#include <linux/delay.h>

#include "kgsl.h"
#include "kgsl_pwrscale.h"
#include "kgsl_device.h"
#include "kgsl_trace.h"
#include "kgsl_sharedmem.h"

#define KGSL_PWRFLAGS_POWER_ON 0
#define KGSL_PWRFLAGS_CLK_ON   1
#define KGSL_PWRFLAGS_AXI_ON   2
#define KGSL_PWRFLAGS_IRQ_ON   3

#define UPDATE_BUSY_VAL		1000000
#define UPDATE_BUSY		50

/*
 * Expected delay for post-interrupt processing on A3xx.
 * The delay may be longer, gradually increase the delay
 * to compensate.  If the GPU isn't done by max delay,
 * it's working on something other than just the final
 * command sequence so stop waiting for it to be idle.
 */
#define INIT_UDELAY		200
#define MAX_UDELAY		2000

struct clk_pair {
	const char *name;
	uint map;
};

static struct clk_pair clks[KGSL_MAX_CLKS] = {
	{
		.name = "src_clk",
		.map = KGSL_CLK_SRC,
	},
	{
		.name = "core_clk",
		.map = KGSL_CLK_CORE,
	},
	{
		.name = "iface_clk",
		.map = KGSL_CLK_IFACE,
	},
	{
		.name = "mem_clk",
		.map = KGSL_CLK_MEM,
	},
	{
		.name = "mem_iface_clk",
		.map = KGSL_CLK_MEM_IFACE,
	},
	{
		.name = "alt_mem_iface_clk",
		.map = KGSL_CLK_ALT_MEM_IFACE,
	},
};

static void kgsl_pwrctrl_axi(struct kgsl_device *device, int state);
static void kgsl_pwrctrl_pwrrail(struct kgsl_device *device, int state);

/* Update the elapsed time at a particular clock level
 * if the device is active(on_time = true).Otherwise
 * store it as sleep time.
 */
static void update_clk_statistics(struct kgsl_device *device,
				bool on_time)
{
	struct kgsl_pwrctrl *pwr = &device->pwrctrl;
	struct kgsl_clk_stats *clkstats = &pwr->clk_stats;
	ktime_t elapsed;
	int elapsed_us;
	if (clkstats->start.tv64 == 0)
		clkstats->start = ktime_get();
	clkstats->stop = ktime_get();
	elapsed = ktime_sub(clkstats->stop, clkstats->start);
	elapsed_us = ktime_to_us(elapsed);
	clkstats->elapsed += elapsed_us;
	if (on_time)
		clkstats->clock_time[pwr->active_pwrlevel] += elapsed_us;
	else
		clkstats->clock_time[pwr->num_pwrlevels - 1] += elapsed_us;
	clkstats->start = ktime_get();
}

/*
 * Given a requested power level do bounds checking on the constraints and
 * return the nearest possible level
 */

static inline int _adjust_pwrlevel(struct kgsl_pwrctrl *pwr, int level)
{
	int max_pwrlevel = max_t(int, pwr->thermal_pwrlevel, pwr->max_pwrlevel);
	int min_pwrlevel = max_t(int, pwr->thermal_pwrlevel, pwr->min_pwrlevel);

	if (level < max_pwrlevel)
		return max_pwrlevel;
	if (level > min_pwrlevel)
		return min_pwrlevel;

	return level;
}

void kgsl_pwrctrl_buslevel_update(struct kgsl_device *device,
			bool on)
{
	struct kgsl_pwrctrl *pwr = &device->pwrctrl;
	int cur = pwr->pwrlevels[pwr->active_pwrlevel].bus_freq;
	int buslevel = 0;
	if (!pwr->pcl)
		return;
	/* the bus should be ON to update the active frequency */
	if (on && !(test_bit(KGSL_PWRFLAGS_AXI_ON, &pwr->power_flags)))
		return;
	/*
	 * If the bus should remain on calculate our request and submit it,
	 * otherwise request bus level 0, off.
	 */
	if (on) {
		buslevel = min_t(int, pwr->pwrlevels[0].bus_freq,
				cur + pwr->bus_mod);
		buslevel = max_t(int, buslevel, 1);
	}
	msm_bus_scale_client_update_request(pwr->pcl, buslevel);
	trace_kgsl_pwrlevel(device, pwr->active_pwrlevel, buslevel);
}
EXPORT_SYMBOL(kgsl_pwrctrl_buslevel_update);

void kgsl_pwrctrl_pwrlevel_change(struct kgsl_device *device,
				unsigned int new_level)
{
	struct kgsl_pwrctrl *pwr = &device->pwrctrl;
	struct kgsl_pwrlevel *pwrlevel;
	int delta, level;

	/* Adjust the power level to the current constraints */
	new_level = _adjust_pwrlevel(pwr, new_level);

	if (new_level == pwr->active_pwrlevel)
		return;

	delta = new_level < pwr->active_pwrlevel ? -1 : 1;

	update_clk_statistics(device, true);

	level = pwr->active_pwrlevel;

	/*
	 * Set the active powerlevel first in case the clocks are off - if we
	 * don't do this then the pwrlevel change won't take effect when the
	 * clocks come back
	 */

	pwr->active_pwrlevel = new_level;
	pwr->bus_mod = 0;
	pwrlevel = &pwr->pwrlevels[pwr->active_pwrlevel];

	kgsl_pwrctrl_buslevel_update(device, true);

	if (test_bit(KGSL_PWRFLAGS_CLK_ON, &pwr->power_flags) ||
		(device->state == KGSL_STATE_NAP)) {

		/*
		 * Don't shift by more than one level at a time to
		 * avoid glitches.
		 */

		while (level != new_level) {
			level += delta;

			clk_set_rate(pwr->grp_clks[0],
				pwr->pwrlevels[level].gpu_freq);
		}
	}


	trace_kgsl_pwrlevel(device, pwr->active_pwrlevel, pwrlevel->gpu_freq);
}

{'fraction_non_alphanumeric': 0.1098732232039954, 'fraction_numerical': 0.008259700345754899, 'mean_word_length': 4.364760432766615, 'pattern_counts': {'":': 0, '<': 25, '<?xml version=': 0, '>': 103, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2110473', 'n_tokens_mistral': 4181, 'n_tokens_neox': 3928, 'n_words': 1019}