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

Commit c2ab7f7b authored by Oleg Perelet's avatar Oleg Perelet
Browse files

msm:kgsl: Add Limits Management code to A6XX platform



Add Limits Management and Isense control code for A630
keep feature it disabled.

CRs-Fixed: 2062271
Change-Id: Ic11654ffbf4eaaade13db93dc686f6124debf7b5
Signed-off-by: default avatarOleg Perelet <operelet@codeaurora.org>
parent 1edef9b9
Loading
Loading
Loading
Loading
+35 −0
Original line number Diff line number Diff line
@@ -859,11 +859,46 @@
#define A6XX_GMU_HOST2GMU_INTR_INFO_1		0x1F99C
#define A6XX_GMU_HOST2GMU_INTR_INFO_2		0x1F99D
#define A6XX_GMU_HOST2GMU_INTR_INFO_3		0x1F99E
#define A6XX_GMU_GENERAL_1			0x1F9C6
#define A6XX_GMU_GENERAL_7			0x1F9CC

/* ISENSE registers */
#define A6XX_GMU_ISENSE_CTRL			0x1F95D
#define A6XX_GPU_CS_ENABLE_REG			0x23120
#define A6XX_GPU_GMU_CX_GMU_ISENSE_CTRL		0x1f95d
#define A6XX_GPU_CS_AMP_CALIBRATION_CONTROL3	0x22d78
#define A6XX_GPU_CS_AMP_CALIBRATION_CONTROL2	0x22d58
#define A6XX_GPU_CS_A_SENSOR_CTRL_0		0x22d80
#define A6XX_GPU_CS_A_SENSOR_CTRL_2		0x422da
#define A6XX_GPU_CS_SENSOR_GENERAL_STATUS	0x2301a
#define A6XX_GPU_CS_AMP_CALIBRATION_CONTROL1	0x23157
#define A6XX_GPU_CS_SENSOR_GENERAL_STATUS	0x2301a
#define A6XX_GPU_CS_AMP_CALIBRATION_STATUS1_0	0x2301d
#define A6XX_GPU_CS_AMP_CALIBRATION_STATUS1_2	0x2301f
#define A6XX_GPU_CS_AMP_CALIBRATION_STATUS1_4	0x23021
#define A6XX_GPU_CS_AMP_CALIBRATION_DONE	0x23165
#define A6XX_GPU_CS_AMP_PERIOD_CTRL		0x2316d
#define A6XX_GPU_CS_AMP_CALIBRATION_DONE	0x23165

#define CS_PWR_ON_STATUS			(10)
#define AMP_SW_WRM_TRIM_START			(24)
#define AMP_TRIM_TIMER				(6)
#define AMP_SW_TRIM_START			(0)
#define SS_AMPTRIM_DONE				(11)
#define AMP_OFFSET_CHECK_MIN_ERR		(1)
#define AMP_OFFSET_CHECK_MAX_ERR		(2)
#define AMP_OUT_OF_RANGE_ERR			(4)
#define TRIM_CNT_VALUE				(1)
#define RUNTIME_CNT_VALUE			(16)
#define TRIM_ENABLE				(0)

#define AMP_ERR			(BIT(AMP_OFFSET_CHECK_MIN_ERR) || \
				BIT(AMP_OFFSET_CHECK_MAX_ERR) || \
				BIT(AMP_OUT_OF_RANGE_ERR))

/* LM registers */
#define A6XX_GPU_GMU_CX_GMU_PWR_THRESHOLD       0x1F94D


#define A6XX_GMU_AO_INTERRUPT_EN		0x23B03
#define A6XX_GMU_AO_HOST_INTERRUPT_CLR		0x23B04
+1 −1
Original line number Diff line number Diff line
@@ -327,7 +327,7 @@ static const struct adreno_gpu_core adreno_gpulist[] = {
		.minor = 0,
		.patchid = ANY_ID,
		.features = ADRENO_64BIT | ADRENO_RPMH |
			ADRENO_GPMU | ADRENO_CONTENT_PROTECTION,
			ADRENO_GPMU | ADRENO_CONTENT_PROTECTION | ADRENO_LM,
		.sqefw_name = "a630_sqe.fw",
		.zap_name = "a630_zap",
		.gpudev = &adreno_a6xx_gpudev,
+1 −19
Original line number Diff line number Diff line
/* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved.
/* Copyright (c) 2015-2017, 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
@@ -151,24 +151,6 @@ void a5xx_hwcg_set(struct adreno_device *adreno_dev, bool on);
#define GPMU_ISENSE_STATUS		GENMASK(3, 0)
#define GPMU_ISENSE_END_POINT_CAL_ERR	BIT(0)

/* A5XX_GPU_CS_AMP_CALIBRATION_CONTROL1 */
#define AMP_SW_TRIM_START		BIT(0)

/* A5XX_GPU_CS_SENSOR_GENERAL_STATUS */
#define SS_AMPTRIM_DONE			BIT(11)
#define CS_PWR_ON_STATUS		BIT(10)

/* A5XX_GPU_CS_AMP_CALIBRATION_STATUS*_* */
#define AMP_OUT_OF_RANGE_ERR		BIT(4)
#define AMP_OFFSET_CHECK_MAX_ERR	BIT(2)
#define AMP_OFFSET_CHECK_MIN_ERR	BIT(1)

/* A5XX_GPU_CS_AMP_CALIBRATION_DONE */
#define SW_OPAMP_CAL_DONE           BIT(0)

#define AMP_CALIBRATION_ERR (AMP_OFFSET_CHECK_MIN_ERR | \
		AMP_OFFSET_CHECK_MAX_ERR | AMP_OUT_OF_RANGE_ERR)

#define AMP_CALIBRATION_RETRY_CNT	3
#define AMP_CALIBRATION_TIMEOUT		6

+122 −7
Original line number Diff line number Diff line
@@ -360,6 +360,22 @@ static void a6xx_hwcg_set(struct adreno_device *adreno_dev, bool on)
	kgsl_regwrite(device, A5XX_RBBM_ISDB_CNT, on ? 0x00000182 : 0x00000180);
}

#define LM_DEFAULT_LIMIT	6000

static uint32_t lm_limit(struct adreno_device *adreno_dev)
{
	struct kgsl_device *device = KGSL_DEVICE(adreno_dev);

	if (adreno_dev->lm_limit)
		return adreno_dev->lm_limit;

	if (of_property_read_u32(device->pdev->dev.of_node, "qcom,lm-limit",
		&adreno_dev->lm_limit))
		adreno_dev->lm_limit = LM_DEFAULT_LIMIT;

	return adreno_dev->lm_limit;
}

/*
 * a6xx_start() - Device start
 * @adreno_dev: Pointer to adreno device
@@ -379,6 +395,9 @@ static void a6xx_start(struct adreno_device *adreno_dev)
	/* enable hardware clockgating */
	a6xx_hwcg_set(adreno_dev, true);

	if (ADRENO_FEATURE(adreno_dev, ADRENO_LM))
		adreno_dev->lm_threshold_count = A6XX_GMU_GENERAL_1;

	adreno_vbif_start(adreno_dev, a6xx_vbif_platforms,
			ARRAY_SIZE(a6xx_vbif_platforms));

@@ -935,7 +954,8 @@ static void a6xx_gmu_power_config(struct kgsl_device *device)
	}

	/* ACD feature enablement */
	if (ADRENO_FEATURE(adreno_dev, ADRENO_LM))
	if (ADRENO_FEATURE(adreno_dev, ADRENO_LM) &&
		test_bit(ADRENO_LM_CTRL, &adreno_dev->pwrctrl_flag))
		kgsl_gmu_regrmw(device, A6XX_GMU_BOOT_KMD_LM_HANDSHAKE, 0,
				BIT(10));

@@ -943,9 +963,6 @@ static void a6xx_gmu_power_config(struct kgsl_device *device)
	if (ADRENO_FEATURE(adreno_dev, ADRENO_RPMH))
		kgsl_gmu_regrmw(device, A6XX_GMU_RPMH_CTRL, 0,
				RPMH_ENABLE_MASK);

	/* Disable reference bandgap voltage */
	kgsl_gmu_regwrite(device, A6XX_GMU_AO_SPARE_CNTL, 1);
}

/*
@@ -1420,6 +1437,7 @@ static int a6xx_rpmh_power_on_gpu(struct kgsl_device *device)
static int a6xx_rpmh_power_off_gpu(struct kgsl_device *device)
{
	struct gmu_device *gmu = &device->gmu;
	const struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
	int val, ret = 0;

	/* Turn off the SPTP and HM head switches */
@@ -1446,6 +1464,8 @@ static int a6xx_rpmh_power_off_gpu(struct kgsl_device *device)
			&val);
	kgsl_gmu_regwrite(device, A6XX_GMU_RSCC_CONTROL_REQ, 0);

	if (ADRENO_FEATURE(adreno_dev, ADRENO_LM) &&
		test_bit(ADRENO_LM_CTRL, &adreno_dev->pwrctrl_flag))
		kgsl_gmu_regwrite(device, A6XX_GMU_AO_SPARE_CNTL, 0);

	/* FIXME: v2 has different procedure to trigger sequence */
@@ -1453,6 +1473,78 @@ static int a6xx_rpmh_power_off_gpu(struct kgsl_device *device)
	return ret;
}

#define KMASK(start, n) (GENMASK((start + n), (start)))

static void isense_cold_trimm(struct kgsl_device *device)
{
	unsigned int reg;
	struct gmu_device *gmu = &device->gmu;

	kgsl_gmu_regwrite(device, A6XX_GMU_AO_SPARE_CNTL, 1);
	kgsl_gmu_regwrite(device, A6XX_GPU_CS_AMP_CALIBRATION_DONE, 0);

	kgsl_gmu_regwrite(device, A6XX_GPU_GMU_CX_GMU_ISENSE_CTRL, 0x1);
	kgsl_gmu_regwrite(device, A6XX_GPU_CS_AMP_CALIBRATION_CONTROL3,
		0x00000F8F);
	kgsl_gmu_regwrite(device, A6XX_GPU_CS_AMP_CALIBRATION_CONTROL2,
		0x00705161);
	udelay(10);
	kgsl_gmu_regwrite(device, A6XX_GPU_CS_ENABLE_REG, 0x3);
	kgsl_gmu_regwrite(device, A6XX_GPU_CS_A_SENSOR_CTRL_0, 0x10040a);
	kgsl_gmu_regwrite(device, A6XX_GPU_CS_A_SENSOR_CTRL_2, 0x10040a);

	kgsl_gmu_regread(device, A6XX_GPU_CS_SENSOR_GENERAL_STATUS, &reg);
	if ((reg & BIT(CS_PWR_ON_STATUS)) != (1 << CS_PWR_ON_STATUS)) {
		dev_err(&gmu->pdev->dev, "ERROR - ISENSE power-up\n");
		return;
	}

	kgsl_gmu_regrmw(device, A6XX_GPU_CS_AMP_CALIBRATION_CONTROL1,
		KMASK(AMP_TRIM_TIMER, 15), 70 << AMP_TRIM_TIMER);
	kgsl_gmu_regrmw(device, A6XX_GPU_CS_AMP_CALIBRATION_CONTROL1,
		KMASK(AMP_SW_TRIM_START, 1), 0 << AMP_SW_TRIM_START);
	kgsl_gmu_regrmw(device, A6XX_GPU_CS_AMP_CALIBRATION_CONTROL1,
		KMASK(AMP_SW_TRIM_START, 1), 1 << AMP_SW_TRIM_START);

	if (timed_poll_check(device, A6XX_GPU_CS_SENSOR_GENERAL_STATUS,
		BIT(SS_AMPTRIM_DONE), GMU_START_TIMEOUT,
		BIT(SS_AMPTRIM_DONE))) {
		dev_err(&gmu->pdev->dev, "ISENSE SS_AMPTRIM failure\n");
		return;
	}

	kgsl_gmu_regread(device, A6XX_GPU_CS_AMP_CALIBRATION_STATUS1_0, &reg);
	if (reg & AMP_ERR) {
		kgsl_gmu_regread(device, A6XX_GPU_CS_AMP_CALIBRATION_STATUS1_0,
			&reg);
		dev_err(&gmu->pdev->dev,
			"ISENSE ERROR:trimming GX 0x%08x\n", reg);
		return;
	}

	kgsl_gmu_regread(device, A6XX_GPU_CS_AMP_CALIBRATION_STATUS1_2, &reg);
	if (reg & AMP_ERR) {
		kgsl_gmu_regread(device, A6XX_GPU_CS_AMP_CALIBRATION_STATUS1_2,
			&reg);
		dev_err(&gmu->pdev->dev,
			"ISENSE ERROR:trimming SPTPRAC 0x%08x\n", reg);
		return;
	}

	kgsl_gmu_regwrite(device, A6XX_GPU_CS_AMP_CALIBRATION_DONE, 1);
	kgsl_gmu_regrmw(device, A6XX_GPU_CS_AMP_PERIOD_CTRL,
		KMASK(TRIM_CNT_VALUE, 13), 20 << TRIM_CNT_VALUE);
	kgsl_gmu_regrmw(device, A6XX_GPU_CS_AMP_PERIOD_CTRL,
		KMASK(RUNTIME_CNT_VALUE, 9), 50 << RUNTIME_CNT_VALUE);

	kgsl_gmu_regrmw(device, A6XX_GPU_CS_AMP_PERIOD_CTRL,
		KMASK(TRIM_ENABLE, 1), 1 << TRIM_ENABLE);
	udelay(4);
	kgsl_gmu_regrmw(device, A6XX_GPU_CS_AMP_PERIOD_CTRL,
		KMASK(TRIM_ENABLE, 1), 0 << TRIM_ENABLE);
	kgsl_gmu_regwrite(device, A6XX_GPU_CS_AMP_CALIBRATION_DONE, 1);

}
/*
 * a6xx_gmu_fw_start() - set up GMU and start FW
 * @device: Pointer to KGSL device
@@ -1530,6 +1622,13 @@ static int a6xx_gmu_fw_start(struct kgsl_device *device,
	kgsl_gmu_regwrite(device, A6XX_GMU_AHB_FENCE_RANGE_0,
			FENCE_RANGE_MASK);

	if (ADRENO_FEATURE(adreno_dev, ADRENO_LM) &&
		test_bit(ADRENO_LM_CTRL, &adreno_dev->pwrctrl_flag)) {
		kgsl_gmu_regwrite(device, A6XX_GPU_GMU_CX_GMU_PWR_THRESHOLD,
			lm_limit(adreno_dev));
		isense_cold_trimm(device);
	}

	/* Configure power control and bring the GMU out of reset */
	a6xx_gmu_power_config(device);
	ret = a6xx_gmu_start(device);
@@ -1759,7 +1858,8 @@ static void a6xx_isense_disable(struct kgsl_device *device)
	unsigned int val;
	const struct adreno_device *adreno_dev = ADRENO_DEVICE(device);

	if (!ADRENO_FEATURE(adreno_dev, ADRENO_LM))
	if (!ADRENO_FEATURE(adreno_dev, ADRENO_LM) ||
		!test_bit(ADRENO_LM_CTRL, &adreno_dev->pwrctrl_flag))
		return;

	kgsl_gmu_regread(device, A6XX_GPU_CS_ENABLE_REG, &val);
@@ -1775,7 +1875,8 @@ static int a6xx_llm_glm_handshake(struct kgsl_device *device)
	const struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
	struct gmu_device *gmu = &device->gmu;

	if (!ADRENO_FEATURE(adreno_dev, ADRENO_LM))
	if (!ADRENO_FEATURE(adreno_dev, ADRENO_LM) ||
		!test_bit(ADRENO_LM_CTRL, &adreno_dev->pwrctrl_flag))
		return 0;

	kgsl_gmu_regread(device, A6XX_GMU_LLM_GLM_SLEEP_CTRL, &val);
@@ -1794,6 +1895,19 @@ static int a6xx_llm_glm_handshake(struct kgsl_device *device)
	return 0;
}


static void a6xx_count_throttles(struct adreno_device *adreno_dev,
	uint64_t adj)
{
	if (!ADRENO_FEATURE(adreno_dev, ADRENO_LM) ||
		!test_bit(ADRENO_LM_CTRL, &adreno_dev->pwrctrl_flag))
		return;

	kgsl_gmu_regread(KGSL_DEVICE(adreno_dev),
		adreno_dev->lm_threshold_count,
		&adreno_dev->lm_threshold_cross);
}

static int a6xx_complete_rpmh_votes(struct kgsl_device *device)
{
	int ret = 0;
@@ -2807,6 +2921,7 @@ struct adreno_gpudev adreno_a6xx_gpudev = {
	.regulator_disable = a6xx_sptprac_disable,
	.perfcounters = &a6xx_perfcounters,
	.enable_pwr_counters = a6xx_enable_pwr_counters,
	.count_throttles = a6xx_count_throttles,
	.microcode_read = a6xx_microcode_read,
	.enable_64bit = a6xx_enable_64bit,
	.llc_configure_gpu_scid = a6xx_llc_configure_gpu_scid,
+2 −0
Original line number Diff line number Diff line
@@ -1166,6 +1166,8 @@ int gmu_probe(struct kgsl_device *device)
	else
		gmu->idle_level = GPU_HW_ACTIVE;

	/* disable LM during boot time */
	clear_bit(ADRENO_LM_CTRL, &adreno_dev->pwrctrl_flag);
	return 0;

error:
Loading