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

Commit f1c1aa08 authored by Suman Tatiraju's avatar Suman Tatiraju
Browse files

msm: kgsl: Add support for peak power detection



A430 has capability to detect peak currect conditions and trigger
GPU clock throttling. Add support for peak power detection(PPD)
in the A430 feature list and program the registers at device start.

Change-Id: Iabfbbfa7a7c11b28510c18ad6c9e2641be958334
Signed-off-by: default avatarSuman Tatiraju <sumant@codeaurora.org>
parent 810f6916
Loading
Loading
Loading
Loading
+3 −1
Original line number Diff line number Diff line
@@ -22,6 +22,7 @@ Required properties:
				KGSL_CLK_MEM    0x00000008
				KGSL_CLK_MEM_IFACE 0x00000010
				KGSL_CLK_AXI    0x00000020
				KGSL_CLK_RBBMTIMER 0x00000080

- clocks:		List of phandle and clock specifier pairs, one pair
			for each clock input to the device.
@@ -29,7 +30,8 @@ Required properties:
			order as the clocks property.
				Current values of clock-names are:
				"src_clk", "core_clk", "iface_clk", "mem_clk", "mem_iface_clk",
				"alt_mem_iface_clk"
				"alt_mem_iface_clk", "rbbmtimer_clk"
				"core_clk" and "iface_clk" are required and others are optional

Bus Scaling Data:
- qcom,msm-bus,name: String property to describe the name of the 3D graphics processor.
+5 −3
Original line number Diff line number Diff line
@@ -30,12 +30,14 @@

		/*
		 * Clocks = KGSL_CLK_CORE | KGSL_CLK_IFACE
		 * KGSL_CLK_RBBMTIMER
		 */
		qcom,clk-map = <0x00000006>;
		qcom,clk-map = <0x00000086>;

		clocks = <&clock_mmss clk_oxili_gfx3d_clk>,
			<&clock_mmss clk_oxilicx_ahb_clk>;
		clock-names = "core_clk", "iface_clk";
			<&clock_mmss clk_oxilicx_ahb_clk>,
			<&clock_mmss clk_oxili_rbbmtimer_clk>;
		clock-names = "core_clk", "iface_clk", "rbbmtimer_clk";

		/* Bus Scale Settings */
		qcom,bus-control;
+5 −0
Original line number Diff line number Diff line
@@ -416,6 +416,11 @@ enum a4xx_rb_perfctr_rb_sel {
#define A4XX_RBBM_CFG_DEBBUS_MISR1		0x1af
#define A4XX_RBBM_POWER_STATUS			0x1b0
#define A4XX_RBBM_WAIT_IDLE_CLOCKS_CTL2		0x1b8
#define A4XX_RBBM_PPD_CTRL			0x1b9
#define A4XX_RBBM_PPD_EPOCH_INTRA_TH_1		0x1ba
#define A4XX_RBBM_PPD_EPOCH_INTRA_TH_2		0x1bb
#define A4XX_RBBM_PPD_EPOCH_INTER_TH_HI_CLR_TH  0x1bc
#define A4XX_RBBM_PPD_EPOCH_INTER_TH_LO         0x1bd
#define A4XX_RBBM_SECVID_TRUST_CONTROL		0xf400
#define A4XX_RBBM_SECVID_TSB_TRUSTED_BASE	0xf800
#define A4XX_RBBM_SECVID_TSB_TRUSTED_SIZE	0xf801
+1 −1
Original line number Diff line number Diff line
@@ -179,7 +179,7 @@ static const struct adreno_gpu_core adreno_gpulist[] = {
		.minor = 0,
		.patchid = ANY_ID,
		.features = ADRENO_USES_OCMEM  | ADRENO_WARM_START |
			ADRENO_USE_BOOTSTRAP | ADRENO_SPTP_PC,
			ADRENO_USE_BOOTSTRAP | ADRENO_SPTP_PC | ADRENO_PPD,
		.pm4fw_name = "a420_pm4.fw",
		.pfpfw_name = "a420_pfp.fw",
		.gpudev = &adreno_a4xx_gpudev,
+138 −1
Original line number Diff line number Diff line
@@ -1365,6 +1365,10 @@ static int _adreno_start(struct adreno_device *adreno_dev)
	if (gpudev->enable_pc)
		gpudev->enable_pc(adreno_dev);

	/* Enable peak power detect feature */
	if (gpudev->enable_ppd)
		gpudev->enable_ppd(adreno_dev);

	status = adreno_ringbuffer_cold_start(adreno_dev);
	if (status)
		goto error_irq_off;
@@ -1991,13 +1995,146 @@ static const struct device_attribute *_attr_list[] = {
	NULL,
};

/* Add a ppd directory for controlling different knobs from sysfs */
struct adreno_ppd_attribute {
	struct attribute attr;
	ssize_t (*show)(struct kgsl_device *device, char *buf);
	ssize_t (*store)(struct kgsl_device *device, const char *buf,
		size_t count);
};

#define PPD_ATTR(_name, _mode, _show, _store) \
struct adreno_ppd_attribute attr_##_name = { \
	.attr = { .name = __stringify(_name), .mode = _mode }, \
	.show = _show, \
	.store = _store, \
}

#define to_ppd_attr(a) \
container_of(a, struct adreno_ppd_attribute, attr)

#define kobj_to_device(a) \
container_of(a, struct kgsl_device, ppd_kobj)

/**
 * ppd_enable_store() - Enable or disable peak power detection
 * @attr: Device attribute
 * @buf: value to write
 * @count: size of the value to write
 *
 */
static ssize_t ppd_enable_store(struct kgsl_device *device,
				const char *buf, size_t count)
{
	struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
	struct adreno_gpudev *gpudev;
	unsigned int ret;
	unsigned int ppd_on = 1;

	if ((adreno_dev == NULL) || (device == NULL))
		return -ENODEV;

	gpudev = ADRENO_GPU_DEVICE(adreno_dev);
	ret = kgsl_sysfs_store(buf, &ppd_on);
	if (ret < 0)
		return ret;

	mutex_lock(&device->mutex);

	kgsl_pwrctrl_change_state(device, KGSL_STATE_SUSPEND);
	if (ppd_on)
		set_bit(ADRENO_PPD_CTRL, &adreno_dev->pwrctrl_flag);
	else
		clear_bit(ADRENO_PPD_CTRL, &adreno_dev->pwrctrl_flag);
	kgsl_pwrctrl_change_state(device, KGSL_STATE_SLUMBER);

	mutex_unlock(&device->mutex);
	return count;
}

/**
 * ppd_enable_show() -  Show whether ppd is enabled
 * @dev: device ptr
 * @buf: value read
 */
static ssize_t ppd_enable_show(struct kgsl_device *device,
					char *buf)
{
	struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
	return snprintf(buf, PAGE_SIZE, "%u\n", test_bit(ADRENO_PPD_CTRL,
					&adreno_dev->pwrctrl_flag));
}
/* Add individual ppd attributes here */
static PPD_ATTR(enable, 0644, ppd_enable_show, ppd_enable_store);

static void ppd_sysfs_release(struct kobject *kobj)
{
}

static ssize_t ppd_sysfs_show(struct kobject *kobj,
	struct attribute *attr, char *buf)
{
	struct adreno_ppd_attribute *pattr = to_ppd_attr(attr);
	struct kgsl_device *device = kobj_to_device(kobj);
	ssize_t ret;

	if (device && pattr->show)
		ret = pattr->show(device, buf);
	else
		ret = -EIO;

	return ret;
}

static ssize_t ppd_sysfs_store(struct kobject *kobj,
	struct attribute *attr, const char *buf, size_t count)
{
	struct adreno_ppd_attribute *pattr = to_ppd_attr(attr);
	struct kgsl_device *device = kobj_to_device(kobj);
	ssize_t ret;

	if (device && pattr->store)
		ret = pattr->store(device, buf, count);
	else
		ret = -EIO;

	return ret;
}

static const struct sysfs_ops ppd_sysfs_ops = {
	.show = ppd_sysfs_show,
	.store = ppd_sysfs_store,
};

static struct kobj_type ktype_ppd = {
	.sysfs_ops = &ppd_sysfs_ops,
	.default_attrs = NULL,
	.release = ppd_sysfs_release,
};

static int adreno_init_sysfs(struct kgsl_device *device)
{
	return kgsl_create_device_sysfs_files(device->dev, _attr_list);
	int ret;
	ret =  kgsl_create_device_sysfs_files(device->dev, _attr_list);
	if (ret)
		goto done;
	ret = kobject_init_and_add(&device->ppd_kobj, &ktype_ppd,
		&device->dev->kobj, "ppd");
	if (ret)
		goto done;

	ret  = sysfs_create_file(&device->ppd_kobj, &attr_enable.attr);

done:
	return ret;
}

static void adreno_uninit_sysfs(struct kgsl_device *device)
{
	sysfs_remove_file(&device->ppd_kobj, &attr_enable.attr);

	kobject_put(&device->ppd_kobj);

	kgsl_remove_device_sysfs_files(device->dev, _attr_list);
}

Loading