Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit e7c78f11 authored by Harshdeep Dhatt's avatar Harshdeep Dhatt
Browse files

msm: kgsl: Create adreno power operations



This enables us to define target specific device power up/down
sequences. Also create adreno_power_cycle for certain settings
to take effect by powering down, change the settings and then
resume the device.

Change-Id: Ie6a0feb224f0b0babcd0249c812674c31dc6c4ab
Signed-off-by: default avatarHarshdeep Dhatt <hdhatt@codeaurora.org>
parent f707fc73
Loading
Loading
Loading
Loading
+192 −12
Original line number Diff line number Diff line
@@ -1546,11 +1546,10 @@ static void adreno_unbind(struct device *dev)
	clear_bit(ADRENO_DEVICE_INITIALIZED, &adreno_dev->priv);
}

static int adreno_pm_resume(struct device *dev)
static void adreno_resume(struct adreno_device *adreno_dev)
{
	struct kgsl_device *device = dev_get_drvdata(dev);
	struct kgsl_device *device = KGSL_DEVICE(adreno_dev);

	mutex_lock(&device->mutex);
	if (device->state == KGSL_STATE_SUSPEND) {
		adreno_dispatcher_unhalt(device);
		kgsl_pwrctrl_change_state(device, KGSL_STATE_SLUMBER);
@@ -1565,19 +1564,41 @@ static int adreno_pm_resume(struct device *dev)
		kgsl_pwrctrl_change_state(device, KGSL_STATE_SLUMBER);
		dev_err(device->dev, "resume invoked without a suspend\n");
	}
}

static int adreno_pm_resume(struct device *dev)
{
	struct kgsl_device *device = dev_get_drvdata(dev);
	struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
	const struct adreno_power_ops *ops = ADRENO_POWER_OPS(adreno_dev);

	mutex_lock(&device->mutex);
	ops->pm_resume(adreno_dev);
	mutex_unlock(&device->mutex);

	return 0;
}

static int adreno_suspend(struct adreno_device *adreno_dev)
{
	struct kgsl_device *device = KGSL_DEVICE(adreno_dev);
	int status = kgsl_pwrctrl_change_state(device, KGSL_STATE_SUSPEND);

	if (!status && device->state == KGSL_STATE_SUSPEND)
		adreno_dispatcher_halt(device);

	return status;
}

static int adreno_pm_suspend(struct device *dev)
{
	struct kgsl_device *device = dev_get_drvdata(dev);
	struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
	const struct adreno_power_ops *ops = ADRENO_POWER_OPS(adreno_dev);
	int status;

	mutex_lock(&device->mutex);
	status = kgsl_pwrctrl_change_state(device, KGSL_STATE_SUSPEND);
	if (!status && device->state == KGSL_STATE_SUSPEND)
		adreno_dispatcher_halt(device);
	status = ops->pm_suspend(adreno_dev);
	mutex_unlock(&device->mutex);

	return status;
@@ -1825,14 +1846,15 @@ static void adreno_set_active_ctxs_null(struct adreno_device *adreno_dev)
	}
}

static int adreno_first_open(struct kgsl_device *device)
static int adreno_open(struct adreno_device *adreno_dev)
{
	struct kgsl_device *device = KGSL_DEVICE(adreno_dev);
	int ret;

	/*
	 * active_cnt special case: we are starting up for the first
	 * time, so use this sequence instead of the kgsl_pwrctrl_wake()
	 * which will be called by kgsl_active_count_get().
	 * which will be called by adreno_active_count_get().
	 */
	atomic_inc(&device->active_cnt);

@@ -1850,7 +1872,7 @@ static int adreno_first_open(struct kgsl_device *device)

	complete_all(&device->hwaccess_gate);
	kgsl_pwrctrl_change_state(device, KGSL_STATE_ACTIVE);
	kgsl_active_count_put(device);
	adreno_active_count_put(adreno_dev);

	return 0;
err:
@@ -1860,8 +1882,18 @@ static int adreno_first_open(struct kgsl_device *device)
	return ret;
}

static int adreno_last_close(struct kgsl_device *device)
static int adreno_first_open(struct kgsl_device *device)
{
	struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
	const struct adreno_power_ops *ops = ADRENO_POWER_OPS(adreno_dev);

	return ops->first_open(adreno_dev);
}

static int adreno_close(struct adreno_device *adreno_dev)
{
	struct kgsl_device *device = KGSL_DEVICE(adreno_dev);

	/*
	 * Wait up to 1 second for the active count to go low
	 * and then start complaining about it
@@ -1878,6 +1910,84 @@ static int adreno_last_close(struct kgsl_device *device)
	return kgsl_pwrctrl_change_state(device, KGSL_STATE_INIT);
}

static int adreno_last_close(struct kgsl_device *device)
{
	struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
	const struct adreno_power_ops *ops = ADRENO_POWER_OPS(adreno_dev);

	return ops->last_close(adreno_dev);
}

static int adreno_pwrctrl_active_count_get(struct adreno_device *adreno_dev)
{
	struct kgsl_device *device = KGSL_DEVICE(adreno_dev);
	int ret = 0;

	if (WARN_ON(!mutex_is_locked(&device->mutex)))
		return -EINVAL;

	if ((atomic_read(&device->active_cnt) == 0) &&
		(device->state != KGSL_STATE_ACTIVE)) {
		mutex_unlock(&device->mutex);
		wait_for_completion(&device->hwaccess_gate);
		mutex_lock(&device->mutex);
		device->pwrctrl.superfast = true;
		ret = kgsl_pwrctrl_change_state(device, KGSL_STATE_ACTIVE);
	}
	if (ret == 0)
		atomic_inc(&device->active_cnt);
	trace_kgsl_active_count(device,
		(unsigned long) __builtin_return_address(0));
	return ret;
}

static void adreno_pwrctrl_active_count_put(struct adreno_device *adreno_dev)
{
	struct kgsl_device *device = KGSL_DEVICE(adreno_dev);

	if (WARN_ON(!mutex_is_locked(&device->mutex)))
		return;

	if (WARN(atomic_read(&device->active_cnt) == 0,
			"Unbalanced get/put calls to KGSL active count\n"))
		return;

	if (atomic_dec_and_test(&device->active_cnt)) {
		bool nap_on = !(device->pwrctrl.ctrl_flags &
			BIT(KGSL_PWRFLAGS_NAP_OFF));
		if (nap_on && device->state == KGSL_STATE_ACTIVE &&
			device->requested_state == KGSL_STATE_NONE) {
			kgsl_pwrctrl_request_state(device, KGSL_STATE_NAP);
			kgsl_schedule_work(&device->idle_check_ws);
		} else if (!nap_on) {
			kgsl_pwrscale_update_stats(device);
			kgsl_pwrscale_update(device);
		}

		mod_timer(&device->idle_timer,
			jiffies + device->pwrctrl.interval_timeout);
	}

	trace_kgsl_active_count(device,
		(unsigned long) __builtin_return_address(0));

	wake_up(&device->active_cnt_wq);
}

int adreno_active_count_get(struct adreno_device *adreno_dev)
{
	const struct adreno_power_ops *ops = ADRENO_POWER_OPS(adreno_dev);

	return ops->active_count_get(adreno_dev);
}

void adreno_active_count_put(struct adreno_device *adreno_dev)
{
	const struct adreno_power_ops *ops = ADRENO_POWER_OPS(adreno_dev);

	ops->active_count_put(adreno_dev);
}

/**
 * _adreno_start - Power up the GPU and prepare to accept commands
 * @adreno_dev: Pointer to an adreno_device structure
@@ -2597,9 +2707,9 @@ static int adreno_setproperty(struct kgsl_device_private *dev_priv,
			if (enable) {
				device->pwrctrl.ctrl_flags = 0;

				if (!kgsl_active_count_get(device)) {
				if (!adreno_active_count_get(adreno_dev)) {
					adreno_fault_detect_start(adreno_dev);
					kgsl_active_count_put(device);
					adreno_active_count_put(adreno_dev);
				}

				kgsl_pwrscale_enable(device);
@@ -3662,6 +3772,67 @@ static void adreno_drawctxt_sched(struct kgsl_device *device,
	adreno_dispatcher_queue_context(device, ADRENO_CONTEXT(context));
}

int adreno_power_cycle(struct adreno_device *adreno_dev,
	void (*callback)(struct adreno_device *adreno_dev, void *priv),
	void *priv)
{
	struct kgsl_device *device = KGSL_DEVICE(adreno_dev);
	const struct adreno_power_ops *ops = ADRENO_POWER_OPS(adreno_dev);
	int ret;

	mutex_lock(&device->mutex);
	ret = ops->pm_suspend(adreno_dev);

	if (!ret) {
		callback(adreno_dev, priv);
		ops->pm_resume(adreno_dev);
	}

	mutex_unlock(&device->mutex);

	return ret;
}

int adreno_power_cycle_bool(struct adreno_device *adreno_dev,
	bool *flag, bool val)
{
	struct kgsl_device *device = KGSL_DEVICE(adreno_dev);
	const struct adreno_power_ops *ops = ADRENO_POWER_OPS(adreno_dev);
	int ret;

	mutex_lock(&device->mutex);
	ret = ops->pm_suspend(adreno_dev);

	if (!ret) {
		*flag = val;
		ops->pm_resume(adreno_dev);
	}

	mutex_unlock(&device->mutex);

	return ret;
}

int adreno_power_cycle_u32(struct adreno_device *adreno_dev,
	u32 *flag, u32 val)
{
	struct kgsl_device *device = KGSL_DEVICE(adreno_dev);
	const struct adreno_power_ops *ops = ADRENO_POWER_OPS(adreno_dev);
	int ret;

	mutex_lock(&device->mutex);
	ret = ops->pm_suspend(adreno_dev);

	if (!ret) {
		*flag = val;
		ops->pm_resume(adreno_dev);
	}

	mutex_unlock(&device->mutex);

	return ret;
}

static const struct kgsl_functable adreno_functable = {
	/* Mandatory functions */
	.regread = adreno_regread,
@@ -3712,6 +3883,15 @@ static const struct component_master_ops adreno_ops = {
	.unbind = adreno_unbind,
};

const struct adreno_power_ops adreno_power_operations = {
	.first_open = adreno_open,
	.last_close = adreno_close,
	.active_count_get = adreno_pwrctrl_active_count_get,
	.active_count_put = adreno_pwrctrl_active_count_put,
	.pm_suspend = adreno_suspend,
	.pm_resume = adreno_resume,
};

static const struct of_device_id adreno_gmu_match[] = {
	{ .compatible = "qcom,gpu-gmu" },
	{ .compatible = "qcom,gpu-rgmu" },
+123 −6
Original line number Diff line number Diff line
@@ -27,6 +27,12 @@
/* ADRENO_GPU_DEVICE - Given an adreno device return the GPU specific struct */
#define ADRENO_GPU_DEVICE(_a) ((_a)->gpucore->gpudev)

/*
 * ADRENO_POWER_OPS - Given an adreno device return the GPU specific power
 * ops
 */
#define ADRENO_POWER_OPS(_a) ((_a)->gpucore->gpudev->power_ops)

#define ADRENO_CHIPID_CORE(_id) (((_id) >> 24) & 0xFF)
#define ADRENO_CHIPID_MAJOR(_id) (((_id) >> 16) & 0xFF)
#define ADRENO_CHIPID_MINOR(_id) (((_id) >> 8) & 0xFF)
@@ -322,6 +328,37 @@ struct adreno_reglist {
	u32 value;
};

/**
 * struct adreno_power_ops - Container for target specific power up/down
 * sequences
 */
struct adreno_power_ops {
	/**
	 * @first_open: Target specific function triggered when first kgsl
	 * instance is opened
	 */
	int (*first_open)(struct adreno_device *adreno_dev);
	/**
	 * @last_close: Target specific function triggered when last kgsl
	 * instance is closed
	 */
	int (*last_close)(struct adreno_device *adreno_dev);
	/**
	 * @active_count_get: Target specific function to keep gpu from power
	 * collapsing
	 */
	int (*active_count_get)(struct adreno_device *adreno_dev);
	/**
	 * @active_count_put: Target specific function to allow gpu to power
	 * collapse
	 */
	void (*active_count_put)(struct adreno_device *adreno_dev);
	/** @pm_suspend: Target specific function to suspend the driver */
	int (*pm_suspend)(struct adreno_device *adreno_dev);
	/** @pm_resume: Target specific function to resume the driver */
	void (*pm_resume)(struct adreno_device *adreno_dev);
};

/**
 * struct adreno_gpu_core - A specific GPU core definition
 * @gpurev: Unique GPU revision identifier
@@ -794,6 +831,11 @@ struct adreno_gpudev {
				bool update_reg);
	/** @read_alwayson: Return the current value of the alwayson counter */
	u64 (*read_alwayson)(struct adreno_device *adreno_dev);
	/**
	 * @power_ops: Target specific function pointers to power up/down the
	 * gpu
	 */
	const struct adreno_power_ops *power_ops;
};

/**
@@ -855,6 +897,7 @@ struct adreno_ft_perf_counters {
	unsigned int countable;
};

extern const struct adreno_power_ops adreno_power_operations;
extern unsigned int *adreno_ft_regs;
extern unsigned int adreno_ft_regs_num;
extern unsigned int *adreno_ft_regs_val;
@@ -950,6 +993,30 @@ void adreno_isense_regread(struct adreno_device *adreno_dev,
 */
bool adreno_irq_pending(struct adreno_device *adreno_dev);

/**
 * adreno_active_count_get - Wrapper for target specific active count get
 * @adreno_dev: pointer to the adreno device
 *
 * Increase the active count for the KGSL device and execute slumber exit
 * sequence if this is the first reference. Code paths that need to touch the
 * hardware or wait for the hardware to complete an operation must hold an
 * active count reference until they are finished. The device mutex must be held
 * while calling this function.
 *
 * Return: 0 on success or negative error on failure to wake up the device
 */
int adreno_active_count_get(struct adreno_device *adreno_dev);

/**
 * adreno_active_count_put - Wrapper for target specific active count put
 * @adreno_dev: pointer to the adreno device
 *
 * Decrease the active or the KGSL device and schedule the idle thread to
 * execute the slumber sequence if there are no remaining references. The
 * device mutex must be held while calling this function.
 */
void adreno_active_count_put(struct adreno_device *adreno_dev);

#define ADRENO_TARGET(_name, _id) \
static inline int adreno_is_##_name(struct adreno_device *adreno_dev) \
{ \
@@ -1556,28 +1623,33 @@ static inline unsigned int counter_delta(struct kgsl_device *device,
	return ret;
}

static inline int adreno_perfcntr_active_oob_get(struct kgsl_device *device)
static inline int adreno_perfcntr_active_oob_get(
	struct adreno_device *adreno_dev)
{
	int ret = kgsl_active_count_get(device);
	struct kgsl_device *device = KGSL_DEVICE(adreno_dev);
	int ret = adreno_active_count_get(adreno_dev);

	if (!ret) {
		ret = gmu_core_dev_oob_set(device, oob_perfcntr);
		if (ret) {
			gmu_core_snapshot(device);
			adreno_set_gpu_fault(ADRENO_DEVICE(device),
			adreno_set_gpu_fault(adreno_dev,
				ADRENO_GMU_FAULT_SKIP_SNAPSHOT);
			adreno_dispatcher_schedule(device);
			kgsl_active_count_put(device);
			adreno_active_count_put(adreno_dev);
		}
	}

	return ret;
}

static inline void adreno_perfcntr_active_oob_put(struct kgsl_device *device)
static inline void adreno_perfcntr_active_oob_put(
	struct adreno_device *adreno_dev)
{
	struct kgsl_device *device = KGSL_DEVICE(adreno_dev);

	gmu_core_dev_oob_clear(device, oob_perfcntr);
	kgsl_active_count_put(device);
	adreno_active_count_put(adreno_dev);
}

static inline bool adreno_has_sptprac_gdsc(struct adreno_device *adreno_dev)
@@ -1740,4 +1812,49 @@ irqreturn_t adreno_irq_callbacks(struct adreno_device *adreno_dev,
int adreno_device_probe(struct platform_device *pdev,
		struct adreno_device *adreno_dev);

/**
 * adreno_power_cycle - Suspend and resume the device
 * @adreno_dev: Pointer to the adreno device
 * @callback: Function that needs to be executed
 * @priv: Argument to be passed to the callback
 *
 * Certain properties that can be set via sysfs need to power
 * cycle the device to take effect. This function suspends
 * the device, executes the callback, and resumes the device.
 *
 * Return: 0 on success or negative on failure
 */
int adreno_power_cycle(struct adreno_device *adreno_dev,
	void (*callback)(struct adreno_device *adreno_dev, void *priv),
	void *priv);

/**
 * adreno_power_cycle_bool - Power cycle the device to change device setting
 * @adreno_dev: Pointer to the adreno device
 * @flag: Flag that needs to be set
 * @val: The value flag should be set to
 *
 * Certain properties that can be set via sysfs need to power cycle the device
 * to take effect. This function suspends the device, sets the flag, and
 * resumes the device.
 *
 * Return: 0 on success or negative on failure
 */
int adreno_power_cycle_bool(struct adreno_device *adreno_dev,
	bool *flag, bool val);

/**
 * adreno_power_cycle_u32 - Power cycle the device to change device setting
 * @adreno_dev: Pointer to the adreno device
 * @flag: Flag that needs to be set
 * @val: The value flag should be set to
 *
 * Certain properties that can be set via sysfs need to power cycle the device
 * to take effect. This function suspends the device, sets the flag, and
 * resumes the device.
 *
 * Return: 0 on success or negative on failure
 */
int adreno_power_cycle_u32(struct adreno_device *adreno_dev,
	u32 *flag, u32 val);
#endif /*__ADRENO_H */
+1 −0
Original line number Diff line number Diff line
@@ -1434,4 +1434,5 @@ struct adreno_gpudev adreno_a3xx_gpudev = {
	.clk_set_options = a3xx_clk_set_options,
	.read_alwayson = a3xx_read_alwayson,
	.hw_isidle = a3xx_hw_isidle,
	.power_ops = &adreno_power_operations,
};
+2 −1
Original line number Diff line number Diff line
@@ -1449,7 +1449,7 @@ static void a5xx_start(struct adreno_device *adreno_dev)

	/* Enable ISDB mode if requested */
	if (test_bit(ADRENO_DEVICE_ISDB_ENABLED, &adreno_dev->priv)) {
		if (!kgsl_active_count_get(device)) {
		if (!adreno_active_count_get(adreno_dev)) {
			/*
			 * Disable ME/PFP split timeouts when the debugger is
			 * enabled because the CP doesn't know when a shader is
@@ -3011,4 +3011,5 @@ struct adreno_gpudev adreno_a5xx_gpudev = {
	.clk_set_options = a5xx_clk_set_options,
	.read_alwayson = a5xx_read_alwayson,
	.hw_isidle = a5xx_hw_isidle,
	.power_ops = &adreno_power_operations,
};
+1 −0
Original line number Diff line number Diff line
@@ -2677,4 +2677,5 @@ struct adreno_gpudev adreno_a6xx_gpudev = {
#endif
	.clk_set_options = a6xx_clk_set_options,
	.read_alwayson = a6xx_read_alwayson,
	.power_ops = &adreno_power_operations,
};
Loading