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

Commit d455937e authored by Dave Airlie's avatar Dave Airlie
Browse files

Merge branch 'msm-next' of git://people.freedesktop.org/~robclark/linux into drm-next

Noteworthy changes this time:
1) 4k support for newer chips (ganging up hwpipes and mixers)
2) using OPP bindings for gpu
3) more prep work towards per-process pagetables

* 'msm-next' of git://people.freedesktop.org/~robclark/linux: (47 commits)
  msm/drm: gpu: Dynamically locate the clocks from the device tree
  drm/msm: gpu: Use OPP tables if we can
  drm/msm: Hard code the GPU "slow frequency"
  drm/msm: Add MSM_PARAM_GMEM_BASE
  drm/msm: Reference count address spaces
  drm/msm: Make sure to detach the MMU during GPU cleanup
  drm/msm/mdp5: Enable 3D mux in mdp5_ctl
  drm/msm/mdp5: Reset CTL blend registers before configuring them
  drm/msm/mdp5: Assign 'right' mixer to CRTC state
  drm/msm/mdp5: Stage border out on base stage if CRTC has 2 LMs
  drm/msm/mdp5: Stage right side hwpipes on Right-side Layer Mixer
  drm/msm/mdp5: Prepare Layer Mixers for source split
  drm/msm/mdp5: Configure 'right' hwpipe
  drm/msm/mdp5: Assign a 'right hwpipe' to plane state
  drm/msm/mdp5: Create mdp5_hwpipe_mode_set
  drm/msm/mdp5: Add optional 'right' Layer Mixer in CRTC state
  drm/msm/mdp5: Add a CAP for Source Split
  drm/msm/mdp5: Remove mixer/intf pointers from mdp5_ctl
  drm/msm/mdp5: Start using parameters from CRTC state
  drm/msm/mdp5: Add more stuff to CRTC state
  ...
parents df45eaca 98db803f
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -40,6 +40,7 @@ msm-y := \
	mdp/mdp5/mdp5_mdss.o \
	mdp/mdp5/mdp5_kms.o \
	mdp/mdp5/mdp5_pipe.o \
	mdp/mdp5/mdp5_mixer.o \
	mdp/mdp5/mdp5_plane.o \
	mdp/mdp5/mdp5_smp.o \
	msm_atomic.o \
+0 −2
Original line number Diff line number Diff line
@@ -412,10 +412,8 @@ static const unsigned int a3xx_registers[] = {
#ifdef CONFIG_DEBUG_FS
static void a3xx_show(struct msm_gpu *gpu, struct seq_file *m)
{
	gpu->funcs->pm_resume(gpu);
	seq_printf(m, "status:   %08x\n",
			gpu_read(gpu, REG_A3XX_RBBM_STATUS));
	gpu->funcs->pm_suspend(gpu);
	adreno_show(gpu, m);
}
#endif
+0 −4
Original line number Diff line number Diff line
@@ -456,12 +456,8 @@ static const unsigned int a4xx_registers[] = {
#ifdef CONFIG_DEBUG_FS
static void a4xx_show(struct msm_gpu *gpu, struct seq_file *m)
{
	gpu->funcs->pm_resume(gpu);

	seq_printf(m, "status:   %08x\n",
			gpu_read(gpu, REG_A4XX_RBBM_STATUS));
	gpu->funcs->pm_suspend(gpu);

	adreno_show(gpu, m);

}
+13 −9
Original line number Diff line number Diff line
@@ -638,10 +638,8 @@ static void a5xx_cp_err_irq(struct msm_gpu *gpu)
	}
}

static void a5xx_rbbm_err_irq(struct msm_gpu *gpu)
static void a5xx_rbbm_err_irq(struct msm_gpu *gpu, u32 status)
{
	u32 status = gpu_read(gpu, REG_A5XX_RBBM_INT_0_STATUS);

	if (status & A5XX_RBBM_INT_0_MASK_RBBM_AHB_ERROR) {
		u32 val = gpu_read(gpu, REG_A5XX_RBBM_AHB_ERROR_STATUS);

@@ -653,6 +651,10 @@ static void a5xx_rbbm_err_irq(struct msm_gpu *gpu)

		/* Clear the error */
		gpu_write(gpu, REG_A5XX_RBBM_AHB_CMD, (1 << 4));

		/* Clear the interrupt */
		gpu_write(gpu, REG_A5XX_RBBM_INT_CLEAR_CMD,
			A5XX_RBBM_INT_0_MASK_RBBM_AHB_ERROR);
	}

	if (status & A5XX_RBBM_INT_0_MASK_RBBM_TRANSFER_TIMEOUT)
@@ -704,10 +706,16 @@ static irqreturn_t a5xx_irq(struct msm_gpu *gpu)
{
	u32 status = gpu_read(gpu, REG_A5XX_RBBM_INT_0_STATUS);

	gpu_write(gpu, REG_A5XX_RBBM_INT_CLEAR_CMD, status);
	/*
	 * Clear all the interrupts except RBBM_AHB_ERROR - if we clear it
	 * before the source is cleared the interrupt will storm.
	 */
	gpu_write(gpu, REG_A5XX_RBBM_INT_CLEAR_CMD,
		status & ~A5XX_RBBM_INT_0_MASK_RBBM_AHB_ERROR);

	/* Pass status to a5xx_rbbm_err_irq because we've already cleared it */
	if (status & RBBM_ERROR_MASK)
		a5xx_rbbm_err_irq(gpu);
		a5xx_rbbm_err_irq(gpu, status);

	if (status & A5XX_RBBM_INT_0_MASK_CP_HW_ERROR)
		a5xx_cp_err_irq(gpu);
@@ -837,12 +845,8 @@ static int a5xx_get_timestamp(struct msm_gpu *gpu, uint64_t *value)
#ifdef CONFIG_DEBUG_FS
static void a5xx_show(struct msm_gpu *gpu, struct seq_file *m)
{
	gpu->funcs->pm_resume(gpu);

	seq_printf(m, "status:   %08x\n",
			gpu_read(gpu, REG_A5XX_RBBM_STATUS));
	gpu->funcs->pm_suspend(gpu);

	adreno_show(gpu, m);
}
#endif
+93 −33
Original line number Diff line number Diff line
@@ -2,7 +2,7 @@
 * Copyright (C) 2013-2014 Red Hat
 * Author: Rob Clark <robdclark@gmail.com>
 *
 * Copyright (c) 2014 The Linux Foundation. All rights reserved.
 * Copyright (c) 2014,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 as published by
@@ -17,6 +17,7 @@
 * this program.  If not, see <http://www.gnu.org/licenses/>.
 */

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

#define ANY_ID 0xff
@@ -155,21 +156,14 @@ struct msm_gpu *adreno_load_gpu(struct drm_device *dev)

	if (gpu) {
		int ret;
		mutex_lock(&dev->struct_mutex);
		gpu->funcs->pm_resume(gpu);
		mutex_unlock(&dev->struct_mutex);

		disable_irq(gpu->irq);

		ret = gpu->funcs->hw_init(gpu);
		pm_runtime_get_sync(&pdev->dev);
		ret = msm_gpu_hw_init(gpu);
		pm_runtime_put_sync(&pdev->dev);
		if (ret) {
			dev_err(dev->dev, "gpu hw init failed: %d\n", ret);
			gpu->funcs->destroy(gpu);
			gpu = NULL;
		} else {
			enable_irq(gpu->irq);
			/* give inactive pm a chance to kick in: */
			msm_gpu_retire(gpu);
		}
	}

@@ -220,10 +214,71 @@ static int find_chipid(struct device *dev, u32 *chipid)
	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);

	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;
	}

	return 0;
}

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

@@ -238,28 +293,10 @@ static int adreno_bind(struct device *dev, struct device *master, void *data)

	/* 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;
				}
				config.fast_rate = max(config.fast_rate, val);
				config.slow_rate = min(config.slow_rate, val);
			}
		}
	}

	if (!config.fast_rate) {
		dev_warn(dev, "could not find clk rates\n");
		/* This is a safe low speed for all devices: */
		config.fast_rate = 200000000;
		config.slow_rate = 27000000;
	}
	ret = adreno_get_pwrlevels(dev, &config);
	if (ret)
		return ret;

	dev->platform_data = &config;
	set_gpu_pdev(dev_get_drvdata(master), to_platform_device(dev));
@@ -296,12 +333,35 @@ static const struct of_device_id dt_match[] = {
	{}
};

#ifdef CONFIG_PM
static int adreno_resume(struct device *dev)
{
	struct platform_device *pdev = to_platform_device(dev);
	struct msm_gpu *gpu = platform_get_drvdata(pdev);

	return gpu->funcs->pm_resume(gpu);
}

static int adreno_suspend(struct device *dev)
{
	struct platform_device *pdev = to_platform_device(dev);
	struct msm_gpu *gpu = platform_get_drvdata(pdev);

	return gpu->funcs->pm_suspend(gpu);
}
#endif

static const struct dev_pm_ops adreno_pm_ops = {
	SET_RUNTIME_PM_OPS(adreno_suspend, adreno_resume, NULL)
};

static struct platform_driver adreno_driver = {
	.probe = adreno_probe,
	.remove = adreno_remove,
	.driver = {
		.name = "adreno",
		.of_match_table = dt_match,
		.pm = &adreno_pm_ops,
	},
};

Loading