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

Commit 6968f859 authored by Linux Build Service Account's avatar Linux Build Service Account Committed by Gerrit - the friendly Code Review server
Browse files

Merge "msm: kgsl: Add support for SP/TP power collapse"

parents 5f851c5b 590c4413
Loading
Loading
Loading
Loading
+4 −0
Original line number Diff line number Diff line
@@ -200,6 +200,7 @@ enum a4xx_rb_perfctr_rb_sel {
#define A4XX_RBBM_CFG_DEBBUS_CLRC		0x94
#define A4XX_RBBM_CFG_DEBBUS_LOADIVT		0x95

#define A4XX_RBBM_POWER_CNTL_IP			0x98
#define A4XX_RBBM_PERFCTR_CP_0_LO		0x9c
#define A4XX_RBBM_PERFCTR_CP_0_HI		0x9d
#define A4XX_RBBM_PERFCTR_CP_1_LO		0x9e
@@ -402,6 +403,7 @@ enum a4xx_rb_perfctr_rb_sel {
#define A4XX_RBBM_CFG_DEBBUS_TRACE_BUF4		0x1ad
#define A4XX_RBBM_CFG_DEBBUS_MISR0		0x1ae
#define A4XX_RBBM_CFG_DEBBUS_MISR1		0x1af
#define A4XX_RBBM_POWER_STATUS			0x1b0

/* CP registers */
#define A4XX_CP_RB_BASE			0x200
@@ -427,6 +429,7 @@ enum a4xx_rb_perfctr_rb_sel {
#define A4XX_CP_ME_RAM_DATA		0x227

#define A4XX_CP_DEBUG			0x22e
#define A4XX_CP_POWER_COLLAPSE_CNTL	0x234
/*
 * CP debug settings for A4xx cores
 * MIU_128BIT_WRITE_ENABLE [25] - Allow 128 bit writes to the VBIF
@@ -697,6 +700,7 @@ enum a4xx_pc_perfctr_pc_sel {

/* HLSQ registers */
#define A4XX_HLSQ_TIMEOUT_THRESHOLD     0xe00
#define A4XX_HLSQ_STATE_RESTORE_TRIGGER	0xe01
#define A4XX_HLSQ_PERFCTR_HLSQ_SEL_0	0xe06
#define A4XX_HLSQ_PERFCTR_HLSQ_SEL_1	0xe07
#define A4XX_HLSQ_PERFCTR_HLSQ_SEL_2	0xe08
+37 −5
Original line number Diff line number Diff line
@@ -1639,6 +1639,11 @@ static int adreno_init(struct kgsl_device *device)
	if (test_bit(ADRENO_DEVICE_INITIALIZED, &adreno_dev->priv))
		return 0;

	/* Identify the specific GPU */
	adreno_identify_gpu(adreno_dev);

	gpudev = ADRENO_GPU_DEVICE(adreno_dev);

	/* Power up the device */
	ret = kgsl_pwrctrl_enable(device);
	if (ret)
@@ -1647,11 +1652,6 @@ static int adreno_init(struct kgsl_device *device)
	/* Make a high priority workqueue for starting the GPU */
	adreno_wq = alloc_workqueue("adreno", 0, 1);

	/* Identify the specific GPU */
	adreno_identify_gpu(adreno_dev);

	gpudev = ADRENO_GPU_DEVICE(adreno_dev);

	/* Initialize coresight for the target */
	adreno_coresight_init(device);

@@ -2604,6 +2604,10 @@ bool adreno_hw_isidle(struct kgsl_device *device)
	struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
	struct adreno_gpudev *gpudev = ADRENO_GPU_DEVICE(adreno_dev);

	if (gpudev->is_sptp_idle)
		if (!gpudev->is_sptp_idle(adreno_dev))
			return false;

	adreno_readreg(adreno_dev, ADRENO_REG_RBBM_STATUS,
		&reg_rbbm_status);

@@ -3102,6 +3106,30 @@ static unsigned int adreno_gpuid(struct kgsl_device *device,
	return (0x0003 << 16) | ADRENO_GPUREV(adreno_dev);
}

static void adreno_enable_pc(struct kgsl_device *device)
{
	struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
	struct adreno_gpudev *gpudev  = ADRENO_GPU_DEVICE(adreno_dev);
	if (gpudev->enable_pc)
		gpudev->enable_pc(adreno_dev);
}

static void adreno_disable_pc(struct kgsl_device *device)
{
	struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
	struct adreno_gpudev *gpudev  = ADRENO_GPU_DEVICE(adreno_dev);
	if (gpudev->disable_pc)
		gpudev->disable_pc(adreno_dev);
}

static void adreno_regulator_enable(struct kgsl_device *device)
{
	struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
	struct adreno_gpudev *gpudev  = ADRENO_GPU_DEVICE(adreno_dev);
	if (gpudev->regulator_enable)
		gpudev->regulator_enable(adreno_dev);
}

static const struct kgsl_functable adreno_functable = {
	/* Mandatory functions */
	.regread = adreno_regread,
@@ -3133,6 +3161,10 @@ static const struct kgsl_functable adreno_functable = {
	.setproperty_compat = adreno_setproperty_compat,
	.drawctxt_sched = adreno_drawctxt_sched,
	.resume = adreno_dispatcher_start,
	.enable_pc = adreno_enable_pc,
	.disable_pc = adreno_disable_pc,
	.regulator_enable = adreno_regulator_enable,

};

static struct platform_driver adreno_platform_driver = {
+5 −0
Original line number Diff line number Diff line
@@ -19,6 +19,7 @@
#include "adreno_profile.h"
#include "kgsl_iommu.h"
#include <linux/stat.h>
#include <linux/delay.h>

#ifdef CONFIG_MSM_OCMEM
#include <soc/qcom/ocmem.h>
@@ -602,6 +603,10 @@ struct adreno_gpudev {
	void (*perfcounter_write)(struct adreno_device *adreno_dev,
		unsigned int group, unsigned int counter);
	void (*soft_reset)(struct adreno_device *device);
	bool (*is_sptp_idle)(struct adreno_device *);
	void (*enable_pc)(struct adreno_device *);
	void (*disable_pc)(struct adreno_device *);
	void (*regulator_enable)(struct adreno_device *);
};

#define FT_DETECT_REGS_COUNT 14
+5 −0
Original line number Diff line number Diff line
@@ -1061,10 +1061,15 @@ int a3xx_perfcounter_enable(struct adreno_device *adreno_dev,
	}
	reg = &(counters->groups[group].regs[counter]);

	if (adreno_is_a4xx(adreno_dev))
		gpudev->disable_pc(adreno_dev);
	/* Select the desired perfcounter */
	kgsl_regwrite(&adreno_dev->dev, reg->select, countable);
	counters->groups[group].regs[counter].value = 0;

	if (adreno_is_a4xx(adreno_dev))
		gpudev->enable_pc(adreno_dev);

	return 0;
}

+96 −0
Original line number Diff line number Diff line
@@ -16,6 +16,11 @@
#include "adreno_a3xx.h"
#include "adreno_a4xx.h"
#include "adreno_cp_parser.h"
#include "adreno_trace.h"

#define SP_TP_PWR_COLLAPSE_MASK 0x6
#define SP_TP_PWR_ON_MASK BIT(0)
#define SP_TP_PWR_ON BIT(20)

/*
 * Set of registers to dump for A4XX on snapshot.
@@ -270,6 +275,92 @@ static const struct adreno_vbif_platform a4xx_vbif_platforms[] = {
	{ adreno_is_a430, a430_vbif },
};

/*
 * a4xx_is_sptp_idle() - A430 SP/TP should be off to be considered idle
 * @adreno_dev: The adreno device pointer
 */
static bool a4xx_is_sptp_idle(struct adreno_device *adreno_dev)
{
	unsigned int reg;
	struct kgsl_device *device = &adreno_dev->dev;
	if (adreno_is_a420(adreno_dev))
		return true;

	/* If SP/TP pc isn't enabled, don't worry about power */
	kgsl_regread(device, A4XX_CP_POWER_COLLAPSE_CNTL, &reg);
	if (!(reg & 0x10))
		return true;

	/* Check that SP/TP is off */
	kgsl_regread(device, A4XX_RBBM_POWER_STATUS, &reg);
	return !(reg & SP_TP_PWR_ON);
}

/*
 * a4xx_regulator_enable() - Enable any necessary HW regulators
 * @adreno_dev: The adreno device pointer
 *
 * Some HW blocks may need their regulators explicitly enabled
 * on a restart.  Clocks must be on during this call.
 */
static void a4xx_regulator_enable(struct adreno_device *adreno_dev)
{
	unsigned int reg;
	struct kgsl_device *device = &adreno_dev->dev;
	if (adreno_is_a420(adreno_dev))
		return;

	kgsl_regread(device, A4XX_RBBM_POWER_CNTL_IP, &reg);
	reg = (reg & ~SP_TP_PWR_ON_MASK);
	kgsl_regwrite(device, A4XX_RBBM_POWER_CNTL_IP, reg);
	do {
		udelay(5);
		kgsl_regread(device, A4XX_RBBM_POWER_STATUS, &reg);
	} while (!(reg & SP_TP_PWR_ON));
	trace_adreno_sp_tp((unsigned long) __builtin_return_address(0));
}

/*
 * a4xx_enable_pc() - Enable the SP/TP block power collapse
 * @adreno_dev: The adreno device pointer
 */
static void a4xx_enable_pc(struct adreno_device *adreno_dev)
{
	unsigned int reg;
	struct kgsl_device *device = &adreno_dev->dev;
	if (adreno_is_a420(adreno_dev))
		return;

	kgsl_regread(device, A4XX_RBBM_POWER_CNTL_IP, &reg);
	reg = (reg & ~SP_TP_PWR_COLLAPSE_MASK) | 0x2;
	kgsl_regwrite(device, A4XX_RBBM_POWER_CNTL_IP, reg);
	kgsl_regwrite(device, A4XX_CP_POWER_COLLAPSE_CNTL, 0x00400010);
	trace_adreno_sp_tp((unsigned long) __builtin_return_address(0));
};

/*
 * a4xx_disable_pc() - Disable the SP/TP block power collapse
 * @adreno_dev: The adreno device pointer
 */
static void a4xx_disable_pc(struct adreno_device *adreno_dev)
{
	unsigned int reg;
	struct kgsl_device *device = &adreno_dev->dev;
	if (adreno_is_a420(adreno_dev))
		return;

	/* remove hw control and use the sw override */
	kgsl_regread(device, A4XX_RBBM_POWER_CNTL_IP, &reg);
	reg = (reg & ~SP_TP_PWR_COLLAPSE_MASK) | 0x4;
	kgsl_regwrite(device, A4XX_RBBM_POWER_CNTL_IP, reg);

	/* turn the SP/TP on & restore it */
	a4xx_regulator_enable(adreno_dev);
	kgsl_regwrite(device, A4XX_HLSQ_STATE_RESTORE_TRIGGER, 0x1);
	trace_adreno_sp_tp((unsigned long) __builtin_return_address(0));
}


/*
 * a4xx_enable_hwcg() - Program the clock control registers
 * @device: The adreno device pointer
@@ -456,6 +547,7 @@ static void a4xx_start(struct adreno_device *adreno_dev)
			(adreno_is_a420(adreno_dev) ? (1 << 29) : 0));

	a4xx_enable_hwcg(device);
	a4xx_enable_pc(adreno_dev);
	/*
	 * For A420 set RBBM_CLOCK_DELAY_HLSQ.CGC_HLSQ_TP_EARLY_CYC >= 2
	 * due to timing issue with HLSQ_TP_CLK_EN
@@ -1266,4 +1358,8 @@ struct adreno_gpudev adreno_a4xx_gpudev = {
	.invalid_countables = a4xx_perfctr_invalid_countables,
	.soft_reset = a3xx_soft_reset,
	.snapshot = a4xx_snapshot,
	.is_sptp_idle = a4xx_is_sptp_idle,
	.enable_pc = a4xx_enable_pc,
	.disable_pc = a4xx_disable_pc,
	.regulator_enable = a4xx_regulator_enable,
};
Loading