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

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

msm: kgsl: Consolidate regulator calls



Create a struct kgsl_regulator and use it to store regulator
pointer/name pairs and conslidate the bits that allocate and
use regulators.

Change-Id: Ic0dedbad8fb104e30038cbdb35aa74ce9b0817e9
Signed-off-by: default avatarJordan Crouse <jcrouse@codeaurora.org>
parent 94475817
Loading
Loading
Loading
Loading
+46 −31
Original line number Diff line number Diff line
@@ -1354,6 +1354,24 @@ static int adreno_init(struct kgsl_device *device)
	return 0;
}

static bool regulators_left_on(struct kgsl_device *device)
{
	int i;

	for (i = 0; i < KGSL_MAX_REGULATORS; i++) {
		struct kgsl_regulator *regulator =
			&device->pwrctrl.regulators[i];

		if (IS_ERR_OR_NULL(regulator->reg))
			break;

		if (regulator_is_enabled(regulator->reg))
			return true;
	}

	return false;
}

/**
 * _adreno_start - Power up the GPU and prepare to accept commands
 * @adreno_dev: Pointer to an adreno_device structure
@@ -1365,9 +1383,9 @@ static int _adreno_start(struct adreno_device *adreno_dev)
{
	struct kgsl_device *device = &adreno_dev->dev;
	struct adreno_gpudev *gpudev = ADRENO_GPU_DEVICE(adreno_dev);
	int i, status = -EINVAL;
	int status = -EINVAL;
	unsigned int state = device->state;
	unsigned int regulator_left_on = 0;
	bool regulator_left_on;
	unsigned int pmqos_wakeup_vote = device->pwrctrl.pm_qos_wakeup_latency;
	unsigned int pmqos_active_vote = device->pwrctrl.pm_qos_active_latency;

@@ -1379,13 +1397,7 @@ static int _adreno_start(struct adreno_device *adreno_dev)

	kgsl_cffdump_open(device);

	for (i = 0; i < KGSL_MAX_REGULATORS; i++) {
		if (device->pwrctrl.gpu_reg[i] &&
			regulator_is_enabled(device->pwrctrl.gpu_reg[i])) {
			regulator_left_on = 1;
			break;
		}
	}
	regulator_left_on = regulators_left_on(device);

	/* Clear any GPU faults that might have been left over */
	adreno_clear_gpu_fault(adreno_dev);
@@ -2711,41 +2723,44 @@ static void adreno_iommu_sync(struct kgsl_device *device, bool sync)
	}
}

static void _regulator_disable(struct kgsl_regulator *regulator, bool poll)
{
	unsigned long wait_time = jiffies + msecs_to_jiffies(200);

	if (IS_ERR_OR_NULL(regulator->reg))
		return;

	regulator_disable(regulator->reg);

	if (poll == false)
		return;

	while (!time_after(jiffies, wait_time)) {
		if (!regulator_is_enabled(regulator->reg))
			return;
		cpu_relax();
	}

	KGSL_CORE_ERR("regulator '%s' still on after 200ms\n", regulator->name);
}

static void adreno_regulator_disable_poll(struct kgsl_device *device)
{
	struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
	struct kgsl_pwrctrl *pwr = &device->pwrctrl;
	unsigned long wait_time;
	int i, rail_on;
	int i;

	/* Fast path - hopefully we don't need this quirk */
	if (!ADRENO_QUIRK(adreno_dev, ADRENO_QUIRK_IOMMU_SYNC)) {
		for (i = KGSL_MAX_REGULATORS - 1; i >= 0; i--)
			if (pwr->gpu_reg[i] != NULL)
				regulator_disable(pwr->gpu_reg[i]);
			_regulator_disable(&pwr->regulators[i], false);
		return;
	}

	adreno_iommu_sync(device, true);

	/* Turn off CX and then GX as recommended by HW team */
	for (i = 0; i <= KGSL_MAX_REGULATORS - 1; i++) {
		if (pwr->gpu_reg[i] == NULL)
			continue;
		regulator_disable(pwr->gpu_reg[i]);
		rail_on = 1;
		wait_time = jiffies + msecs_to_jiffies(200);
		while (!time_after(jiffies, wait_time)) {
			if (!regulator_is_enabled(pwr->gpu_reg[i])) {
				rail_on = 0;
				break;
			}
			cpu_relax();
		}
		if (rail_on)
			KGSL_CORE_ERR("%s regulator on after 200ms\n",
				pwr->gpu_reg_name[i]);
	}
	for (i = 0; i < KGSL_MAX_REGULATORS; i++)
		_regulator_disable(&pwr->regulators[i], true);

	adreno_iommu_sync(device, false);
}
+73 −57
Original line number Diff line number Diff line
@@ -1348,10 +1348,49 @@ static void kgsl_pwrctrl_axi(struct kgsl_device *device, int state)
	}
}

static int _regulator_enable(struct kgsl_device *device,
		struct kgsl_regulator *regulator)
{
	int ret;

	if (IS_ERR_OR_NULL(regulator->reg))
		return 0;

	ret = regulator_enable(regulator->reg);
	if (ret)
		KGSL_DRV_ERR(device, "Failed to enable regulator '%s': %d\n",
			regulator->name, ret);
	return ret;
}

static void _regulator_disable(struct kgsl_regulator *regulator)
{
	if (!IS_ERR_OR_NULL(regulator->reg))
		regulator_disable(regulator->reg);
}

static int _enable_regulators(struct kgsl_device *device,
		struct kgsl_pwrctrl *pwr)
{
	int i;

	for (i = 0; i < KGSL_MAX_REGULATORS; i++) {
		int ret = _regulator_enable(device, &pwr->regulators[i]);

		if (ret) {
			for (i = i - 1; i >= 0; i--)
				_regulator_disable(&pwr->regulators[i]);
			return ret;
		}
	}

	return 0;
}

static int kgsl_pwrctrl_pwrrail(struct kgsl_device *device, int state)
{
	struct kgsl_pwrctrl *pwr = &device->pwrctrl;
	int i, j, status = 0;
	int status = 0;

	if (test_bit(KGSL_PWRFLAGS_POWER_ON, &pwr->ctrl_flags))
		return 0;
@@ -1365,28 +1404,12 @@ static int kgsl_pwrctrl_pwrrail(struct kgsl_device *device, int state)
	} else if (state == KGSL_PWRFLAGS_ON) {
		if (!test_and_set_bit(KGSL_PWRFLAGS_POWER_ON,
			&pwr->power_flags)) {
			for (i = 0; i < KGSL_MAX_REGULATORS; i++) {
				if (pwr->gpu_reg[i])
					status = regulator_enable(
							pwr->gpu_reg[i]);
				if (status) {
					KGSL_DRV_ERR(device,
						"%s regulator failure: %d\n",
						pwr->gpu_reg_name[i],
						status);
					break;
				}
			}
				status = _enable_regulators(device, pwr);

			if (status) {
				for (j = i - 1; j >= 0; j--) {
					if (pwr->gpu_reg[j])
						regulator_disable(
							pwr->gpu_reg[j]);
				}
				if (status)
					clear_bit(KGSL_PWRFLAGS_POWER_ON,
						&pwr->power_flags);
			} else
				else
					trace_kgsl_rail(device, state);
		}
	}
@@ -1475,29 +1498,33 @@ void kgsl_deep_nap_timer(unsigned long data)
	}
}

static int _get_regulator(struct kgsl_device *device,
		struct kgsl_regulator *regulator, const char *str)
{
	regulator->reg = devm_regulator_get(&device->pdev->dev, str);
	if (IS_ERR(regulator->reg)) {
		KGSL_CORE_ERR("Couldn't get regulator: %s (%ld)\n",
			str, PTR_ERR(regulator->reg));
		return PTR_ERR(regulator->reg);
	}

	strlcpy(regulator->name, str, sizeof(regulator->name));
	return 0;
}

static int get_legacy_regulators(struct kgsl_device *device)
{
	struct device *dev = &device->pdev->dev;
	struct kgsl_pwrctrl *pwr = &device->pwrctrl;
	int ret;

	pwr->gpu_reg[0] = regulator_get(dev, "vdd");
	if (IS_ERR(pwr->gpu_reg[0])) {
		KGSL_CORE_ERR("Couldn't get 'vdd' regulator\n");
		pwr->gpu_reg[0] = NULL;
		return -ENODEV;
	}
	ret = _get_regulator(device, &pwr->regulators[0], "vdd");

	/* Use vddcx only on targets that have it. */
	if (of_find_property(dev->of_node, "vddcx-supply", NULL)) {
		pwr->gpu_reg[1] = regulator_get(dev, "vddcx");
		if (IS_ERR(pwr->gpu_reg[1])) {
			KGSL_CORE_ERR("Couldn't get 'cx' regulator\n");
			pwr->gpu_reg[1] = NULL;
			return -ENODEV;
		}
	}
	if (ret == 0 && of_find_property(dev->of_node, "vddcx-supply", NULL))
		ret = _get_regulator(device, &pwr->regulators[1], "vddcx");

	return 0;
	return ret;
}

static int get_regulators(struct kgsl_device *device)
@@ -1511,25 +1538,18 @@ static int get_regulators(struct kgsl_device *device)
	if (!of_find_property(dev->of_node, "regulator-names", NULL))
		return get_legacy_regulators(device);

	of_property_for_each_string(dev->of_node, "regulator-names", prop,
		name) {
		struct regulator *reg;
	of_property_for_each_string(dev->of_node,
		"regulator-names", prop, name) {
		int ret;

		if (index == KGSL_MAX_REGULATORS) {
			KGSL_CORE_ERR("Too many regulators defined\n");
			return -ENOMEM;
		}

		reg = regulator_get(dev, name);
		if (IS_ERR(reg)) {
			KGSL_CORE_ERR("Couldn't get '%s' regulator\n", name);
			pwr->gpu_reg[index] = NULL;
			return -ENODEV;
		}

		pwr->gpu_reg[index] = reg;
		strlcpy(pwr->gpu_reg_name[index], name,
			KGSL_MAX_REGULATOR_NAME_LEN);
		ret = _get_regulator(device, &pwr->regulators[index], name);
		if (ret)
			return ret;
		index++;
	}

@@ -1778,12 +1798,8 @@ void kgsl_pwrctrl_close(struct kgsl_device *device)

	pwr->ocmem_pcl = 0;

	for (i = 0; i < KGSL_MAX_REGULATORS; i++) {
		if (pwr->gpu_reg[i]) {
			regulator_put(pwr->gpu_reg[i]);
			pwr->gpu_reg[i] = NULL;
		}
	}
	for (i = 0; i < KGSL_MAX_REGULATORS; i++)
		pwr->regulators[i].reg = NULL;

	for (i = 0; i < KGSL_MAX_REGULATORS; i++)
		pwr->grp_clks[i] = NULL;
+7 −5
Original line number Diff line number Diff line
@@ -29,7 +29,6 @@

#define KGSL_MAX_CLKS 11
#define KGSL_MAX_REGULATORS 2
#define KGSL_MAX_REGULATOR_NAME_LEN 8

#define KGSL_MAX_PWRLEVELS 10

@@ -103,6 +102,11 @@ struct kgsl_pwrlevel {
	unsigned int bus_max;
};

struct kgsl_regulator {
	struct regulator *reg;
	char name[8];
};

/**
 * struct kgsl_pwrctrl - Power control settings for a KGSL device
 * @interrupt_num - The interrupt number for the device
@@ -119,8 +123,7 @@ struct kgsl_pwrlevel {
 * @num_pwrlevels - number of available power levels
 * @interval_timeout - timeout in jiffies to be idle before a power event
 * @strtstp_sleepwake - true if the device supports low latency GPU start/stop
 * @gpu_reg - array of pointers to the regulator structures
 * @gpu_reg_name - array of pointers to the regulator names
 * @regulators - array of pointers to kgsl_regulator structs
 * @pcl - bus scale identifier
 * @ocmem - ocmem bus scale identifier
 * @irq_name - resource name for the IRQ
@@ -168,8 +171,7 @@ struct kgsl_pwrctrl {
	unsigned int num_pwrlevels;
	unsigned long interval_timeout;
	bool strtstp_sleepwake;
	struct regulator *gpu_reg[KGSL_MAX_REGULATORS];
	char gpu_reg_name[KGSL_MAX_REGULATORS][KGSL_MAX_REGULATOR_NAME_LEN];
	struct kgsl_regulator regulators[KGSL_MAX_REGULATORS];
	uint32_t pcl;
	uint32_t ocmem_pcl;
	const char *irq_name;