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

Commit 323b20c4 authored by Dave Airlie's avatar Dave Airlie
Browse files

Merge tag 'drm-msm-next-2018-01-10' of git://people.freedesktop.org/~robclark/linux into drm-next

Updates for 4.16.. fairly small this time around, main thing is
devfreq support for the gpu.

* tag 'drm-msm-next-2018-01-10' of git://people.freedesktop.org/~robclark/linux:
  drm/msm: Add devfreq support for the GPU
  drm/msm/adreno: a5xx: Explicitly program the CP0 performance counter
  drm/msm/adreno: Read the speed bins for a5xx targets
  drm/msm/adreno: Move clock parsing to adreno_gpu_init()
  drm/msm/adreno: Cleanup chipid parsing
  drm/msm/gpu: Remove unused bus scaling code
  drm/msm/adreno: Remove a useless call to dev_pm_opp_get_freq()
  drm/msm/adreno: Call dev_pm_opp_put()
  drm/msm: Fix NULL deref in adreno_load_gpu
  drm/msm: gpu: Only sync fences on rings that exist
  drm/msm: fix leak in failed get_pages
  drm/msm: avoid false-positive -Wmaybe-uninitialized warning
  drm/msm/mdp4: Deduplicate bus_find_device() by name matching
  drm/msm: add missing MODULE_FIRMWARE declarations
  drm/msm: update adreno firmware path in MODULE_FIRMWARE
  drm/msm: free kstrdup'd cmdline
  drm/msm: fix msm_rd_dump_submit prototype
  drm/msm: fix spelling mistake: "ringubffer" -> "ringbuffer"
parents fb8baefc f91c14ab
Loading
Loading
Loading
Loading
+38 −0
Original line number Diff line number Diff line
@@ -17,6 +17,8 @@
#include <linux/dma-mapping.h>
#include <linux/of_address.h>
#include <linux/soc/qcom/mdt_loader.h>
#include <linux/pm_opp.h>
#include <linux/nvmem-consumer.h>
#include "msm_gem.h"
#include "msm_mmu.h"
#include "a5xx_gpu.h"
@@ -595,6 +597,12 @@ static int a5xx_hw_init(struct msm_gpu *gpu)
	/* Turn on performance counters */
	gpu_write(gpu, REG_A5XX_RBBM_PERFCTR_CNTL, 0x01);

	/* Select CP0 to always count cycles */
	gpu_write(gpu, REG_A5XX_CP_PERFCTR_CP_SEL_0, PERF_CP_ALWAYS_COUNT);

	/* Select RBBM0 to countable 6 to get the busy status for devfreq */
	gpu_write(gpu, REG_A5XX_RBBM_PERFCTR_RBBM_SEL_0, 6);

	/* Increase VFD cache access so LRZ and other data gets evicted less */
	gpu_write(gpu, REG_A5XX_UCHE_CACHE_WAYS, 0x02);

@@ -1165,6 +1173,14 @@ static struct msm_ringbuffer *a5xx_active_ring(struct msm_gpu *gpu)
	return a5xx_gpu->cur_ring;
}

static int a5xx_gpu_busy(struct msm_gpu *gpu, uint64_t *value)
{
	*value = gpu_read64(gpu, REG_A5XX_RBBM_PERFCTR_RBBM_0_LO,
		REG_A5XX_RBBM_PERFCTR_RBBM_0_HI);

	return 0;
}

static const struct adreno_gpu_funcs funcs = {
	.base = {
		.get_param = adreno_get_param,
@@ -1180,10 +1196,30 @@ static const struct adreno_gpu_funcs funcs = {
#ifdef CONFIG_DEBUG_FS
		.show = a5xx_show,
#endif
		.gpu_busy = a5xx_gpu_busy,
	},
	.get_timestamp = a5xx_get_timestamp,
};

static void check_speed_bin(struct device *dev)
{
	struct nvmem_cell *cell;
	u32 bin, val;

	cell = nvmem_cell_get(dev, "speed_bin");

	/* If a nvmem cell isn't defined, nothing to do */
	if (IS_ERR(cell))
		return;

	bin = *((u32 *) nvmem_cell_read(cell, NULL));
	nvmem_cell_put(cell);

	val = (1 << bin);

	dev_pm_opp_set_supported_hw(dev, &val, 1);
}

struct msm_gpu *a5xx_gpu_init(struct drm_device *dev)
{
	struct msm_drm_private *priv = dev->dev_private;
@@ -1210,6 +1246,8 @@ struct msm_gpu *a5xx_gpu_init(struct drm_device *dev)

	a5xx_gpu->lm_leakage = 0x4E001A;

	check_speed_bin(&pdev->dev);

	ret = adreno_gpu_init(dev, pdev, adreno_gpu, &funcs, 4);
	if (ret) {
		a5xx_destroy(&(a5xx_gpu->base.base));
+7 −1
Original line number Diff line number Diff line
@@ -103,10 +103,16 @@ static inline uint32_t _get_mvolts(struct msm_gpu *gpu, uint32_t freq)
	struct msm_drm_private *priv = dev->dev_private;
	struct platform_device *pdev = priv->gpu_pdev;
	struct dev_pm_opp *opp;
	u32 ret = 0;

	opp = dev_pm_opp_find_freq_exact(&pdev->dev, freq, true);

	return (!IS_ERR(opp)) ? dev_pm_opp_get_voltage(opp) / 1000 : 0;
	if (!IS_ERR(opp)) {
		ret = dev_pm_opp_get_voltage(opp) / 1000;
		dev_pm_opp_put(opp);
	}

	return ret;
}

/* Setup thermal limit management */
+39 −101
Original line number Diff line number Diff line
@@ -17,7 +17,6 @@
 * this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#include <linux/pm_opp.h>
#include "adreno_gpu.h"

#define ANY_ID 0xff
@@ -90,14 +89,19 @@ static const struct adreno_info gpulist[] = {
	},
};

MODULE_FIRMWARE("a300_pm4.fw");
MODULE_FIRMWARE("a300_pfp.fw");
MODULE_FIRMWARE("a330_pm4.fw");
MODULE_FIRMWARE("a330_pfp.fw");
MODULE_FIRMWARE("a420_pm4.fw");
MODULE_FIRMWARE("a420_pfp.fw");
MODULE_FIRMWARE("a530_fm4.fw");
MODULE_FIRMWARE("a530_pfp.fw");
MODULE_FIRMWARE("qcom/a300_pm4.fw");
MODULE_FIRMWARE("qcom/a300_pfp.fw");
MODULE_FIRMWARE("qcom/a330_pm4.fw");
MODULE_FIRMWARE("qcom/a330_pfp.fw");
MODULE_FIRMWARE("qcom/a420_pm4.fw");
MODULE_FIRMWARE("qcom/a420_pfp.fw");
MODULE_FIRMWARE("qcom/a530_pm4.fw");
MODULE_FIRMWARE("qcom/a530_pfp.fw");
MODULE_FIRMWARE("qcom/a530v3_gpmu.fw2");
MODULE_FIRMWARE("qcom/a530_zap.mdt");
MODULE_FIRMWARE("qcom/a530_zap.b00");
MODULE_FIRMWARE("qcom/a530_zap.b01");
MODULE_FIRMWARE("qcom/a530_zap.b02");

static inline bool _rev_match(uint8_t entry, uint8_t id)
{
@@ -125,11 +129,14 @@ struct msm_gpu *adreno_load_gpu(struct drm_device *dev)
{
	struct msm_drm_private *priv = dev->dev_private;
	struct platform_device *pdev = priv->gpu_pdev;
	struct msm_gpu *gpu = platform_get_drvdata(priv->gpu_pdev);
	struct msm_gpu *gpu = NULL;
	int ret;

	if (pdev)
		gpu = platform_get_drvdata(pdev);

	if (!gpu) {
		dev_err(dev->dev, "no adreno device\n");
		dev_err_once(dev->dev, "no GPU device was found\n");
		return NULL;
	}

@@ -153,101 +160,45 @@ static void set_gpu_pdev(struct drm_device *dev,
	priv->gpu_pdev = pdev;
}

static int find_chipid(struct device *dev, u32 *chipid)
static int find_chipid(struct device *dev, struct adreno_rev *rev)
{
	struct device_node *node = dev->of_node;
	const char *compat;
	int ret;
	u32 chipid;

	/* first search the compat strings for qcom,adreno-XYZ.W: */
	ret = of_property_read_string_index(node, "compatible", 0, &compat);
	if (ret == 0) {
		unsigned rev, patch;
		unsigned int r, patch;

		if (sscanf(compat, "qcom,adreno-%u.%u", &rev, &patch) == 2) {
			*chipid = 0;
			*chipid |= (rev / 100) << 24;  /* core */
			rev %= 100;
			*chipid |= (rev / 10) << 16;   /* major */
			rev %= 10;
			*chipid |= rev << 8;           /* minor */
			*chipid |= patch;
		if (sscanf(compat, "qcom,adreno-%u.%u", &r, &patch) == 2) {
			rev->core = r / 100;
			r %= 100;
			rev->major = r / 10;
			r %= 10;
			rev->minor = r;
			rev->patchid = patch;

			return 0;
		}
	}

	/* and if that fails, fall back to legacy "qcom,chipid" property: */
	ret = of_property_read_u32(node, "qcom,chipid", chipid);
	if (ret)
	ret = of_property_read_u32(node, "qcom,chipid", &chipid);
	if (ret) {
		dev_err(dev, "could not parse qcom,chipid: %d\n", ret);
		return ret;

	dev_warn(dev, "Using legacy qcom,chipid binding!\n");
	dev_warn(dev, "Use compatible qcom,adreno-%u%u%u.%u instead.\n",
			(*chipid >> 24) & 0xff, (*chipid >> 16) & 0xff,
			(*chipid >> 8) & 0xff, *chipid & 0xff);

	return 0;
}

/* Get legacy powerlevels from qcom,gpu-pwrlevels and populate the opp table */
static int adreno_get_legacy_pwrlevels(struct device *dev)
{
	struct device_node *child, *node;
	int ret;

	node = of_find_compatible_node(dev->of_node, NULL,
		"qcom,gpu-pwrlevels");
	if (!node) {
		dev_err(dev, "Could not find the GPU powerlevels\n");
		return -ENXIO;
	}

	for_each_child_of_node(node, child) {
		unsigned int val;

		ret = of_property_read_u32(child, "qcom,gpu-freq", &val);
		if (ret)
			continue;

		/*
		 * Skip the intentionally bogus clock value found at the bottom
		 * of most legacy frequency tables
		 */
		if (val != 27000000)
			dev_pm_opp_add(dev, val, 0);
	}

	return 0;
}

static int adreno_get_pwrlevels(struct device *dev,
		struct adreno_platform_config *config)
{
	unsigned long freq = ULONG_MAX;
	struct dev_pm_opp *opp;
	int ret;

	/* You down with OPP? */
	if (!of_find_property(dev->of_node, "operating-points-v2", NULL))
		ret = adreno_get_legacy_pwrlevels(dev);
	else
		ret = dev_pm_opp_of_add_table(dev);

	if (ret)
		return ret;

	/* Find the fastest defined rate */
	opp = dev_pm_opp_find_freq_floor(dev, &freq);
	if (!IS_ERR(opp))
		config->fast_rate = dev_pm_opp_get_freq(opp);
	rev->core = (chipid >> 24) & 0xff;
	rev->major = (chipid >> 16) & 0xff;
	rev->minor = (chipid >> 8) & 0xff;
	rev->patchid = (chipid & 0xff);

	if (!config->fast_rate) {
		DRM_DEV_INFO(dev,
			"Could not find clock rate. Using default\n");
		/* Pick a suitably safe clock speed for any target */
		config->fast_rate = 200000000;
	}
	dev_warn(dev, "Using legacy qcom,chipid binding!\n");
	dev_warn(dev, "Use compatible qcom,adreno-%u%u%u.%u instead.\n",
		rev->core, rev->major, rev->minor, rev->patchid);

	return 0;
}
@@ -258,22 +209,9 @@ static int adreno_bind(struct device *dev, struct device *master, void *data)
	const struct adreno_info *info;
	struct drm_device *drm = dev_get_drvdata(master);
	struct msm_gpu *gpu;
	u32 val;
	int ret;

	ret = find_chipid(dev, &val);
	if (ret) {
		dev_err(dev, "could not find chipid: %d\n", ret);
		return ret;
	}

	config.rev = ADRENO_REV((val >> 24) & 0xff,
			(val >> 16) & 0xff, (val >> 8) & 0xff, val & 0xff);

	/* find clock rates: */
	config.fast_rate = 0;

	ret = adreno_get_pwrlevels(dev, &config);
	ret = find_chipid(dev, &config.rev);
	if (ret)
		return ret;

+74 −11
Original line number Diff line number Diff line
@@ -17,11 +17,11 @@
 * this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#include <linux/pm_opp.h>
#include "adreno_gpu.h"
#include "msm_gem.h"
#include "msm_mmu.h"


int adreno_get_param(struct msm_gpu *gpu, uint32_t param, uint64_t *value)
{
	struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu);
@@ -461,10 +461,80 @@ void adreno_wait_ring(struct msm_ringbuffer *ring, uint32_t ndwords)
{
	if (spin_until(ring_freewords(ring) >= ndwords))
		DRM_DEV_ERROR(ring->gpu->dev->dev,
			"timeout waiting for space in ringubffer %d\n",
			"timeout waiting for space in ringbuffer %d\n",
			ring->id);
}

/* Get legacy powerlevels from qcom,gpu-pwrlevels and populate the opp table */
static int adreno_get_legacy_pwrlevels(struct device *dev)
{
	struct device_node *child, *node;
	int ret;

	node = of_find_compatible_node(dev->of_node, NULL,
		"qcom,gpu-pwrlevels");
	if (!node) {
		dev_err(dev, "Could not find the GPU powerlevels\n");
		return -ENXIO;
	}

	for_each_child_of_node(node, child) {
		unsigned int val;

		ret = of_property_read_u32(child, "qcom,gpu-freq", &val);
		if (ret)
			continue;

		/*
		 * Skip the intentionally bogus clock value found at the bottom
		 * of most legacy frequency tables
		 */
		if (val != 27000000)
			dev_pm_opp_add(dev, val, 0);
	}

	return 0;
}

static int adreno_get_pwrlevels(struct device *dev,
		struct msm_gpu *gpu)
{
	unsigned long freq = ULONG_MAX;
	struct dev_pm_opp *opp;
	int ret;

	gpu->fast_rate = 0;

	/* You down with OPP? */
	if (!of_find_property(dev->of_node, "operating-points-v2", NULL))
		ret = adreno_get_legacy_pwrlevels(dev);
	else {
		ret = dev_pm_opp_of_add_table(dev);
		if (ret)
			dev_err(dev, "Unable to set the OPP table\n");
	}

	if (!ret) {
		/* Find the fastest defined rate */
		opp = dev_pm_opp_find_freq_floor(dev, &freq);
		if (!IS_ERR(opp)) {
			gpu->fast_rate = freq;
			dev_pm_opp_put(opp);
		}
	}

	if (!gpu->fast_rate) {
		dev_warn(dev,
			"Could not find a clock rate. Using a reasonable default\n");
		/* Pick a suitably safe clock speed for any target */
		gpu->fast_rate = 200000000;
	}

	DBG("fast_rate=%u, slow_rate=27000000", gpu->fast_rate);

	return 0;
}

int adreno_gpu_init(struct drm_device *drm, struct platform_device *pdev,
		struct adreno_gpu *adreno_gpu,
		const struct adreno_gpu_funcs *funcs, int nr_rings)
@@ -479,15 +549,6 @@ int adreno_gpu_init(struct drm_device *drm, struct platform_device *pdev,
	adreno_gpu->revn = adreno_gpu->info->revn;
	adreno_gpu->rev = config->rev;

	gpu->fast_rate = config->fast_rate;
	gpu->bus_freq  = config->bus_freq;
#ifdef DOWNSTREAM_CONFIG_MSM_BUS_SCALING
	gpu->bus_scale_table = config->bus_scale_table;
#endif

	DBG("fast_rate=%u, slow_rate=27000000, bus_freq=%u",
			gpu->fast_rate, gpu->bus_freq);

	adreno_gpu_config.ioname = "kgsl_3d0_reg_memory";
	adreno_gpu_config.irqname = "kgsl_3d0_irq";

@@ -496,6 +557,8 @@ int adreno_gpu_init(struct drm_device *drm, struct platform_device *pdev,

	adreno_gpu_config.nr_rings = nr_rings;

	adreno_get_pwrlevels(&pdev->dev, gpu);

	pm_runtime_set_autosuspend_delay(&pdev->dev, DRM_MSM_INACTIVE_PERIOD);
	pm_runtime_use_autosuspend(&pdev->dev);
	pm_runtime_enable(&pdev->dev);
+0 −4
Original line number Diff line number Diff line
@@ -129,10 +129,6 @@ struct adreno_gpu {
/* platform config data (ie. from DT, or pdata) */
struct adreno_platform_config {
	struct adreno_rev rev;
	uint32_t fast_rate, bus_freq;
#ifdef DOWNSTREAM_CONFIG_MSM_BUS_SCALING
	struct msm_bus_scale_pdata *bus_scale_table;
#endif
};

#define ADRENO_IDLE_TIMEOUT msecs_to_jiffies(1000)
Loading