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

Commit b4a6c919 authored by Kasin Li's avatar Kasin Li Committed by Jin Li
Browse files

adreno/DRM: Get clock rate list from pwrlevel-bins



For Adreno 5 driver under DRM framework, use qcom,gpu-pwrlevel-bins
to get the clock rate list. The driver for older GPU version is
still using qcom,gpu-pwrlevels.

Change-Id: Ic9ed0164ef54f8d318970df59720e88b3f277e7f
Signed-off-by: default avatarKasin Li <donglil@codeaurora.org>
parent 3eaee7d3
Loading
Loading
Loading
Loading
+133 −65
Original line number Diff line number Diff line
@@ -19,6 +19,7 @@

#include <linux/of_platform.h>
#include "adreno_gpu.h"
#include "pwrctl.h"

#if defined(CONFIG_MSM_BUS_SCALING) && !defined(CONFIG_OF)
#  include <linux/kgsl.h>
@@ -315,93 +316,160 @@ static void set_gpu_pdev(struct drm_device *dev,
	priv->gpu_pdev = pdev;
}

static int adreno_bind(struct device *dev, struct device *master, void *data)
static int of_parse_legacy_clk(struct adreno_platform_config *config,
			      struct device_node *node)
{
	static struct adreno_platform_config config = {};
#ifdef CONFIG_OF
	struct device_node *child, *node = dev->of_node;
	struct device_node *child;
	u32 val;
	int ret;

	ret = of_property_read_u32(node, "qcom,chipid", &val);
	if (ret) {
		dev_err(dev, "could not find chipid: %d\n", ret);
	for_each_available_child_of_node(node, child) {
		if (of_device_is_compatible(child, "qcom,gpu-pwrlevels")) {
			struct device_node *pwrlvl;

			for_each_available_child_of_node(child, pwrlvl) {
				ret = of_property_read_u32(pwrlvl,
					"qcom,gpu-freq", &val);
				if (ret)
					return ret;
				config->fast_rate = max(config->fast_rate, val);
				config->slow_rate = min(config->slow_rate, val);
			}
		}
	}
	return 0;
}

	config.rev = ADRENO_REV((val >> 24) & 0xff,
			(val >> 16) & 0xff, (val >> 8) & 0xff, val & 0xff);
int efuse_read_u32(struct adreno_platform_config *config,
			  unsigned int offset,
			  unsigned int *val)
{
	if (config->efuse_base == NULL)
		return -ENODEV;

	/* find clock rates: */
	config.fast_rate = 0;
	config.slow_rate = ~0;
	for_each_child_of_node(node, child) {
		if (of_device_is_compatible(child, "qcom,gpu-pwrlevels")) {
			struct device_node *pwrlvl;
			for_each_child_of_node(child, pwrlvl) {
				ret = of_property_read_u32(pwrlvl, "qcom,gpu-freq", &val);
				if (ret) {
					dev_err(dev, "could not find gpu-freq: %d\n", ret);
					return ret;
	if (offset >= config->efuse_len)
		return -ERANGE;

	if (val != NULL) {
		*val = readl_relaxed(config->efuse_base + offset);
		/* Make sure memory is updated before returning */
		rmb();
	}
				config.fast_rate = max(config.fast_rate, val);
				config.slow_rate = min(config.slow_rate, val);

	return 0;
}

static int of_parse_pwrlevels(struct adreno_platform_config *config,
			      struct device_node *node)
{
	struct drmgsl_pwrctl *pwrctl = config->pwrctl;
	struct drmgsl_pwrlevel *level;
	struct device_node *child;
	unsigned int index;
	int i = 0;

	for_each_available_child_of_node(node, child) {
		level = pwrctl->pwrlevels + i;

		if (of_property_read_u32(child, "reg", &index))
			return -EINVAL;

		if (of_property_read_u32(child, "qcom,gpu-freq",
			&level->gpu_freq))
			return -EINVAL;

		config->fast_rate = max(config->fast_rate, level->gpu_freq);
		config->slow_rate = min(config->slow_rate, level->gpu_freq);

		if (of_property_read_u32(child, "qcom,bus-freq",
			&level->bus_freq))
			return -EINVAL;

		if (of_property_read_u32(child, "qcom,bus-min",
			&level->bus_min))
			level->bus_min = level->bus_freq;

		if (of_property_read_u32(child, "qcom,bus-max",
			&level->bus_max))
			level->bus_max = level->bus_freq;
	}

	return 0;
}

	if (!config.fast_rate) {
		dev_err(dev, "could not find clk rates\n");
		return -ENXIO;
static int of_parse_pwrlevel_bin(struct device *dev,
				struct adreno_platform_config *config,
				struct device_node *node)
{
	struct device_node *child;
	struct drmgsl_pwrctl *pwrctl;
	struct drmgsl_pwrlevel *pwrlevels;
	unsigned int n;

	pwrctl = devm_kzalloc(dev, sizeof(*config->pwrctl),
				      GFP_KERNEL);
	if (!pwrctl)
		return -ENOMEM;

	for_each_available_child_of_node(node, child) {
		unsigned int bin;

		if (of_property_read_u32(child, "qcom,speed-bin", &bin))
			continue;

		if (bin != config->speed_bin)
			continue;

		n = of_get_child_count(child);
		if (n == 0)
			return -EINVAL;

		pwrlevels = devm_kmalloc_array(dev, n,
					       sizeof(*pwrlevels),
					       GFP_KERNEL);
		if (!pwrlevels)
			return -ENOMEM;

		pwrctl->level_num = n;
		pwrctl->pwrlevels = pwrlevels;
		config->pwrctl = pwrctl;
		return of_parse_pwrlevels(config, child);
	}
	return -EINVAL;
}

#else
	struct kgsl_device_platform_data *pdata = dev->platform_data;
	uint32_t version = socinfo_get_version();
	if (cpu_is_apq8064ab()) {
		config.fast_rate = 450000000;
		config.slow_rate = 27000000;
		config.bus_freq  = 4;
		config.rev = ADRENO_REV(3, 2, 1, 0);
	} else if (cpu_is_apq8064()) {
		config.fast_rate = 400000000;
		config.slow_rate = 27000000;
		config.bus_freq  = 4;

		if (SOCINFO_VERSION_MAJOR(version) == 2)
			config.rev = ADRENO_REV(3, 2, 0, 2);
		else if ((SOCINFO_VERSION_MAJOR(version) == 1) &&
				(SOCINFO_VERSION_MINOR(version) == 1))
			config.rev = ADRENO_REV(3, 2, 0, 1);
		else
			config.rev = ADRENO_REV(3, 2, 0, 0);
static int adreno_bind(struct device *dev, struct device *master, void *data)
{
	static struct adreno_platform_config config = {};
	struct device_node *root = dev->of_node;
	struct device_node *node;
	u32 val;
	int ret;

	} else if (cpu_is_msm8960ab()) {
		config.fast_rate = 400000000;
		config.slow_rate = 320000000;
		config.bus_freq  = 4;
	ret = of_property_read_u32(root, "qcom,chipid", &val);
	if (ret) {
		dev_err(dev, "could not find chipid: %d\n", ret);
		return ret;
	}

		if (SOCINFO_VERSION_MINOR(version) == 0)
			config.rev = ADRENO_REV(3, 2, 1, 0);
		else
			config.rev = ADRENO_REV(3, 2, 1, 1);
	config.rev = ADRENO_REV((val >> 24) & 0xff,
			(val >> 16) & 0xff, (val >> 8) & 0xff, val & 0xff);

	} else if (cpu_is_msm8930()) {
		config.fast_rate = 400000000;
		config.slow_rate = 27000000;
		config.bus_freq  = 3;
	/* find clock rates: */
	config.fast_rate = 0;
	config.slow_rate = ~0;

		if ((SOCINFO_VERSION_MAJOR(version) == 1) &&
			(SOCINFO_VERSION_MINOR(version) == 2))
			config.rev = ADRENO_REV(3, 0, 5, 2);
	node = of_find_node_by_name(root, "qcom,gpu-pwrlevel-bins");
	if (node == NULL)
		ret = of_parse_legacy_clk(&config, root);
	else
			config.rev = ADRENO_REV(3, 0, 5, 0);
		ret = of_parse_pwrlevel_bin(dev, &config, node);

	if (ret || !config.fast_rate) {
		dev_err(dev, "could not find clk rates\n");
		return -ENXIO;
	}
#ifdef CONFIG_MSM_BUS_SCALING
	config.bus_scale_table = pdata->bus_scale_table;
#endif
#endif

	dev->platform_data = &config;
	set_gpu_pdev(dev_get_drvdata(master), to_platform_device(dev));
	return adreno_iommu_probe(to_platform_device(dev));
+6 −0
Original line number Diff line number Diff line
@@ -231,6 +231,7 @@ struct adreno_gpu {
};
#define to_adreno_gpu(x) container_of(x, struct adreno_gpu, base)

struct drmgsl_pwrctl;
/* platform config data (ie. from DT, or pdata) */
struct adreno_platform_config {
	struct adreno_rev rev;
@@ -239,6 +240,11 @@ struct adreno_platform_config {
#ifdef CONFIG_MSM_BUS_SCALING
	struct msm_bus_scale_pdata *bus_scale_table;
#endif
	struct drmgsl_pwrctl *pwrctl;
	unsigned int speed_bin;

	void __iomem *efuse_base;
	size_t efuse_len;
};

#define ADRENO_UCHE_GMEM_BASE	0x100000
+38 −0
Original line number Diff line number Diff line
/* Copyright (c) 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
 * only version 2 as published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 */

#ifndef __DRMGSL_PWRCTL_H
#define __DRMGSL_PWRCTL_H

struct drmgsl_pwrlevel {
	unsigned int gpu_freq;
	unsigned int bus_freq;
	unsigned int bus_min;
	unsigned int bus_max;
};

struct drmgsl_pwrctl {
	struct drmgsl_pwrlevel *pwrlevels;
	unsigned int level_num;
	unsigned int active_pwrlevel;
	unsigned int previous_pwrlevel;
	unsigned int thermal_pwrlevel;
	unsigned int default_pwrlevel;
	unsigned int wakeup_maxpwrlevel;
	unsigned int max_pwrlevel;
	unsigned int min_pwrlevel;
	unsigned int num_pwrlevels;
	unsigned long interval_timeout;
};

#endif /* __DRMGSL_PWRCTRL_H */