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

Commit f1298d0d authored by Jordan Crouse's avatar Jordan Crouse
Browse files

msm: kgsl: Tweek LLM sleep/wake algorithm



In the LLM sleep sequence, the IDLE_FULL_LM bit (0) needs to be set
to force the children to sleep.  Also, after the first child is
put to sleep, we need to wait for the idle acknowledgment before
taking the next child down.

In the wake sequence, poll until WAKEUP_ACK is 1 *and* IDLE_FULL_ACK
is 0 to ensure that the wake sequence was successful.

CRs-Fixed: 970270
Change-Id: Ic0dedbadfca1e0882d84965d634166f921f1e630
Signed-off-by: default avatarJordan Crouse <jcrouse@codeaurora.org>
parent a8d79f9c
Loading
Loading
Loading
Loading
+41 −24
Original line number Diff line number Diff line
@@ -1578,61 +1578,78 @@ static bool llm_is_enabled(struct adreno_device *adreno_dev)

static void sleep_llm(struct adreno_device *adreno_dev)
{
	unsigned int r, retry = 5;
	unsigned int r, retry;
	struct kgsl_device *device = KGSL_DEVICE(adreno_dev);

	if (!llm_is_enabled(adreno_dev))
		return;

	kgsl_regread(device, A5XX_GPMU_GPMU_LLM_GLM_SLEEP_CTRL, &r);

	if ((r & STATE_OF_CHILD) == 0) {
		kgsl_regwrite(device, A5XX_GPMU_GPMU_LLM_GLM_SLEEP_CTRL,
			(r | STATE_OF_CHILD_01) & ~STATE_OF_CHILD);
		/* If both children are on, sleep CHILD_O1 first */
		kgsl_regrmw(device, A5XX_GPMU_GPMU_LLM_GLM_SLEEP_CTRL,
			STATE_OF_CHILD, STATE_OF_CHILD_01 | IDLE_FULL_LM_SLEEP);
		/* Wait for IDLE_FULL_ACK before continuing */
		for (retry = 0; retry < 5; retry++) {
			udelay(1);
			kgsl_regread(device,
				A5XX_GPMU_GPMU_LLM_GLM_SLEEP_STATUS, &r);
			if (r & IDLE_FULL_ACK)
				break;
		}

	kgsl_regread(device, A5XX_GPMU_GPMU_LLM_GLM_SLEEP_CTRL, &r);
	kgsl_regwrite(device, A5XX_GPMU_GPMU_LLM_GLM_SLEEP_CTRL,
		(r | STATE_OF_CHILD_11) & ~STATE_OF_CHILD);
		if (retry == 5)
			KGSL_CORE_ERR("GPMU: LLM failed to idle: 0x%X\n", r);
	}

	do {
	/* Now turn off both children */
	kgsl_regrmw(device, A5XX_GPMU_GPMU_LLM_GLM_SLEEP_CTRL,
		0, STATE_OF_CHILD | IDLE_FULL_LM_SLEEP);

	/* wait for WAKEUP_ACK to be zero */
	for (retry = 0; retry < 5; retry++) {
		udelay(1);
		kgsl_regread(device, A5XX_GPMU_GPMU_LLM_GLM_SLEEP_STATUS, &r);
	} while (!(r & WAKEUP_ACK) && retry--);
		if ((r & WAKEUP_ACK) == 0)
			break;
	}

	if (!retry)
		KGSL_CORE_ERR("GPMU: LLM sleep failure\n");
	if (retry == 5)
		KGSL_CORE_ERR("GPMU: LLM failed to sleep: 0x%X\n", r);
}

static void wake_llm(struct adreno_device *adreno_dev)
{
	unsigned int r, retry = 5;
	unsigned int r, retry;
	struct kgsl_device *device = KGSL_DEVICE(adreno_dev);

	if (!llm_is_enabled(adreno_dev))
		return;

	kgsl_regread(device, A5XX_GPMU_GPMU_LLM_GLM_SLEEP_CTRL, &r);
	kgsl_regwrite(device, A5XX_GPMU_GPMU_LLM_GLM_SLEEP_CTRL,
		(r | STATE_OF_CHILD_01) & ~STATE_OF_CHILD);

	udelay(1);
	kgsl_regrmw(device, A5XX_GPMU_GPMU_LLM_GLM_SLEEP_CTRL,
		STATE_OF_CHILD, STATE_OF_CHILD_01);

	if (((device->pwrctrl.num_pwrlevels - 2) -
		device->pwrctrl.active_pwrlevel) <= LM_DCVS_LIMIT)
		return;

	kgsl_regread(device, A5XX_GPMU_TEMP_SENSOR_CONFIG, &r);
	kgsl_regwrite(device, A5XX_GPMU_GPMU_LLM_GLM_SLEEP_CTRL,
		r & ~STATE_OF_CHILD);
	udelay(1);

	do {
	/* Turn on all children */
	kgsl_regrmw(device, A5XX_GPMU_GPMU_LLM_GLM_SLEEP_CTRL,
		STATE_OF_CHILD | IDLE_FULL_LM_SLEEP, 0);

	/* Wait for IDLE_FULL_ACK to be zero and WAKEUP_ACK to be set */
	for (retry = 0; retry < 5; retry++) {
		udelay(1);
		kgsl_regread(device, A5XX_GPMU_GPMU_LLM_GLM_SLEEP_STATUS, &r);
	} while (!(r & WAKEUP_ACK) && retry--);
		if ((r & (WAKEUP_ACK | IDLE_FULL_ACK)) == WAKEUP_ACK)
			break;
	}

	if (!retry)
		KGSL_CORE_ERR("GPMU: LLM wakeup failure\n");
	if (retry == 5)
		KGSL_CORE_ERR("GPMU: LLM failed to wake: 0x%X\n", r);
}

static bool llm_is_awake(struct adreno_device *adreno_dev)
+2 −3
Original line number Diff line number Diff line
/* Copyright (c) 2015, The Linux Foundation. All rights reserved.
/* Copyright (c) 2015-2016, 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
@@ -95,12 +95,11 @@ void a5xx_crashdump_init(struct adreno_device *adreno_dev);
/* A5XX_GPMU_GPMU_LLM_GLM_SLEEP_CTRL */
#define STATE_OF_CHILD			GENMASK(5, 4)
#define STATE_OF_CHILD_01		BIT(4)
#define STATE_OF_CHILD_11		(BIT(4) | BIT(5))
#define IDLE_FULL_LM_SLEEP		BIT(0)

/* A5XX_GPMU_GPMU_LLM_GLM_SLEEP_STATUS */
#define WAKEUP_ACK			BIT(1)
#define IDLE_FULL_ACK_SLEEP		BIT(0)
#define IDLE_FULL_ACK			BIT(0)

/* A5XX_GPMU_TEMP_SENSOR_CONFIG */
#define GPMU_BCL_ENABLED		BIT(4)