linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 1/9] drm/msm/mdp4: only use lut_clk on mdp4.2+
@ 2018-11-14 22:24 Jonathan Marek
  2018-11-14 22:24 ` [PATCH 2/9] drm/msm/mdp4: allocate blank_cursor_no with MSM_BO_SCANOUT flag Jonathan Marek
                   ` (7 more replies)
  0 siblings, 8 replies; 13+ messages in thread
From: Jonathan Marek @ 2018-11-14 22:24 UTC (permalink / raw)
  To: freedreno
  Cc: Rob Clark, David Airlie, Sean Paul, Steve Kowalik, Rajesh Yadav,
	open list:DRM DRIVER FOR MSM ADRENO GPU,
	open list:DRM DRIVER FOR MSM ADRENO GPU, open list

Signed-off-by: Jonathan Marek <jonathan@marek.ca>
---
 drivers/gpu/drm/msm/disp/mdp4/mdp4_kms.c | 22 +++++++++++++---------
 1 file changed, 13 insertions(+), 9 deletions(-)

diff --git a/drivers/gpu/drm/msm/disp/mdp4/mdp4_kms.c b/drivers/gpu/drm/msm/disp/mdp4/mdp4_kms.c
index ae25d763cd8c..8f765f284d11 100644
--- a/drivers/gpu/drm/msm/disp/mdp4/mdp4_kms.c
+++ b/drivers/gpu/drm/msm/disp/mdp4/mdp4_kms.c
@@ -206,7 +206,8 @@ int mdp4_disable(struct mdp4_kms *mdp4_kms)
 	clk_disable_unprepare(mdp4_kms->clk);
 	if (mdp4_kms->pclk)
 		clk_disable_unprepare(mdp4_kms->pclk);
-	clk_disable_unprepare(mdp4_kms->lut_clk);
+	if (mdp4_kms->lut_clk)
+		clk_disable_unprepare(mdp4_kms->lut_clk);
 	if (mdp4_kms->axi_clk)
 		clk_disable_unprepare(mdp4_kms->axi_clk);
 
@@ -220,7 +221,8 @@ int mdp4_enable(struct mdp4_kms *mdp4_kms)
 	clk_prepare_enable(mdp4_kms->clk);
 	if (mdp4_kms->pclk)
 		clk_prepare_enable(mdp4_kms->pclk);
-	clk_prepare_enable(mdp4_kms->lut_clk);
+	if (mdp4_kms->lut_clk)
+		clk_prepare_enable(mdp4_kms->lut_clk);
 	if (mdp4_kms->axi_clk)
 		clk_prepare_enable(mdp4_kms->axi_clk);
 
@@ -472,12 +474,13 @@ struct msm_kms *mdp4_kms_init(struct drm_device *dev)
 	if (IS_ERR(mdp4_kms->pclk))
 		mdp4_kms->pclk = NULL;
 
-	// XXX if (rev >= MDP_REV_42) { ???
-	mdp4_kms->lut_clk = devm_clk_get(&pdev->dev, "lut_clk");
-	if (IS_ERR(mdp4_kms->lut_clk)) {
-		dev_err(dev->dev, "failed to get lut_clk\n");
-		ret = PTR_ERR(mdp4_kms->lut_clk);
-		goto fail;
+	if (mdp4_kms->rev >= 2) {
+		mdp4_kms->lut_clk = devm_clk_get(&pdev->dev, "lut_clk");
+		if (IS_ERR(mdp4_kms->lut_clk)) {
+			dev_err(dev->dev, "failed to get lut_clk\n");
+			ret = PTR_ERR(mdp4_kms->lut_clk);
+			goto fail;
+		}
 	}
 
 	mdp4_kms->axi_clk = devm_clk_get(&pdev->dev, "bus_clk");
@@ -488,7 +491,8 @@ struct msm_kms *mdp4_kms_init(struct drm_device *dev)
 	}
 
 	clk_set_rate(mdp4_kms->clk, config->max_clk);
-	clk_set_rate(mdp4_kms->lut_clk, config->max_clk);
+	if (mdp4_kms->lut_clk)
+		clk_set_rate(mdp4_kms->lut_clk, config->max_clk);
 
 	pm_runtime_enable(dev->dev);
 	mdp4_kms->rpm_enabled = true;
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH 2/9] drm/msm/mdp4: allocate blank_cursor_no with MSM_BO_SCANOUT flag
  2018-11-14 22:24 [PATCH 1/9] drm/msm/mdp4: only use lut_clk on mdp4.2+ Jonathan Marek
@ 2018-11-14 22:24 ` Jonathan Marek
  2018-11-14 22:24 ` [PATCH 3/9] drm/msm/mdp4: add lcdc-align-lsb flag to control lane alignment Jonathan Marek
                   ` (6 subsequent siblings)
  7 siblings, 0 replies; 13+ messages in thread
From: Jonathan Marek @ 2018-11-14 22:24 UTC (permalink / raw)
  To: freedreno
  Cc: Rob Clark, David Airlie, Sean Paul, Steve Kowalik, Rajesh Yadav,
	open list:DRM DRIVER FOR MSM ADRENO GPU,
	open list:DRM DRIVER FOR MSM ADRENO GPU, open list

For allocation in contiguous memory when the GPU has MMU but not mdp4.

Signed-off-by: Jonathan Marek <jonathan@marek.ca>
---
 drivers/gpu/drm/msm/disp/mdp4/mdp4_kms.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/msm/disp/mdp4/mdp4_kms.c b/drivers/gpu/drm/msm/disp/mdp4/mdp4_kms.c
index 8f765f284d11..484d2fc2f415 100644
--- a/drivers/gpu/drm/msm/disp/mdp4/mdp4_kms.c
+++ b/drivers/gpu/drm/msm/disp/mdp4/mdp4_kms.c
@@ -534,7 +534,7 @@ struct msm_kms *mdp4_kms_init(struct drm_device *dev)
 		goto fail;
 	}
 
-	mdp4_kms->blank_cursor_bo = msm_gem_new(dev, SZ_16K, MSM_BO_WC);
+	mdp4_kms->blank_cursor_bo = msm_gem_new(dev, SZ_16K, MSM_BO_WC | MSM_BO_SCANOUT);
 	if (IS_ERR(mdp4_kms->blank_cursor_bo)) {
 		ret = PTR_ERR(mdp4_kms->blank_cursor_bo);
 		dev_err(dev->dev, "could not allocate blank-cursor bo: %d\n", ret);
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH 3/9] drm/msm/mdp4: add lcdc-align-lsb flag to control lane alignment
  2018-11-14 22:24 [PATCH 1/9] drm/msm/mdp4: only use lut_clk on mdp4.2+ Jonathan Marek
  2018-11-14 22:24 ` [PATCH 2/9] drm/msm/mdp4: allocate blank_cursor_no with MSM_BO_SCANOUT flag Jonathan Marek
@ 2018-11-14 22:24 ` Jonathan Marek
  2018-11-14 22:24 ` [PATCH 4/9] drm/msm: use contiguous vram for MSM_BO_SCANOUT when possible Jonathan Marek
                   ` (5 subsequent siblings)
  7 siblings, 0 replies; 13+ messages in thread
From: Jonathan Marek @ 2018-11-14 22:24 UTC (permalink / raw)
  To: freedreno
  Cc: Rob Clark, David Airlie, Sean Paul, Boris Brezillon,
	Thierry Reding, open list:DRM DRIVER FOR MSM ADRENO GPU,
	open list:DRM DRIVER FOR MSM ADRENO GPU, open list

Controls which of the 8 lanes are used for 6 bit color.

Signed-off-by: Jonathan Marek <jonathan@marek.ca>
---
 .../gpu/drm/msm/disp/mdp4/mdp4_lcdc_encoder.c | 22 ++++++++++++-------
 1 file changed, 14 insertions(+), 8 deletions(-)

diff --git a/drivers/gpu/drm/msm/disp/mdp4/mdp4_lcdc_encoder.c b/drivers/gpu/drm/msm/disp/mdp4/mdp4_lcdc_encoder.c
index e19ab2ab63f7..7d8d11c8150a 100644
--- a/drivers/gpu/drm/msm/disp/mdp4/mdp4_lcdc_encoder.c
+++ b/drivers/gpu/drm/msm/disp/mdp4/mdp4_lcdc_encoder.c
@@ -377,20 +377,26 @@ static void mdp4_lcdc_encoder_enable(struct drm_encoder *encoder)
 	unsigned long pc = mdp4_lcdc_encoder->pixclock;
 	struct mdp4_kms *mdp4_kms = get_kms(encoder);
 	struct drm_panel *panel;
+	uint32_t config;
 	int i, ret;
 
 	if (WARN_ON(mdp4_lcdc_encoder->enabled))
 		return;
 
 	/* TODO: hard-coded for 18bpp: */
-	mdp4_crtc_set_config(encoder->crtc,
-			MDP4_DMA_CONFIG_R_BPC(BPC6) |
-			MDP4_DMA_CONFIG_G_BPC(BPC6) |
-			MDP4_DMA_CONFIG_B_BPC(BPC6) |
-			MDP4_DMA_CONFIG_PACK_ALIGN_MSB |
-			MDP4_DMA_CONFIG_PACK(0x21) |
-			MDP4_DMA_CONFIG_DEFLKR_EN |
-			MDP4_DMA_CONFIG_DITHER_EN);
+	config =
+		MDP4_DMA_CONFIG_R_BPC(BPC6) |
+		MDP4_DMA_CONFIG_G_BPC(BPC6) |
+		MDP4_DMA_CONFIG_B_BPC(BPC6) |
+		MDP4_DMA_CONFIG_PACK(0x21) |
+		MDP4_DMA_CONFIG_DEFLKR_EN |
+		MDP4_DMA_CONFIG_DITHER_EN;
+
+	if (!of_find_property(dev->dev->of_node, "lcdc-align-lsb", NULL))
+		config |= MDP4_DMA_CONFIG_PACK_ALIGN_MSB;
+
+
+	mdp4_crtc_set_config(encoder->crtc, config);
 	mdp4_crtc_set_intf(encoder->crtc, INTF_LCDC_DTV, 0);
 
 	bs_set(mdp4_lcdc_encoder, 1);
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH 4/9] drm/msm: use contiguous vram for MSM_BO_SCANOUT when possible
  2018-11-14 22:24 [PATCH 1/9] drm/msm/mdp4: only use lut_clk on mdp4.2+ Jonathan Marek
  2018-11-14 22:24 ` [PATCH 2/9] drm/msm/mdp4: allocate blank_cursor_no with MSM_BO_SCANOUT flag Jonathan Marek
  2018-11-14 22:24 ` [PATCH 3/9] drm/msm/mdp4: add lcdc-align-lsb flag to control lane alignment Jonathan Marek
@ 2018-11-14 22:24 ` Jonathan Marek
  2018-11-14 22:24 ` [PATCH 5/9] drm/msm: add headless gpu device (for imx5) Jonathan Marek
                   ` (4 subsequent siblings)
  7 siblings, 0 replies; 13+ messages in thread
From: Jonathan Marek @ 2018-11-14 22:24 UTC (permalink / raw)
  To: freedreno
  Cc: Rob Clark, David Airlie, open list:DRM DRIVER FOR MSM ADRENO GPU,
	open list:DRM DRIVER FOR MSM ADRENO GPU, open list

Makes it possible to have MMU for GPU but not display.

Signed-off-by: Jonathan Marek <jonathan@marek.ca>
---
 drivers/gpu/drm/msm/msm_gem.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/msm/msm_gem.c b/drivers/gpu/drm/msm/msm_gem.c
index d97f6ecb0531..6657453a3a58 100644
--- a/drivers/gpu/drm/msm/msm_gem.c
+++ b/drivers/gpu/drm/msm/msm_gem.c
@@ -914,7 +914,7 @@ static struct drm_gem_object *_msm_gem_new(struct drm_device *dev,
 
 	if (!iommu_present(&platform_bus_type))
 		use_vram = true;
-	else if ((flags & MSM_BO_STOLEN) && priv->vram.size)
+	else if ((flags & (MSM_BO_STOLEN | MSM_BO_SCANOUT)) && priv->vram.size)
 		use_vram = true;
 
 	printk("_msm_gem_new %u bytes use_vram=%u\n", size, use_vram);
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH 5/9] drm/msm: add headless gpu device (for imx5)
  2018-11-14 22:24 [PATCH 1/9] drm/msm/mdp4: only use lut_clk on mdp4.2+ Jonathan Marek
                   ` (2 preceding siblings ...)
  2018-11-14 22:24 ` [PATCH 4/9] drm/msm: use contiguous vram for MSM_BO_SCANOUT when possible Jonathan Marek
@ 2018-11-14 22:24 ` Jonathan Marek
  2018-11-14 22:47   ` Jordan Crouse
  2018-11-14 22:24 ` [PATCH 6/9] drm/msm/adreno: add a2xx Jonathan Marek
                   ` (3 subsequent siblings)
  7 siblings, 1 reply; 13+ messages in thread
From: Jonathan Marek @ 2018-11-14 22:24 UTC (permalink / raw)
  To: freedreno
  Cc: Rob Clark, David Airlie, Bjorn Andersson, Niklas Cassel,
	Andy Gross, Jordan Crouse, Govind Singh,
	open list:DRM DRIVER FOR MSM ADRENO GPU,
	open list:DRM DRIVER FOR MSM ADRENO GPU, open list

Signed-off-by: Jonathan Marek <jonathan@marek.ca>
---
 drivers/gpu/drm/msm/Kconfig       |  4 ++--
 drivers/gpu/drm/msm/msm_debugfs.c |  2 +-
 drivers/gpu/drm/msm/msm_drv.c     | 15 +++++++++++----
 include/linux/qcom_scm.h          |  3 +++
 4 files changed, 17 insertions(+), 7 deletions(-)

diff --git a/drivers/gpu/drm/msm/Kconfig b/drivers/gpu/drm/msm/Kconfig
index 843a9d40c05e..cf549f1ed403 100644
--- a/drivers/gpu/drm/msm/Kconfig
+++ b/drivers/gpu/drm/msm/Kconfig
@@ -2,7 +2,7 @@
 config DRM_MSM
 	tristate "MSM DRM"
 	depends on DRM
-	depends on ARCH_QCOM || (ARM && COMPILE_TEST)
+	depends on ARCH_QCOM || SOC_IMX5 || (ARM && COMPILE_TEST)
 	depends on OF && COMMON_CLK
 	depends on MMU
 	select QCOM_MDT_LOADER if ARCH_QCOM
@@ -11,7 +11,7 @@ config DRM_MSM
 	select DRM_PANEL
 	select SHMEM
 	select TMPFS
-	select QCOM_SCM
+	select QCOM_SCM if ARCH_QCOM
 	select WANT_DEV_COREDUMP
 	select SND_SOC_HDMI_CODEC if SND_SOC
 	select SYNC_FILE
diff --git a/drivers/gpu/drm/msm/msm_debugfs.c b/drivers/gpu/drm/msm/msm_debugfs.c
index f0da0d3c8a80..1ca99ca356a4 100644
--- a/drivers/gpu/drm/msm/msm_debugfs.c
+++ b/drivers/gpu/drm/msm/msm_debugfs.c
@@ -235,7 +235,7 @@ int msm_debugfs_init(struct drm_minor *minor)
 	debugfs_create_file("gpu", S_IRUSR, minor->debugfs_root,
 		dev, &msm_gpu_fops);
 
-	if (priv->kms->funcs->debugfs_init) {
+	if (priv->kms && priv->kms->funcs->debugfs_init) {
 		ret = priv->kms->funcs->debugfs_init(priv->kms, minor);
 		if (ret)
 			return ret;
diff --git a/drivers/gpu/drm/msm/msm_drv.c b/drivers/gpu/drm/msm/msm_drv.c
index 9f219e02f3c7..a10cc0298d38 100644
--- a/drivers/gpu/drm/msm/msm_drv.c
+++ b/drivers/gpu/drm/msm/msm_drv.c
@@ -344,6 +344,7 @@ static int msm_drm_uninit(struct device *dev)
 	return 0;
 }
 
+#define KMS_HEADLESS 1
 #define KMS_MDP4 4
 #define KMS_MDP5 5
 #define KMS_DPU  3
@@ -495,6 +496,9 @@ static int msm_drm_init(struct device *dev, struct drm_driver *drv)
 	msm_gem_shrinker_init(ddev);
 
 	switch (get_mdp_ver(pdev)) {
+	case KMS_HEADLESS:
+		priv->kms = kms = NULL;
+		break;
 	case KMS_MDP4:
 		kms = mdp4_kms_init(ddev);
 		priv->kms = kms;
@@ -633,7 +637,7 @@ static int msm_drm_init(struct device *dev, struct drm_driver *drv)
 	drm_mode_config_reset(ddev);
 
 #ifdef CONFIG_DRM_FBDEV_EMULATION
-	if (fbdev)
+	if (kms && fbdev)
 		priv->fbdev = msm_fbdev_init(ddev);
 #endif
 
@@ -1315,9 +1319,11 @@ static int msm_pdev_probe(struct platform_device *pdev)
 	struct component_match *match = NULL;
 	int ret;
 
-	ret = add_display_components(&pdev->dev, &match);
-	if (ret)
-		return ret;
+	if (get_mdp_ver(pdev) != KMS_HEADLESS) {
+		ret = add_display_components(&pdev->dev, &match);
+		if (ret)
+			return ret;
+	}
 
 	ret = add_gpu_components(&pdev->dev, &match);
 	if (ret)
@@ -1342,6 +1348,7 @@ static int msm_pdev_remove(struct platform_device *pdev)
 }
 
 static const struct of_device_id dt_match[] = {
+	{ .compatible = "qcom,adreno-headless", .data = (void *)KMS_HEADLESS },
 	{ .compatible = "qcom,mdp4", .data = (void *)KMS_MDP4 },
 	{ .compatible = "qcom,mdss", .data = (void *)KMS_MDP5 },
 	{ .compatible = "qcom,sdm845-mdss", .data = (void *)KMS_DPU },
diff --git a/include/linux/qcom_scm.h b/include/linux/qcom_scm.h
index 06996ad4f2bc..1637385bcc17 100644
--- a/include/linux/qcom_scm.h
+++ b/include/linux/qcom_scm.h
@@ -67,6 +67,9 @@ extern int qcom_scm_iommu_secure_ptbl_init(u64 addr, u32 size, u32 spare);
 extern int qcom_scm_io_readl(phys_addr_t addr, unsigned int *val);
 extern int qcom_scm_io_writel(phys_addr_t addr, unsigned int val);
 #else
+
+#include <linux/errno.h>
+
 static inline
 int qcom_scm_set_cold_boot_addr(void *entry, const cpumask_t *cpus)
 {
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH 6/9] drm/msm/adreno: add a2xx
  2018-11-14 22:24 [PATCH 1/9] drm/msm/mdp4: only use lut_clk on mdp4.2+ Jonathan Marek
                   ` (3 preceding siblings ...)
  2018-11-14 22:24 ` [PATCH 5/9] drm/msm: add headless gpu device (for imx5) Jonathan Marek
@ 2018-11-14 22:24 ` Jonathan Marek
  2018-11-14 22:59   ` Jordan Crouse
  2018-11-14 22:24 ` [PATCH 7/9] drm/msm: implement a2xx mmu Jonathan Marek
                   ` (2 subsequent siblings)
  7 siblings, 1 reply; 13+ messages in thread
From: Jonathan Marek @ 2018-11-14 22:24 UTC (permalink / raw)
  To: freedreno
  Cc: Rob Clark, David Airlie, Jordan Crouse, Nicolas Dechesne,
	Arnd Bergmann, Daniel Vetter, Kees Cook, Bjorn Andersson,
	open list, open list:DRM DRIVER FOR MSM ADRENO GPU,
	open list:DRM DRIVER FOR MSM ADRENO GPU

derived from the a3xx driver and tested on the following hardware:
imx51-zii-rdu1 (a200 with 128kb gmem)
imx53-qsrb (a200)
msm8060-tenderloin (a220)

Signed-off-by: Jonathan Marek <jonathan@marek.ca>
---
 drivers/gpu/drm/msm/Makefile               |   1 +
 drivers/gpu/drm/msm/adreno/a2xx_gpu.c      | 445 +++++++++++++++++++++
 drivers/gpu/drm/msm/adreno/a2xx_gpu.h      |  21 +
 drivers/gpu/drm/msm/adreno/adreno_device.c |  33 ++
 drivers/gpu/drm/msm/adreno/adreno_gpu.c    |  27 +-
 drivers/gpu/drm/msm/adreno/adreno_gpu.h    |  15 +
 6 files changed, 534 insertions(+), 8 deletions(-)
 create mode 100644 drivers/gpu/drm/msm/adreno/a2xx_gpu.c
 create mode 100644 drivers/gpu/drm/msm/adreno/a2xx_gpu.h

diff --git a/drivers/gpu/drm/msm/Makefile b/drivers/gpu/drm/msm/Makefile
index 19ab521d4c3a..0170766393ea 100644
--- a/drivers/gpu/drm/msm/Makefile
+++ b/drivers/gpu/drm/msm/Makefile
@@ -6,6 +6,7 @@ ccflags-$(CONFIG_DRM_MSM_DSI) += -Idrivers/gpu/drm/msm/dsi
 msm-y := \
 	adreno/adreno_device.o \
 	adreno/adreno_gpu.o \
+	adreno/a2xx_gpu.o \
 	adreno/a3xx_gpu.o \
 	adreno/a4xx_gpu.o \
 	adreno/a5xx_gpu.o \
diff --git a/drivers/gpu/drm/msm/adreno/a2xx_gpu.c b/drivers/gpu/drm/msm/adreno/a2xx_gpu.c
new file mode 100644
index 000000000000..65b2352408fa
--- /dev/null
+++ b/drivers/gpu/drm/msm/adreno/a2xx_gpu.c
@@ -0,0 +1,445 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright (c) 2018 The Linux Foundation. All rights reserved. */
+
+#include "a2xx_gpu.h"
+
+extern bool hang_debug;
+
+static void a2xx_dump(struct msm_gpu *gpu);
+static bool a2xx_idle(struct msm_gpu *gpu);
+
+static bool a2xx_me_init(struct msm_gpu *gpu)
+{
+	struct msm_ringbuffer *ring = gpu->rb[0];
+
+	OUT_PKT3(ring, CP_ME_INIT, 18);
+
+	/* All fields present (bits 9:0) */
+	OUT_RING(ring, 0x000003ff);
+	/* Disable/Enable Real-Time Stream processing (present but ignored) */
+	OUT_RING(ring, 0x00000000);
+	/* Enable (2D <-> 3D) implicit synchronization (present but ignored) */
+	OUT_RING(ring, 0x00000000);
+
+	OUT_RING(ring, REG_A2XX_RB_SURFACE_INFO - 0x2000);
+	OUT_RING(ring, REG_A2XX_PA_SC_WINDOW_OFFSET - 0x2000);
+	OUT_RING(ring, REG_A2XX_VGT_MAX_VTX_INDX - 0x2000);
+	OUT_RING(ring, REG_A2XX_SQ_PROGRAM_CNTL - 0x2000);
+	OUT_RING(ring, REG_A2XX_RB_DEPTHCONTROL - 0x2000);
+	OUT_RING(ring, REG_A2XX_PA_SU_POINT_SIZE - 0x2000);
+	OUT_RING(ring, REG_A2XX_PA_SC_LINE_CNTL - 0x2000);
+	OUT_RING(ring, REG_A2XX_PA_SU_POLY_OFFSET_FRONT_SCALE - 0x2000);
+
+	/* Vertex and Pixel Shader Start Addresses in instructions
+	 * (3 DWORDS per instruction) */
+	OUT_RING(ring, 0x80000180);
+	/* Maximum Contexts */
+	OUT_RING(ring, 0x00000001);
+	/* Write Confirm Interval and The CP will wait the
+	 * wait_interval * 16 clocks between polling  */
+	OUT_RING(ring, 0x00000000);
+	/* NQ and External Memory Swap */
+	OUT_RING(ring, 0x00000000);
+	/* protected mode error checking (0x1f2 is REG_AXXX_CP_INT_CNTL) */
+	OUT_RING(ring, 0x200001f2);
+	/* Disable header dumping and Header dump address */
+	OUT_RING(ring, 0x00000000);
+	/* Header dump size */
+	OUT_RING(ring, 0x00000000);
+
+	/* enable protected mode */
+	OUT_PKT3(ring, CP_SET_PROTECTED_MODE, 1);
+	OUT_RING(ring, 1);
+
+	gpu->funcs->flush(gpu, ring);
+	return a2xx_idle(gpu);
+}
+
+static int a2xx_hw_init(struct msm_gpu *gpu)
+{
+	struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu);
+	uint32_t *ptr, len;
+	int i, ret;
+
+	DBG("%s", gpu->name);
+
+	gpu_write(gpu, REG_A2XX_RBBM_PM_OVERRIDE1, 0xfffffffe);
+	gpu_write(gpu, REG_A2XX_RBBM_PM_OVERRIDE2, 0xffffffff);
+
+	/* XXX kgsl uses 0x00000001 after first reset on a22x */
+	gpu_write(gpu, REG_A2XX_RBBM_SOFT_RESET, 0xffffffff);
+	msleep(30);
+	gpu_write(gpu, REG_A2XX_RBBM_SOFT_RESET, 0x00000000);
+
+	if (adreno_is_a225(adreno_gpu))
+		gpu_write(gpu, REG_A2XX_SQ_FLOW_CONTROL, 0x18000000);
+
+	/* XXX kgsl uses 0x0000ffff for a20x */
+	gpu_write(gpu, REG_A2XX_RBBM_CNTL, 0x00004442);
+
+	gpu_write(gpu, REG_A2XX_MH_MMU_CONFIG, 0);
+	gpu_write(gpu, REG_A2XX_MH_MMU_MPU_BASE, 0);
+	gpu_write(gpu, REG_A2XX_MH_MMU_MPU_END, 0xfffff000);
+	gpu_write(gpu, REG_A2XX_MH_ARBITER_CONFIG,
+		A2XX_MH_ARBITER_CONFIG_SAME_PAGE_LIMIT(16) |
+		A2XX_MH_ARBITER_CONFIG_L1_ARB_ENABLE |
+		A2XX_MH_ARBITER_CONFIG_L1_ARB_HOLD_ENABLE |
+		A2XX_MH_ARBITER_CONFIG_PAGE_SIZE(1) |
+		A2XX_MH_ARBITER_CONFIG_TC_REORDER_ENABLE |
+		A2XX_MH_ARBITER_CONFIG_TC_ARB_HOLD_ENABLE |
+		A2XX_MH_ARBITER_CONFIG_IN_FLIGHT_LIMIT_ENABLE |
+		A2XX_MH_ARBITER_CONFIG_IN_FLIGHT_LIMIT(8) |
+		A2XX_MH_ARBITER_CONFIG_CP_CLNT_ENABLE |
+		A2XX_MH_ARBITER_CONFIG_VGT_CLNT_ENABLE |
+		A2XX_MH_ARBITER_CONFIG_TC_CLNT_ENABLE |
+		A2XX_MH_ARBITER_CONFIG_RB_CLNT_ENABLE |
+		A2XX_MH_ARBITER_CONFIG_PA_CLNT_ENABLE);
+	if (!adreno_is_a20x(adreno_gpu))
+		gpu_write(gpu, REG_A2XX_MH_CLNT_INTF_CTRL_CONFIG1, 0x00032f07);
+
+	gpu_write(gpu, REG_A2XX_SQ_VS_PROGRAM, 0x00000000);
+	gpu_write(gpu, REG_A2XX_SQ_PS_PROGRAM, 0x00000000);
+
+	gpu_write(gpu, REG_A2XX_RBBM_PM_OVERRIDE1, 0); /* 0x200 for msm8960? */
+	gpu_write(gpu, REG_A2XX_RBBM_PM_OVERRIDE2, 0); /* 0x80/0x1a0 for a22x? */
+
+	/* XXX gsl doesn't set this */
+	gpu_write(gpu, REG_A2XX_RBBM_DEBUG, 0x00080000);
+
+	gpu_write(gpu, REG_A2XX_RBBM_INT_CNTL, 0);
+	gpu_write(gpu, REG_AXXX_CP_INT_CNTL, 0x80000000); /* RB INT */
+	gpu_write(gpu, REG_A2XX_SQ_INT_CNTL, 0);
+
+	for (i = 3; i <= 5; i++)
+		if ((SZ_16K << i) == adreno_gpu->gmem)
+			break;
+	gpu_write(gpu, REG_A2XX_RB_EDRAM_INFO, i);
+
+	ret = adreno_hw_init(gpu);
+	if (ret)
+		return ret;
+
+	/* NOTE: PM4/micro-engine firmware registers look to be the same
+	 * for a2xx and a3xx.. we could possibly push that part down to
+	 * adreno_gpu base class.  Or push both PM4 and PFP but
+	 * parameterize the pfp ucode addr/data registers..
+	 */
+
+	/* Load PM4: */
+	ptr = (uint32_t *)(adreno_gpu->fw[ADRENO_FW_PM4]->data);
+	len = adreno_gpu->fw[ADRENO_FW_PM4]->size / 4;
+	DBG("loading PM4 ucode version: %x", ptr[1]);
+
+	gpu_write(gpu, REG_AXXX_CP_DEBUG, 0x02000000);
+	gpu_write(gpu, REG_AXXX_CP_ME_RAM_WADDR, 0);
+	for (i = 1; i < len; i++)
+		gpu_write(gpu, REG_AXXX_CP_ME_RAM_DATA, ptr[i]);
+
+	/* Load PFP: */
+	ptr = (uint32_t *)(adreno_gpu->fw[ADRENO_FW_PFP]->data);
+	len = adreno_gpu->fw[ADRENO_FW_PFP]->size / 4;
+	DBG("loading PFP ucode version: %x", ptr[5]);
+
+	gpu_write(gpu, REG_A2XX_CP_PFP_UCODE_ADDR, 0);
+	for (i = 1; i < len; i++)
+		gpu_write(gpu, REG_A2XX_CP_PFP_UCODE_DATA, ptr[i]);
+
+	gpu_write(gpu, REG_AXXX_CP_QUEUE_THRESHOLDS, 0x000C0804);
+
+	/* clear ME_HALT to start micro engine */
+	gpu_write(gpu, REG_AXXX_CP_ME_CNTL, 0);
+
+	return a2xx_me_init(gpu) ? 0 : -EINVAL;
+}
+
+static void a2xx_recover(struct msm_gpu *gpu)
+{
+	int i;
+
+	adreno_dump_info(gpu);
+
+	for (i = 0; i < 8; i++) {
+		printk("CP_SCRATCH_REG%d: %u\n", i,
+			gpu_read(gpu, REG_AXXX_CP_SCRATCH_REG0 + i));
+	}
+
+	/* dump registers before resetting gpu, if enabled: */
+	if (hang_debug)
+		a2xx_dump(gpu);
+
+	gpu_write(gpu, REG_A2XX_RBBM_SOFT_RESET, 1);
+	gpu_read(gpu, REG_A2XX_RBBM_SOFT_RESET);
+	gpu_write(gpu, REG_A2XX_RBBM_SOFT_RESET, 0);
+	adreno_recover(gpu);
+}
+
+static void a2xx_destroy(struct msm_gpu *gpu)
+{
+	struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu);
+	struct a2xx_gpu *a2xx_gpu = to_a2xx_gpu(adreno_gpu);
+
+	DBG("%s", gpu->name);
+
+	adreno_gpu_cleanup(adreno_gpu);
+
+	kfree(a2xx_gpu);
+}
+
+static bool a2xx_idle(struct msm_gpu *gpu)
+{
+	/* wait for ringbuffer to drain: */
+	if (!adreno_idle(gpu, gpu->rb[0]))
+		return false;
+
+	/* then wait for GPU to finish: */
+	if (spin_until(!(gpu_read(gpu, REG_A2XX_RBBM_STATUS) &
+			A2XX_RBBM_STATUS_GUI_ACTIVE))) {
+		DRM_ERROR("%s: timeout waiting for GPU to idle!\n", gpu->name);
+
+		/* TODO maybe we need to reset GPU here to recover from hang? */
+		return false;
+	}
+
+	return true;
+}
+
+static irqreturn_t a2xx_irq(struct msm_gpu *gpu)
+{
+
+	uint32_t mstatus, status;
+
+	mstatus = gpu_read(gpu, REG_A2XX_MASTER_INT_SIGNAL);
+
+	if (mstatus & A2XX_MASTER_INT_SIGNAL_MH_INT_STAT) {
+		status = gpu_read(gpu, REG_A2XX_MH_INTERRUPT_STATUS);
+
+		dev_warn(gpu->dev->dev, "MH_INT: %08X\n", status);
+		dev_warn(gpu->dev->dev, "MMU_PAGE_FAULT: %08X\n",
+			gpu_read(gpu, REG_A2XX_MH_MMU_PAGE_FAULT));
+		gpu_write(gpu, REG_A2XX_MH_INTERRUPT_CLEAR, status);
+	}
+
+	if (mstatus & A2XX_MASTER_INT_SIGNAL_CP_INT_STAT) {
+		status = gpu_read(gpu, REG_AXXX_CP_INT_STATUS);
+
+		/* only RB_INT is expected */
+		if (status & ~AXXX_CP_INT_CNTL_RB_INT_MASK)
+			dev_warn(gpu->dev->dev, "CP_INT: %08X\n", status);
+
+		gpu_write(gpu, REG_AXXX_CP_INT_ACK, status);
+	}
+
+	if (mstatus & A2XX_MASTER_INT_SIGNAL_RBBM_INT_STAT) {
+		status = gpu_read(gpu, REG_A2XX_RBBM_INT_STATUS);
+
+		dev_warn(gpu->dev->dev, "RBBM_INT: %08X\n", status);
+
+		gpu_write(gpu, REG_A2XX_RBBM_INT_ACK, status);
+	}
+
+	msm_gpu_retire(gpu);
+
+	return IRQ_HANDLED;
+}
+
+static const unsigned int a200_registers[] = {
+	0x0000, 0x0002, 0x0004, 0x000B, 0x003B, 0x003D, 0x0040, 0x0044,
+	0x0046, 0x0047, 0x01C0, 0x01C1, 0x01C3, 0x01C8, 0x01D5, 0x01D9,
+	0x01DC, 0x01DD, 0x01EA, 0x01EA, 0x01EE, 0x01F3, 0x01F6, 0x01F7,
+	0x01FC, 0x01FF, 0x0391, 0x0392, 0x039B, 0x039E, 0x03B2, 0x03B5,
+	0x03B7, 0x03B7, 0x03F8, 0x03FB, 0x0440, 0x0440, 0x0443, 0x0444,
+	0x044B, 0x044B, 0x044D, 0x044F, 0x0452, 0x0452, 0x0454, 0x045B,
+	0x047F, 0x047F, 0x0578, 0x0587, 0x05C9, 0x05C9, 0x05D0, 0x05D0,
+	0x0601, 0x0604, 0x0606, 0x0609, 0x060B, 0x060E, 0x0613, 0x0614,
+	0x0A29, 0x0A2B, 0x0A2F, 0x0A31, 0x0A40, 0x0A43, 0x0A45, 0x0A45,
+	0x0A4E, 0x0A4F, 0x0C2C, 0x0C2C, 0x0C30, 0x0C30, 0x0C38, 0x0C3C,
+	0x0C40, 0x0C40, 0x0C44, 0x0C44, 0x0C80, 0x0C86, 0x0C88, 0x0C94,
+	0x0C99, 0x0C9A, 0x0CA4, 0x0CA5, 0x0D00, 0x0D03, 0x0D06, 0x0D06,
+	0x0D08, 0x0D0B, 0x0D34, 0x0D35, 0x0DAE, 0x0DC1, 0x0DC8, 0x0DD4,
+	0x0DD8, 0x0DD9, 0x0E00, 0x0E00, 0x0E02, 0x0E04, 0x0E17, 0x0E1E,
+	0x0EC0, 0x0EC9, 0x0ECB, 0x0ECC, 0x0ED0, 0x0ED0, 0x0ED4, 0x0ED7,
+	0x0EE0, 0x0EE2, 0x0F01, 0x0F02, 0x0F0C, 0x0F0C, 0x0F0E, 0x0F12,
+	0x0F26, 0x0F2A, 0x0F2C, 0x0F2C, 0x2000, 0x2002, 0x2006, 0x200F,
+	0x2080, 0x2082, 0x2100, 0x2109, 0x210C, 0x2114, 0x2180, 0x2184,
+	0x21F5, 0x21F7, 0x2200, 0x2208, 0x2280, 0x2283, 0x2293, 0x2294,
+	0x2300, 0x2308, 0x2312, 0x2312, 0x2316, 0x231D, 0x2324, 0x2326,
+	0x2380, 0x2383, 0x2400, 0x2402, 0x2406, 0x240F, 0x2480, 0x2482,
+	0x2500, 0x2509, 0x250C, 0x2514, 0x2580, 0x2584, 0x25F5, 0x25F7,
+	0x2600, 0x2608, 0x2680, 0x2683, 0x2693, 0x2694, 0x2700, 0x2708,
+	0x2712, 0x2712, 0x2716, 0x271D, 0x2724, 0x2726, 0x2780, 0x2783,
+	0x4000, 0x4003, 0x4800, 0x4805, 0x4900, 0x4900, 0x4908, 0x4908,
+	~0   /* sentinel */
+};
+
+static const unsigned int a220_registers[] = {
+	0x0000, 0x0002, 0x0004, 0x000B, 0x003B, 0x003D, 0x0040, 0x0044,
+	0x0046, 0x0047, 0x01C0, 0x01C1, 0x01C3, 0x01C8, 0x01D5, 0x01D9,
+	0x01DC, 0x01DD, 0x01EA, 0x01EA, 0x01EE, 0x01F3, 0x01F6, 0x01F7,
+	0x01FC, 0x01FF, 0x0391, 0x0392, 0x039B, 0x039E, 0x03B2, 0x03B5,
+	0x03B7, 0x03B7, 0x03F8, 0x03FB, 0x0440, 0x0440, 0x0443, 0x0444,
+	0x044B, 0x044B, 0x044D, 0x044F, 0x0452, 0x0452, 0x0454, 0x045B,
+	0x047F, 0x047F, 0x0578, 0x0587, 0x05C9, 0x05C9, 0x05D0, 0x05D0,
+	0x0601, 0x0604, 0x0606, 0x0609, 0x060B, 0x060E, 0x0613, 0x0614,
+	0x0A29, 0x0A2B, 0x0A2F, 0x0A31, 0x0A40, 0x0A40, 0x0A42, 0x0A43,
+	0x0A45, 0x0A45, 0x0A4E, 0x0A4F, 0x0C30, 0x0C30, 0x0C38, 0x0C39,
+	0x0C3C, 0x0C3C, 0x0C80, 0x0C81, 0x0C88, 0x0C93, 0x0D00, 0x0D03,
+	0x0D05, 0x0D06, 0x0D08, 0x0D0B, 0x0D34, 0x0D35, 0x0DAE, 0x0DC1,
+	0x0DC8, 0x0DD4, 0x0DD8, 0x0DD9, 0x0E00, 0x0E00, 0x0E02, 0x0E04,
+	0x0E17, 0x0E1E, 0x0EC0, 0x0EC9, 0x0ECB, 0x0ECC, 0x0ED0, 0x0ED0,
+	0x0ED4, 0x0ED7, 0x0EE0, 0x0EE2, 0x0F01, 0x0F02, 0x2000, 0x2002,
+	0x2006, 0x200F, 0x2080, 0x2082, 0x2100, 0x2102, 0x2104, 0x2109,
+	0x210C, 0x2114, 0x2180, 0x2184, 0x21F5, 0x21F7, 0x2200, 0x2202,
+	0x2204, 0x2204, 0x2208, 0x2208, 0x2280, 0x2282, 0x2294, 0x2294,
+	0x2300, 0x2308, 0x2309, 0x230A, 0x2312, 0x2312, 0x2316, 0x2316,
+	0x2318, 0x231D, 0x2324, 0x2326, 0x2380, 0x2383, 0x2400, 0x2402,
+	0x2406, 0x240F, 0x2480, 0x2482, 0x2500, 0x2502, 0x2504, 0x2509,
+	0x250C, 0x2514, 0x2580, 0x2584, 0x25F5, 0x25F7, 0x2600, 0x2602,
+	0x2604, 0x2606, 0x2608, 0x2608, 0x2680, 0x2682, 0x2694, 0x2694,
+	0x2700, 0x2708, 0x2712, 0x2712, 0x2716, 0x2716, 0x2718, 0x271D,
+	0x2724, 0x2726, 0x2780, 0x2783, 0x4000, 0x4003, 0x4800, 0x4805,
+	0x4900, 0x4900, 0x4908, 0x4908,
+	~0   /* sentinel */
+};
+
+static const unsigned int a225_registers[] = {
+	0x0000, 0x0002, 0x0004, 0x000B, 0x003B, 0x003D, 0x0040, 0x0044,
+	0x0046, 0x0047, 0x013C, 0x013C, 0x0140, 0x014F, 0x01C0, 0x01C1,
+	0x01C3, 0x01C8, 0x01D5, 0x01D9, 0x01DC, 0x01DD, 0x01EA, 0x01EA,
+	0x01EE, 0x01F3, 0x01F6, 0x01F7, 0x01FC, 0x01FF, 0x0391, 0x0392,
+	0x039B, 0x039E, 0x03B2, 0x03B5, 0x03B7, 0x03B7, 0x03F8, 0x03FB,
+	0x0440, 0x0440, 0x0443, 0x0444, 0x044B, 0x044B, 0x044D, 0x044F,
+	0x0452, 0x0452, 0x0454, 0x045B, 0x047F, 0x047F, 0x0578, 0x0587,
+	0x05C9, 0x05C9, 0x05D0, 0x05D0, 0x0601, 0x0604, 0x0606, 0x0609,
+	0x060B, 0x060E, 0x0613, 0x0614, 0x0A29, 0x0A2B, 0x0A2F, 0x0A31,
+	0x0A40, 0x0A40, 0x0A42, 0x0A43, 0x0A45, 0x0A45, 0x0A4E, 0x0A4F,
+	0x0C01, 0x0C1D, 0x0C30, 0x0C30, 0x0C38, 0x0C39, 0x0C3C, 0x0C3C,
+	0x0C80, 0x0C81, 0x0C88, 0x0C93, 0x0D00, 0x0D03, 0x0D05, 0x0D06,
+	0x0D08, 0x0D0B, 0x0D34, 0x0D35, 0x0DAE, 0x0DC1, 0x0DC8, 0x0DD4,
+	0x0DD8, 0x0DD9, 0x0E00, 0x0E00, 0x0E02, 0x0E04, 0x0E17, 0x0E1E,
+	0x0EC0, 0x0EC9, 0x0ECB, 0x0ECC, 0x0ED0, 0x0ED0, 0x0ED4, 0x0ED7,
+	0x0EE0, 0x0EE2, 0x0F01, 0x0F02, 0x2000, 0x200F, 0x2080, 0x2082,
+	0x2100, 0x2109, 0x210C, 0x2114, 0x2180, 0x2184, 0x21F5, 0x21F7,
+	0x2200, 0x2202, 0x2204, 0x2206, 0x2208, 0x2210, 0x2220, 0x2222,
+	0x2280, 0x2282, 0x2294, 0x2294, 0x2297, 0x2297, 0x2300, 0x230A,
+	0x2312, 0x2312, 0x2315, 0x2316, 0x2318, 0x231D, 0x2324, 0x2326,
+	0x2340, 0x2357, 0x2360, 0x2360, 0x2380, 0x2383, 0x2400, 0x240F,
+	0x2480, 0x2482, 0x2500, 0x2509, 0x250C, 0x2514, 0x2580, 0x2584,
+	0x25F5, 0x25F7, 0x2600, 0x2602, 0x2604, 0x2606, 0x2608, 0x2610,
+	0x2620, 0x2622, 0x2680, 0x2682, 0x2694, 0x2694, 0x2697, 0x2697,
+	0x2700, 0x270A, 0x2712, 0x2712, 0x2715, 0x2716, 0x2718, 0x271D,
+	0x2724, 0x2726, 0x2740, 0x2757, 0x2760, 0x2760, 0x2780, 0x2783,
+	0x4000, 0x4003, 0x4800, 0x4806, 0x4808, 0x4808, 0x4900, 0x4900,
+	0x4908, 0x4908,
+	~0   /* sentinel */
+};
+
+/* would be nice to not have to duplicate the _show() stuff with printk(): */
+static void a2xx_dump(struct msm_gpu *gpu)
+{
+	printk("status:   %08x\n",
+			gpu_read(gpu, REG_A2XX_RBBM_STATUS));
+	adreno_dump(gpu);
+}
+
+static struct msm_gpu_state *a2xx_gpu_state_get(struct msm_gpu *gpu)
+{
+	struct msm_gpu_state *state = kzalloc(sizeof(*state), GFP_KERNEL);
+
+	if (!state)
+		return ERR_PTR(-ENOMEM);
+
+	adreno_gpu_state_get(gpu, state);
+
+	state->rbbm_status = gpu_read(gpu, REG_A2XX_RBBM_STATUS);
+
+	return state;
+}
+
+/* Register offset defines for A2XX - copy of A3XX */
+static const unsigned int a2xx_register_offsets[REG_ADRENO_REGISTER_MAX] = {
+	REG_ADRENO_DEFINE(REG_ADRENO_CP_RB_BASE, REG_AXXX_CP_RB_BASE),
+	REG_ADRENO_SKIP(REG_ADRENO_CP_RB_BASE_HI),
+	REG_ADRENO_DEFINE(REG_ADRENO_CP_RB_RPTR_ADDR, REG_AXXX_CP_RB_RPTR_ADDR),
+	REG_ADRENO_SKIP(REG_ADRENO_CP_RB_RPTR_ADDR_HI),
+	REG_ADRENO_DEFINE(REG_ADRENO_CP_RB_RPTR, REG_AXXX_CP_RB_RPTR),
+	REG_ADRENO_DEFINE(REG_ADRENO_CP_RB_WPTR, REG_AXXX_CP_RB_WPTR),
+	REG_ADRENO_DEFINE(REG_ADRENO_CP_RB_CNTL, REG_AXXX_CP_RB_CNTL),
+};
+
+static const struct adreno_gpu_funcs funcs = {
+	.base = {
+		.get_param = adreno_get_param,
+		.hw_init = a2xx_hw_init,
+		.pm_suspend = msm_gpu_pm_suspend,
+		.pm_resume = msm_gpu_pm_resume,
+		.recover = a2xx_recover,
+		.submit = adreno_submit,
+		.flush = adreno_flush,
+		.active_ring = adreno_active_ring,
+		.irq = a2xx_irq,
+		.destroy = a2xx_destroy,
+#if defined(CONFIG_DEBUG_FS) || defined(CONFIG_DEV_COREDUMP)
+		.show = adreno_show,
+#endif
+		.gpu_state_get = a2xx_gpu_state_get,
+		.gpu_state_put = adreno_gpu_state_put,
+	},
+};
+
+static const struct msm_gpu_perfcntr perfcntrs[] = {
+/* TODO */
+};
+
+struct msm_gpu *a2xx_gpu_init(struct drm_device *dev)
+{
+	struct a2xx_gpu *a2xx_gpu = NULL;
+	struct adreno_gpu *adreno_gpu;
+	struct msm_gpu *gpu;
+	struct msm_drm_private *priv = dev->dev_private;
+	struct platform_device *pdev = priv->gpu_pdev;
+	int ret;
+
+	if (!pdev) {
+		dev_err(dev->dev, "no a2xx device\n");
+		ret = -ENXIO;
+		goto fail;
+	}
+
+	a2xx_gpu = kzalloc(sizeof(*a2xx_gpu), GFP_KERNEL);
+	if (!a2xx_gpu) {
+		ret = -ENOMEM;
+		goto fail;
+	}
+
+	adreno_gpu = &a2xx_gpu->base;
+	gpu = &adreno_gpu->base;
+
+	gpu->perfcntrs = perfcntrs;
+	gpu->num_perfcntrs = ARRAY_SIZE(perfcntrs);
+
+	if (adreno_is_a20x(adreno_gpu))
+		adreno_gpu->registers = a200_registers;
+	else if (adreno_is_a225(adreno_gpu))
+		adreno_gpu->registers = a225_registers;
+	else
+		adreno_gpu->registers = a220_registers;
+
+	adreno_gpu->reg_offsets = a2xx_register_offsets;
+
+	ret = adreno_gpu_init(dev, pdev, adreno_gpu, &funcs, 1);
+	if (ret)
+		goto fail;
+
+	if (!gpu->aspace) {
+		/* MMU is not implemented...  */
+		dev_err(dev->dev, "No memory protection without MMU\n");
+	}
+
+	return gpu;
+
+fail:
+	if (a2xx_gpu)
+		a2xx_destroy(&a2xx_gpu->base.base);
+
+	return ERR_PTR(ret);
+}
diff --git a/drivers/gpu/drm/msm/adreno/a2xx_gpu.h b/drivers/gpu/drm/msm/adreno/a2xx_gpu.h
new file mode 100644
index 000000000000..02fba2cb8932
--- /dev/null
+++ b/drivers/gpu/drm/msm/adreno/a2xx_gpu.h
@@ -0,0 +1,21 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright (c) 2018 The Linux Foundation. All rights reserved. */
+
+#ifndef __A2XX_GPU_H__
+#define __A2XX_GPU_H__
+
+#include "adreno_gpu.h"
+
+/* arrg, somehow fb.h is getting pulled in: */
+#undef ROP_COPY
+#undef ROP_XOR
+
+#include "a2xx.xml.h"
+
+struct a2xx_gpu {
+	struct adreno_gpu base;
+	bool pm_enabled;
+};
+#define to_a2xx_gpu(x) container_of(x, struct a2xx_gpu, base)
+
+#endif /* __A2XX_GPU_H__ */
diff --git a/drivers/gpu/drm/msm/adreno/adreno_device.c b/drivers/gpu/drm/msm/adreno/adreno_device.c
index 86abdb2b3a9c..6e3f78d4da5d 100644
--- a/drivers/gpu/drm/msm/adreno/adreno_device.c
+++ b/drivers/gpu/drm/msm/adreno/adreno_device.c
@@ -27,6 +27,39 @@ module_param_named(hang_debug, hang_debug, bool, 0600);
 
 static const struct adreno_info gpulist[] = {
 	{
+		.rev   = ADRENO_REV(2, 0, 0, 0),
+		.revn  = 200,
+		.name  = "A200",
+		.fw = {
+			[ADRENO_FW_PM4] = "yamato_pm4.fw",
+			[ADRENO_FW_PFP] = "yamato_pfp.fw",
+		},
+		.gmem  = SZ_256K,
+		.inactive_period = DRM_MSM_INACTIVE_PERIOD,
+		.init  = a2xx_gpu_init,
+	}, { /* a200 on i.mx51 has only 128kib gmem */
+		.rev   = ADRENO_REV(2, 0, 0, 1),
+		.revn  = 201,
+		.name  = "A200",
+		.fw = {
+			[ADRENO_FW_PM4] = "yamato_pm4.fw",
+			[ADRENO_FW_PFP] = "yamato_pfp.fw",
+		},
+		.gmem  = SZ_128K,
+		.inactive_period = DRM_MSM_INACTIVE_PERIOD,
+		.init  = a2xx_gpu_init,
+	}, {
+		.rev   = ADRENO_REV(2, 2, 0, ANY_ID),
+		.revn  = 220,
+		.name  = "A220",
+		.fw = {
+			[ADRENO_FW_PM4] = "leia_pm4_470.fw",
+			[ADRENO_FW_PFP] = "leia_pfp_470.fw",
+		},
+		.gmem  = SZ_512K,
+		.inactive_period = DRM_MSM_INACTIVE_PERIOD,
+		.init  = a2xx_gpu_init,
+	}, {
 		.rev   = ADRENO_REV(3, 0, 5, ANY_ID),
 		.revn  = 305,
 		.name  = "A305",
diff --git a/drivers/gpu/drm/msm/adreno/adreno_gpu.c b/drivers/gpu/drm/msm/adreno/adreno_gpu.c
index 93d70f4a2154..e09671324b05 100644
--- a/drivers/gpu/drm/msm/adreno/adreno_gpu.c
+++ b/drivers/gpu/drm/msm/adreno/adreno_gpu.c
@@ -319,16 +319,27 @@ void adreno_submit(struct msm_gpu *gpu, struct msm_gem_submit *submit,
 		 */
 		OUT_PKT3(ring, CP_EVENT_WRITE, 1);
 		OUT_RING(ring, HLSQ_FLUSH);
-
-		OUT_PKT3(ring, CP_WAIT_FOR_IDLE, 1);
-		OUT_RING(ring, 0x00000000);
 	}
 
-	/* BIT(31) of CACHE_FLUSH_TS triggers CACHE_FLUSH_TS IRQ from GPU */
-	OUT_PKT3(ring, CP_EVENT_WRITE, 3);
-	OUT_RING(ring, CACHE_FLUSH_TS | BIT(31));
-	OUT_RING(ring, rbmemptr(ring, fence));
-	OUT_RING(ring, submit->seqno);
+	/* wait for idle before cache flush/interrupt */
+	OUT_PKT3(ring, CP_WAIT_FOR_IDLE, 1);
+	OUT_RING(ring, 0x00000000);
+
+	if (!adreno_is_a2xx(adreno_gpu)) {
+		/* BIT(31) of CACHE_FLUSH_TS triggers CACHE_FLUSH_TS IRQ from GPU */
+		OUT_PKT3(ring, CP_EVENT_WRITE, 3);
+		OUT_RING(ring, CACHE_FLUSH_TS | BIT(31));
+		OUT_RING(ring, rbmemptr(ring, fence));
+		OUT_RING(ring, submit->seqno);
+	} else {
+		/* BIT(31) means something else on a2xx */
+		OUT_PKT3(ring, CP_EVENT_WRITE, 3);
+		OUT_RING(ring, CACHE_FLUSH_TS);
+		OUT_RING(ring, rbmemptr(ring, fence));
+		OUT_RING(ring, submit->seqno);
+		OUT_PKT3(ring, CP_INTERRUPT, 1);
+		OUT_RING(ring, 0x80000000);
+	}
 
 #if 0
 	if (adreno_is_a3xx(adreno_gpu)) {
diff --git a/drivers/gpu/drm/msm/adreno/adreno_gpu.h b/drivers/gpu/drm/msm/adreno/adreno_gpu.h
index de6e6ee42fba..4adc97a91e1d 100644
--- a/drivers/gpu/drm/msm/adreno/adreno_gpu.h
+++ b/drivers/gpu/drm/msm/adreno/adreno_gpu.h
@@ -154,6 +154,20 @@ struct adreno_platform_config {
 	__ret;                                             \
 })
 
+static inline bool adreno_is_a2xx(struct adreno_gpu *gpu)
+{
+	return (gpu->revn < 300);
+}
+
+static inline bool adreno_is_a20x(struct adreno_gpu *gpu)
+{
+	return (gpu->revn < 210);
+}
+
+static inline bool adreno_is_a225(struct adreno_gpu *gpu)
+{
+	return gpu->revn == 225;
+}
 
 static inline bool adreno_is_a3xx(struct adreno_gpu *gpu)
 {
@@ -334,6 +348,7 @@ static inline void adreno_gpu_write(struct adreno_gpu *gpu,
 		gpu_write(&gpu->base, reg - 1, data);
 }
 
+struct msm_gpu *a2xx_gpu_init(struct drm_device *dev);
 struct msm_gpu *a3xx_gpu_init(struct drm_device *dev);
 struct msm_gpu *a4xx_gpu_init(struct drm_device *dev);
 struct msm_gpu *a5xx_gpu_init(struct drm_device *dev);
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH 7/9] drm/msm: implement a2xx mmu
  2018-11-14 22:24 [PATCH 1/9] drm/msm/mdp4: only use lut_clk on mdp4.2+ Jonathan Marek
                   ` (4 preceding siblings ...)
  2018-11-14 22:24 ` [PATCH 6/9] drm/msm/adreno: add a2xx Jonathan Marek
@ 2018-11-14 22:24 ` Jonathan Marek
  2018-11-20 16:29   ` Rob Clark
  2018-11-14 22:24 ` [PATCH 8/9] drm/msm/mdp5: add config for msm8917 Jonathan Marek
  2018-11-14 22:24 ` [PATCH 9/9] drm/msm: set priv->kms to NULL before uninit Jonathan Marek
  7 siblings, 1 reply; 13+ messages in thread
From: Jonathan Marek @ 2018-11-14 22:24 UTC (permalink / raw)
  To: freedreno
  Cc: Rob Clark, David Airlie, Jordan Crouse, Nicolas Dechesne,
	Archit Taneja, Arnd Bergmann, Kees Cook, Bjorn Andersson,
	open list, open list:DRM DRIVER FOR MSM ADRENO GPU,
	open list:DRM DRIVER FOR MSM ADRENO GPU

A2XX has its own very simple MMU.

Added a msm_use_mmu() function because we can't rely on iommu_present to
decide to use MMU or not.

Signed-off-by: Jonathan Marek <jonathan@marek.ca>
---
 drivers/gpu/drm/msm/Makefile               |   3 +-
 drivers/gpu/drm/msm/adreno/a2xx_gpu.c      |  57 +++++++++--
 drivers/gpu/drm/msm/adreno/adreno_device.c |   3 +
 drivers/gpu/drm/msm/adreno/adreno_gpu.c    |  15 +++
 drivers/gpu/drm/msm/msm_drv.c              |  11 +-
 drivers/gpu/drm/msm/msm_drv.h              |   8 ++
 drivers/gpu/drm/msm/msm_gem.c              |   4 +-
 drivers/gpu/drm/msm/msm_gem_vma.c          |  23 +++++
 drivers/gpu/drm/msm/msm_gpu.c              |  26 +++--
 drivers/gpu/drm/msm/msm_gpummu.c           | 113 +++++++++++++++++++++
 drivers/gpu/drm/msm/msm_mmu.h              |   3 +
 11 files changed, 243 insertions(+), 23 deletions(-)
 create mode 100644 drivers/gpu/drm/msm/msm_gpummu.c

diff --git a/drivers/gpu/drm/msm/Makefile b/drivers/gpu/drm/msm/Makefile
index 0170766393ea..004574bc9bd3 100644
--- a/drivers/gpu/drm/msm/Makefile
+++ b/drivers/gpu/drm/msm/Makefile
@@ -91,7 +91,8 @@ msm-y := \
 	msm_perf.o \
 	msm_rd.o \
 	msm_ringbuffer.o \
-	msm_submitqueue.o
+	msm_submitqueue.o \
+	msm_gpummu.o
 
 msm-$(CONFIG_DEBUG_FS) += adreno/a5xx_debugfs.o \
 			  disp/dpu1/dpu_dbg.o
diff --git a/drivers/gpu/drm/msm/adreno/a2xx_gpu.c b/drivers/gpu/drm/msm/adreno/a2xx_gpu.c
index 65b2352408fa..dd669f046389 100644
--- a/drivers/gpu/drm/msm/adreno/a2xx_gpu.c
+++ b/drivers/gpu/drm/msm/adreno/a2xx_gpu.c
@@ -2,6 +2,8 @@
 /* Copyright (c) 2018 The Linux Foundation. All rights reserved. */
 
 #include "a2xx_gpu.h"
+#include "msm_gem.h"
+#include "msm_mmu.h"
 
 extern bool hang_debug;
 
@@ -58,9 +60,12 @@ static bool a2xx_me_init(struct msm_gpu *gpu)
 static int a2xx_hw_init(struct msm_gpu *gpu)
 {
 	struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu);
+	dma_addr_t pt_base, tran_error;
 	uint32_t *ptr, len;
 	int i, ret;
 
+	msm_gpummu_params(gpu->aspace->mmu, &pt_base, &tran_error);
+
 	DBG("%s", gpu->name);
 
 	gpu_write(gpu, REG_A2XX_RBBM_PM_OVERRIDE1, 0xfffffffe);
@@ -77,9 +82,34 @@ static int a2xx_hw_init(struct msm_gpu *gpu)
 	/* XXX kgsl uses 0x0000ffff for a20x */
 	gpu_write(gpu, REG_A2XX_RBBM_CNTL, 0x00004442);
 
-	gpu_write(gpu, REG_A2XX_MH_MMU_CONFIG, 0);
-	gpu_write(gpu, REG_A2XX_MH_MMU_MPU_BASE, 0);
+	/* MPU: physical range */
+	gpu_write(gpu, REG_A2XX_MH_MMU_MPU_BASE, 0x00000000);
 	gpu_write(gpu, REG_A2XX_MH_MMU_MPU_END, 0xfffff000);
+
+	gpu_write(gpu, REG_A2XX_MH_MMU_CONFIG, A2XX_MH_MMU_CONFIG_MMU_ENABLE |
+		A2XX_MH_MMU_CONFIG_RB_W_CLNT_BEHAVIOR(BEH_TRAN_RNG) |
+		A2XX_MH_MMU_CONFIG_CP_W_CLNT_BEHAVIOR(BEH_TRAN_RNG) |
+		A2XX_MH_MMU_CONFIG_CP_R0_CLNT_BEHAVIOR(BEH_TRAN_RNG) |
+		A2XX_MH_MMU_CONFIG_CP_R1_CLNT_BEHAVIOR(BEH_TRAN_RNG) |
+		A2XX_MH_MMU_CONFIG_CP_R2_CLNT_BEHAVIOR(BEH_TRAN_RNG) |
+		A2XX_MH_MMU_CONFIG_CP_R3_CLNT_BEHAVIOR(BEH_TRAN_RNG) |
+		A2XX_MH_MMU_CONFIG_CP_R4_CLNT_BEHAVIOR(BEH_TRAN_RNG) |
+		A2XX_MH_MMU_CONFIG_VGT_R0_CLNT_BEHAVIOR(BEH_TRAN_RNG) |
+		A2XX_MH_MMU_CONFIG_VGT_R1_CLNT_BEHAVIOR(BEH_TRAN_RNG) |
+		A2XX_MH_MMU_CONFIG_TC_R_CLNT_BEHAVIOR(BEH_TRAN_RNG) |
+		A2XX_MH_MMU_CONFIG_PA_W_CLNT_BEHAVIOR(BEH_TRAN_RNG));
+
+	/* same as parameters in adreno_gpu */
+	gpu_write(gpu, REG_A2XX_MH_MMU_VA_RANGE, SZ_16M |
+		A2XX_MH_MMU_VA_RANGE_NUM_64KB_REGIONS(0xfff));
+
+	gpu_write(gpu, REG_A2XX_MH_MMU_PT_BASE, pt_base);
+	gpu_write(gpu, REG_A2XX_MH_MMU_TRAN_ERROR, tran_error);
+
+	gpu_write(gpu, REG_A2XX_MH_MMU_INVALIDATE,
+		A2XX_MH_MMU_INVALIDATE_INVALIDATE_ALL |
+		A2XX_MH_MMU_INVALIDATE_INVALIDATE_TC);
+
 	gpu_write(gpu, REG_A2XX_MH_ARBITER_CONFIG,
 		A2XX_MH_ARBITER_CONFIG_SAME_PAGE_LIMIT(16) |
 		A2XX_MH_ARBITER_CONFIG_L1_ARB_ENABLE |
@@ -106,9 +136,21 @@ static int a2xx_hw_init(struct msm_gpu *gpu)
 	/* XXX gsl doesn't set this */
 	gpu_write(gpu, REG_A2XX_RBBM_DEBUG, 0x00080000);
 
-	gpu_write(gpu, REG_A2XX_RBBM_INT_CNTL, 0);
-	gpu_write(gpu, REG_AXXX_CP_INT_CNTL, 0x80000000); /* RB INT */
+	gpu_write(gpu, REG_A2XX_RBBM_INT_CNTL,
+		A2XX_RBBM_INT_CNTL_RDERR_INT_MASK);
+	gpu_write(gpu, REG_AXXX_CP_INT_CNTL,
+		AXXX_CP_INT_CNTL_T0_PACKET_IN_IB_MASK |
+		AXXX_CP_INT_CNTL_OPCODE_ERROR_MASK |
+		AXXX_CP_INT_CNTL_PROTECTED_MODE_ERROR_MASK |
+		AXXX_CP_INT_CNTL_RESERVED_BIT_ERROR_MASK |
+		AXXX_CP_INT_CNTL_IB_ERROR_MASK |
+		AXXX_CP_INT_CNTL_IB1_INT_MASK |
+		AXXX_CP_INT_CNTL_RB_INT_MASK);
 	gpu_write(gpu, REG_A2XX_SQ_INT_CNTL, 0);
+	gpu_write(gpu, REG_A2XX_MH_INTERRUPT_MASK,
+		A2XX_MH_INTERRUPT_MASK_AXI_READ_ERROR |
+		A2XX_MH_INTERRUPT_MASK_AXI_WRITE_ERROR |
+		A2XX_MH_INTERRUPT_MASK_MMU_PAGE_FAULT);
 
 	for (i = 3; i <= 5; i++)
 		if ((SZ_16K << i) == adreno_gpu->gmem)
@@ -205,7 +247,6 @@ static bool a2xx_idle(struct msm_gpu *gpu)
 
 static irqreturn_t a2xx_irq(struct msm_gpu *gpu)
 {
-
 	uint32_t mstatus, status;
 
 	mstatus = gpu_read(gpu, REG_A2XX_MASTER_INT_SIGNAL);
@@ -216,6 +257,7 @@ static irqreturn_t a2xx_irq(struct msm_gpu *gpu)
 		dev_warn(gpu->dev->dev, "MH_INT: %08X\n", status);
 		dev_warn(gpu->dev->dev, "MMU_PAGE_FAULT: %08X\n",
 			gpu_read(gpu, REG_A2XX_MH_MMU_PAGE_FAULT));
+
 		gpu_write(gpu, REG_A2XX_MH_INTERRUPT_CLEAR, status);
 	}
 
@@ -430,11 +472,6 @@ struct msm_gpu *a2xx_gpu_init(struct drm_device *dev)
 	if (ret)
 		goto fail;
 
-	if (!gpu->aspace) {
-		/* MMU is not implemented...  */
-		dev_err(dev->dev, "No memory protection without MMU\n");
-	}
-
 	return gpu;
 
 fail:
diff --git a/drivers/gpu/drm/msm/adreno/adreno_device.c b/drivers/gpu/drm/msm/adreno/adreno_device.c
index 6e3f78d4da5d..f651cd51449b 100644
--- a/drivers/gpu/drm/msm/adreno/adreno_device.c
+++ b/drivers/gpu/drm/msm/adreno/adreno_device.c
@@ -307,6 +307,7 @@ static int adreno_bind(struct device *dev, struct device *master, void *data)
 	static struct adreno_platform_config config = {};
 	const struct adreno_info *info;
 	struct drm_device *drm = dev_get_drvdata(master);
+	struct msm_drm_private *priv = drm->dev_private;
 	struct msm_gpu *gpu;
 	int ret;
 
@@ -337,6 +338,8 @@ static int adreno_bind(struct device *dev, struct device *master, void *data)
 
 	dev_set_drvdata(dev, gpu);
 
+	priv->is_a2xx = config.rev.core == 2;
+
 	return 0;
 }
 
diff --git a/drivers/gpu/drm/msm/adreno/adreno_gpu.c b/drivers/gpu/drm/msm/adreno/adreno_gpu.c
index e09671324b05..18736637c933 100644
--- a/drivers/gpu/drm/msm/adreno/adreno_gpu.c
+++ b/drivers/gpu/drm/msm/adreno/adreno_gpu.c
@@ -24,6 +24,7 @@
 #include "adreno_gpu.h"
 #include "msm_gem.h"
 #include "msm_mmu.h"
+#include "a2xx_gpu.h"
 
 int adreno_get_param(struct msm_gpu *gpu, uint32_t param, uint64_t *value)
 {
@@ -290,6 +291,17 @@ void adreno_submit(struct msm_gpu *gpu, struct msm_gem_submit *submit,
 	struct msm_ringbuffer *ring = submit->ring;
 	unsigned i;
 
+	if (adreno_is_a2xx(adreno_gpu)) {
+		/* tlb flush for a2xx MMU. TODO: only do this when required */
+		OUT_PKT3(ring, CP_SET_PROTECTED_MODE, 1);
+		OUT_RING(ring, 0);
+		OUT_PKT0(ring, REG_A2XX_MH_MMU_INVALIDATE, 1);
+		OUT_RING(ring, A2XX_MH_MMU_INVALIDATE_INVALIDATE_ALL |
+			A2XX_MH_MMU_INVALIDATE_INVALIDATE_TC);
+		OUT_PKT3(ring, CP_SET_PROTECTED_MODE, 1);
+		OUT_RING(ring, 1);
+	}
+
 	for (i = 0; i < submit->nr_cmds; i++) {
 		switch (submit->cmd[i].type) {
 		case MSM_SUBMIT_CMD_IB_TARGET_BUF:
@@ -728,6 +740,9 @@ int adreno_gpu_init(struct drm_device *drm, struct platform_device *pdev,
 
 	adreno_gpu_config.va_start = SZ_16M;
 	adreno_gpu_config.va_end = 0xffffffff;
+	/* maximum range of a2xx mmu */
+	if (adreno_is_a2xx(adreno_gpu))
+		adreno_gpu_config.va_end = SZ_16M + 0xfff * SZ_64K;
 
 	adreno_gpu_config.nr_rings = nr_rings;
 
diff --git a/drivers/gpu/drm/msm/msm_drv.c b/drivers/gpu/drm/msm/msm_drv.c
index a10cc0298d38..bda23011494d 100644
--- a/drivers/gpu/drm/msm/msm_drv.c
+++ b/drivers/gpu/drm/msm/msm_drv.c
@@ -25,6 +25,7 @@
 #include "msm_fence.h"
 #include "msm_gpu.h"
 #include "msm_kms.h"
+#include "adreno/adreno_gpu.h"
 
 
 /*
@@ -358,6 +359,14 @@ static int get_mdp_ver(struct platform_device *pdev)
 
 #include <linux/of_address.h>
 
+bool msm_use_mmu(struct drm_device *dev)
+{
+	struct msm_drm_private *priv = dev->dev_private;
+
+	/* a2xx comes with its own MMU */
+	return priv->is_a2xx || iommu_present(&platform_bus_type);
+}
+
 static int msm_init_vram(struct drm_device *dev)
 {
 	struct msm_drm_private *priv = dev->dev_private;
@@ -396,7 +405,7 @@ static int msm_init_vram(struct drm_device *dev)
 		 * Grab the entire CMA chunk carved out in early startup in
 		 * mach-msm:
 		 */
-	} else if (!iommu_present(&platform_bus_type)) {
+	} else if (!msm_use_mmu(dev)) {
 		DRM_INFO("using %s VRAM carveout\n", vram);
 		size = memparse(vram, NULL);
 	}
diff --git a/drivers/gpu/drm/msm/msm_drv.h b/drivers/gpu/drm/msm/msm_drv.h
index 9d11f321f5a9..99a37962e92b 100644
--- a/drivers/gpu/drm/msm/msm_drv.h
+++ b/drivers/gpu/drm/msm/msm_drv.h
@@ -179,6 +179,8 @@ struct msm_drm_private {
 	/* when we have more than one 'msm_gpu' these need to be an array: */
 	struct msm_gpu *gpu;
 	struct msm_file_private *lastctx;
+	/* gpu is only set on open(), but we need this info earlier */
+	bool is_a2xx;
 
 	struct drm_fb_helper *fbdev;
 
@@ -252,9 +254,15 @@ struct msm_gem_address_space *
 msm_gem_address_space_create(struct device *dev, struct iommu_domain *domain,
 		const char *name);
 
+struct msm_gem_address_space *
+msm_gem_address_space_create_a2xx(struct device *dev, struct msm_gpu *gpu,
+		const char *name, uint64_t va_start, uint64_t va_end);
+
 int msm_register_mmu(struct drm_device *dev, struct msm_mmu *mmu);
 void msm_unregister_mmu(struct drm_device *dev, struct msm_mmu *mmu);
 
+bool msm_use_mmu(struct drm_device *dev);
+
 void msm_gem_submit_free(struct msm_gem_submit *submit);
 int msm_ioctl_gem_submit(struct drm_device *dev, void *data,
 		struct drm_file *file);
diff --git a/drivers/gpu/drm/msm/msm_gem.c b/drivers/gpu/drm/msm/msm_gem.c
index 6657453a3a58..c1ef8780f686 100644
--- a/drivers/gpu/drm/msm/msm_gem.c
+++ b/drivers/gpu/drm/msm/msm_gem.c
@@ -912,7 +912,7 @@ static struct drm_gem_object *_msm_gem_new(struct drm_device *dev,
 
 	size = PAGE_ALIGN(size);
 
-	if (!iommu_present(&platform_bus_type))
+	if (!msm_use_mmu(dev))
 		use_vram = true;
 	else if ((flags & (MSM_BO_STOLEN | MSM_BO_SCANOUT)) && priv->vram.size)
 		use_vram = true;
@@ -991,7 +991,7 @@ struct drm_gem_object *msm_gem_import(struct drm_device *dev,
 	int ret, npages;
 
 	/* if we don't have IOMMU, don't bother pretending we can import: */
-	if (!iommu_present(&platform_bus_type)) {
+	if (!msm_use_mmu(dev)) {
 		dev_err(dev->dev, "cannot import without IOMMU\n");
 		return ERR_PTR(-EINVAL);
 	}
diff --git a/drivers/gpu/drm/msm/msm_gem_vma.c b/drivers/gpu/drm/msm/msm_gem_vma.c
index ffbec224551b..8075fd699803 100644
--- a/drivers/gpu/drm/msm/msm_gem_vma.c
+++ b/drivers/gpu/drm/msm/msm_gem_vma.c
@@ -114,3 +114,26 @@ msm_gem_address_space_create(struct device *dev, struct iommu_domain *domain,
 
 	return aspace;
 }
+
+struct msm_gem_address_space *
+msm_gem_address_space_create_a2xx(struct device *dev, struct msm_gpu *gpu,
+		const char *name, uint64_t va_start, uint64_t va_end)
+{
+	struct msm_gem_address_space *aspace;
+	u64 size = va_end - va_start;
+
+	aspace = kzalloc(sizeof(*aspace), GFP_KERNEL);
+	if (!aspace)
+		return ERR_PTR(-ENOMEM);
+
+	spin_lock_init(&aspace->lock);
+	aspace->name = name;
+	aspace->mmu = msm_gpummu_new(dev, gpu);
+
+	drm_mm_init(&aspace->mm, (va_start >> PAGE_SHIFT),
+		size >> PAGE_SHIFT);
+
+	kref_init(&aspace->kref);
+
+	return aspace;
+}
diff --git a/drivers/gpu/drm/msm/msm_gpu.c b/drivers/gpu/drm/msm/msm_gpu.c
index 11aac8337066..9af24a1a70a0 100644
--- a/drivers/gpu/drm/msm/msm_gpu.c
+++ b/drivers/gpu/drm/msm/msm_gpu.c
@@ -19,6 +19,7 @@
 #include "msm_gem.h"
 #include "msm_mmu.h"
 #include "msm_fence.h"
+#include "adreno/adreno_gpu.h"
 
 #include <generated/utsrelease.h>
 #include <linux/string_helpers.h>
@@ -800,7 +801,7 @@ static struct msm_gem_address_space *
 msm_gpu_create_address_space(struct msm_gpu *gpu, struct platform_device *pdev,
 		uint64_t va_start, uint64_t va_end)
 {
-	struct iommu_domain *iommu;
+	struct iommu_domain *iommu = NULL;
 	struct msm_gem_address_space *aspace;
 	int ret;
 
@@ -809,20 +810,27 @@ msm_gpu_create_address_space(struct msm_gpu *gpu, struct platform_device *pdev,
 	 * and have separate page tables per context.  For now, to keep things
 	 * simple and to get something working, just use a single address space:
 	 */
-	iommu = iommu_domain_alloc(&platform_bus_type);
-	if (!iommu)
-		return NULL;
+	if (!adreno_is_a2xx(to_adreno_gpu(gpu))) {
+		iommu = iommu_domain_alloc(&platform_bus_type);
+		if (!iommu)
+			return NULL;
 
-	iommu->geometry.aperture_start = va_start;
-	iommu->geometry.aperture_end = va_end;
+		iommu->geometry.aperture_start = va_start;
+		iommu->geometry.aperture_end = va_end;
 
-	dev_info(gpu->dev->dev, "%s: using IOMMU\n", gpu->name);
+		dev_info(gpu->dev->dev, "%s: using IOMMU\n", gpu->name);
+
+		aspace = msm_gem_address_space_create(&pdev->dev, iommu, "gpu");
+	} else {
+		aspace = msm_gem_address_space_create_a2xx(&pdev->dev, gpu, "gpu",
+			va_start, va_end);
+	}
 
-	aspace = msm_gem_address_space_create(&pdev->dev, iommu, "gpu");
 	if (IS_ERR(aspace)) {
 		dev_err(gpu->dev->dev, "failed to init iommu: %ld\n",
 			PTR_ERR(aspace));
-		iommu_domain_free(iommu);
+		if (iommu)
+			iommu_domain_free(iommu);
 		return ERR_CAST(aspace);
 	}
 
diff --git a/drivers/gpu/drm/msm/msm_gpummu.c b/drivers/gpu/drm/msm/msm_gpummu.c
new file mode 100644
index 000000000000..f14cf7759c7f
--- /dev/null
+++ b/drivers/gpu/drm/msm/msm_gpummu.c
@@ -0,0 +1,113 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright (c) 2018 The Linux Foundation. All rights reserved. */
+
+#include "msm_drv.h"
+#include "msm_mmu.h"
+
+struct msm_gpummu {
+	struct msm_mmu base;
+	struct msm_gpu *gpu;
+	dma_addr_t pt_base;
+	uint32_t *table;
+};
+#define to_msm_gpummu(x) container_of(x, struct msm_gpummu, base)
+
+#define VA_START SZ_16M
+#define VA_RANGE (0xfff * SZ_64K)
+#define MMU_PAGE_SIZE SZ_4K
+#define TABLE_SIZE (sizeof(uint32_t) * VA_RANGE / MMU_PAGE_SIZE)
+
+static int msm_gpummu_attach(struct msm_mmu *mmu, const char * const *names,
+		int cnt)
+{
+	return 0;
+}
+
+static void msm_gpummu_detach(struct msm_mmu *mmu, const char * const *names,
+		int cnt)
+{
+}
+
+static void update_pt(struct msm_mmu *mmu, uint64_t iova,
+		struct sg_table *sgt, unsigned len, unsigned prot)
+{
+	struct msm_gpummu *gpummu = to_msm_gpummu(mmu);
+	unsigned idx = (iova - VA_START) / MMU_PAGE_SIZE;
+	struct scatterlist *sg;
+	unsigned i, j;
+
+	for_each_sg(sgt->sgl, sg, sgt->nents, i) {
+		dma_addr_t addr = sg->dma_address;
+		for (j = 0; j < sg->length / MMU_PAGE_SIZE; j++, idx++) {
+			gpummu->table[idx] = prot ? addr | prot : 0;
+			addr += MMU_PAGE_SIZE;
+		}
+	}
+}
+
+static int msm_gpummu_map(struct msm_mmu *mmu, uint64_t iova,
+		struct sg_table *sgt, unsigned len, int prot)
+{
+	unsigned prot_bits = 0;
+	if (prot & IOMMU_WRITE)
+		prot_bits |= 1;
+	if (prot & IOMMU_READ)
+		prot_bits |= 2;
+	update_pt(mmu, iova, sgt, len, prot_bits);
+	return 0;
+}
+
+static int msm_gpummu_unmap(struct msm_mmu *mmu, uint64_t iova,
+		struct sg_table *sgt, unsigned len)
+{
+	update_pt(mmu, iova, sgt, len, 0);
+	return 0;
+}
+
+static void msm_gpummu_destroy(struct msm_mmu *mmu)
+{
+	struct msm_gpummu *gpummu = to_msm_gpummu(mmu);
+
+	dma_free_attrs(mmu->dev, TABLE_SIZE, gpummu->table, gpummu->pt_base,
+		DMA_ATTR_FORCE_CONTIGUOUS);
+
+	kfree(gpummu);
+}
+
+static const struct msm_mmu_funcs funcs = {
+		.attach = msm_gpummu_attach,
+		.detach = msm_gpummu_detach,
+		.map = msm_gpummu_map,
+		.unmap = msm_gpummu_unmap,
+		.destroy = msm_gpummu_destroy,
+};
+
+struct msm_mmu *msm_gpummu_new(struct device *dev, struct msm_gpu *gpu)
+{
+	struct msm_gpummu *gpummu;
+
+	gpummu = kzalloc(sizeof(*gpummu), GFP_KERNEL);
+	if (!gpummu)
+		return ERR_PTR(-ENOMEM);
+
+	gpummu->table = dma_alloc_attrs(dev, TABLE_SIZE + 32, &gpummu->pt_base,
+		GFP_KERNEL | __GFP_ZERO, DMA_ATTR_FORCE_CONTIGUOUS);
+	if (!gpummu->table) {
+		kfree(gpummu);
+		return ERR_PTR(-ENOMEM);
+	}
+
+	gpummu->gpu = gpu;
+	msm_mmu_init(&gpummu->base, dev, &funcs);
+
+	return &gpummu->base;
+}
+
+void msm_gpummu_params(struct msm_mmu *mmu, dma_addr_t *pt_base,
+		dma_addr_t *tran_error)
+{
+	dma_addr_t base = to_msm_gpummu(mmu)->pt_base;
+
+	*pt_base = base;
+	*tran_error = base + TABLE_SIZE; /* 32-byte aligned */
+}
diff --git a/drivers/gpu/drm/msm/msm_mmu.h b/drivers/gpu/drm/msm/msm_mmu.h
index aa2c5d4580c8..c5bbb49dc1be 100644
--- a/drivers/gpu/drm/msm/msm_mmu.h
+++ b/drivers/gpu/drm/msm/msm_mmu.h
@@ -54,4 +54,7 @@ static inline void msm_mmu_set_fault_handler(struct msm_mmu *mmu, void *arg,
 	mmu->handler = handler;
 }
 
+void msm_gpummu_params(struct msm_mmu *mmu, dma_addr_t *pt_base,
+		dma_addr_t *tran_error);
+
 #endif /* __MSM_MMU_H__ */
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH 8/9] drm/msm/mdp5: add config for msm8917
  2018-11-14 22:24 [PATCH 1/9] drm/msm/mdp4: only use lut_clk on mdp4.2+ Jonathan Marek
                   ` (5 preceding siblings ...)
  2018-11-14 22:24 ` [PATCH 7/9] drm/msm: implement a2xx mmu Jonathan Marek
@ 2018-11-14 22:24 ` Jonathan Marek
  2018-11-14 22:24 ` [PATCH 9/9] drm/msm: set priv->kms to NULL before uninit Jonathan Marek
  7 siblings, 0 replies; 13+ messages in thread
From: Jonathan Marek @ 2018-11-14 22:24 UTC (permalink / raw)
  To: freedreno
  Cc: Rob Clark, David Airlie, Sean Paul,
	open list:DRM DRIVER FOR MSM ADRENO GPU,
	open list:DRM DRIVER FOR MSM ADRENO GPU, open list

Add the mdp5_cfg_hw entry for MDP5 version v1.15 found on msm8917.

Signed-off-by: Jonathan Marek <jonathan@marek.ca>
---
 drivers/gpu/drm/msm/disp/mdp5/mdp5_cfg.c | 86 ++++++++++++++++++++++++
 1 file changed, 86 insertions(+)

diff --git a/drivers/gpu/drm/msm/disp/mdp5/mdp5_cfg.c b/drivers/gpu/drm/msm/disp/mdp5/mdp5_cfg.c
index 824067d2d427..05ad159b6261 100644
--- a/drivers/gpu/drm/msm/disp/mdp5/mdp5_cfg.c
+++ b/drivers/gpu/drm/msm/disp/mdp5/mdp5_cfg.c
@@ -553,6 +553,91 @@ const struct mdp5_cfg_hw msm8x96_config = {
 	.max_clk = 412500000,
 };
 
+const struct mdp5_cfg_hw msm8917_config = {
+	.name = "msm8917",
+	.mdp = {
+		.count = 1,
+		.caps = MDP_CAP_CDM,
+	},
+	.ctl = {
+		.count = 3,
+		.base = { 0x01000, 0x01200, 0x01400 },
+		.flush_hw_mask = 0xffffffff,
+	},
+	.pipe_vig = {
+		.count = 1,
+		.base = { 0x04000 },
+		.caps = MDP_PIPE_CAP_HFLIP	|
+			MDP_PIPE_CAP_VFLIP	|
+			MDP_PIPE_CAP_SCALE	|
+			MDP_PIPE_CAP_CSC	|
+			MDP_PIPE_CAP_DECIMATION	|
+			MDP_PIPE_CAP_SW_PIX_EXT	|
+			0,
+	},
+	.pipe_rgb = {
+		.count = 2,
+		.base = { 0x14000, 0x16000 },
+		.caps = MDP_PIPE_CAP_HFLIP	|
+			MDP_PIPE_CAP_VFLIP	|
+			MDP_PIPE_CAP_DECIMATION	|
+			MDP_PIPE_CAP_SW_PIX_EXT	|
+			0,
+	},
+	.pipe_dma = {
+		.count = 1,
+		.base = { 0x24000 },
+		.caps = MDP_PIPE_CAP_HFLIP	|
+			MDP_PIPE_CAP_VFLIP	|
+			MDP_PIPE_CAP_SW_PIX_EXT	|
+			0,
+	},
+	.pipe_cursor = {
+		.count = 1,
+		.base = { 0x34000 },
+		.caps = MDP_PIPE_CAP_HFLIP	|
+			MDP_PIPE_CAP_VFLIP	|
+			MDP_PIPE_CAP_SW_PIX_EXT	|
+			MDP_PIPE_CAP_CURSOR	|
+			0,
+	},
+
+	.lm = {
+		.count = 2,
+		.base = { 0x44000, 0x45000 },
+		.instances = {
+				{ .id = 0, .pp = 0, .dspp = 0,
+				  .caps = MDP_LM_CAP_DISPLAY, },
+				{ .id = 1, .pp = -1, .dspp = -1,
+				  .caps = MDP_LM_CAP_WB },
+			     },
+		.nb_stages = 8,
+		.max_width = 2048,
+		.max_height = 0xFFFF,
+	},
+	.dspp = {
+		.count = 1,
+		.base = { 0x54000 },
+
+	},
+	.pp = {
+		.count = 1,
+		.base = { 0x70000 },
+	},
+	.cdm = {
+		.count = 1,
+		.base = { 0x79200 },
+	},
+	.intf = {
+		.base = { 0x6a000, 0x6a800 },
+		.connect = {
+			[0] = INTF_DISABLED,
+			[1] = INTF_DSI,
+		},
+	},
+	.max_clk = 320000000,
+};
+
 static const struct mdp5_cfg_handler cfg_handlers[] = {
 	{ .revision = 0, .config = { .hw = &msm8x74v1_config } },
 	{ .revision = 2, .config = { .hw = &msm8x74v2_config } },
@@ -560,6 +645,7 @@ static const struct mdp5_cfg_handler cfg_handlers[] = {
 	{ .revision = 6, .config = { .hw = &msm8x16_config } },
 	{ .revision = 9, .config = { .hw = &msm8x94_config } },
 	{ .revision = 7, .config = { .hw = &msm8x96_config } },
+	{ .revision = 15, .config = { .hw = &msm8917_config } },
 };
 
 static struct mdp5_cfg_platform *mdp5_get_config(struct platform_device *dev);
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH 9/9] drm/msm: set priv->kms to NULL before uninit
  2018-11-14 22:24 [PATCH 1/9] drm/msm/mdp4: only use lut_clk on mdp4.2+ Jonathan Marek
                   ` (6 preceding siblings ...)
  2018-11-14 22:24 ` [PATCH 8/9] drm/msm/mdp5: add config for msm8917 Jonathan Marek
@ 2018-11-14 22:24 ` Jonathan Marek
  7 siblings, 0 replies; 13+ messages in thread
From: Jonathan Marek @ 2018-11-14 22:24 UTC (permalink / raw)
  To: freedreno
  Cc: Rob Clark, David Airlie, open list:DRM DRIVER FOR MSM ADRENO GPU,
	open list:DRM DRIVER FOR MSM ADRENO GPU, open list

otherwise, priv->kms is non-NULL and msm_drm_uninit will cause a panic.

Signed-off-by: Jonathan Marek <jonathan@marek.ca>
---
 drivers/gpu/drm/msm/msm_drv.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/drivers/gpu/drm/msm/msm_drv.c b/drivers/gpu/drm/msm/msm_drv.c
index bda23011494d..94b0593f6090 100644
--- a/drivers/gpu/drm/msm/msm_drv.c
+++ b/drivers/gpu/drm/msm/msm_drv.c
@@ -533,6 +533,7 @@ static int msm_drm_init(struct device *dev, struct drm_driver *drv)
 		 */
 		dev_err(dev, "failed to load kms\n");
 		ret = PTR_ERR(kms);
+		priv->kms = NULL;
 		goto err_msm_uninit;
 	}
 
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* Re: [PATCH 5/9] drm/msm: add headless gpu device (for imx5)
  2018-11-14 22:24 ` [PATCH 5/9] drm/msm: add headless gpu device (for imx5) Jonathan Marek
@ 2018-11-14 22:47   ` Jordan Crouse
  2018-11-14 23:08     ` Jonathan marek
  0 siblings, 1 reply; 13+ messages in thread
From: Jordan Crouse @ 2018-11-14 22:47 UTC (permalink / raw)
  To: Jonathan Marek
  Cc: freedreno, Rob Clark, David Airlie, Bjorn Andersson,
	Niklas Cassel, Andy Gross, Govind Singh,
	open list:DRM DRIVER FOR MSM ADRENO GPU,
	open list:DRM DRIVER FOR MSM ADRENO GPU, open list

Thanks for  the patch. Perhaps a small blurb here for the commit log to let
folks know what your intent was.

On Wed, Nov 14, 2018 at 05:24:12PM -0500, Jonathan Marek wrote:
> Signed-off-by: Jonathan Marek <jonathan@marek.ca>
> ---
>  drivers/gpu/drm/msm/Kconfig       |  4 ++--
>  drivers/gpu/drm/msm/msm_debugfs.c |  2 +-
>  drivers/gpu/drm/msm/msm_drv.c     | 15 +++++++++++----
>  include/linux/qcom_scm.h          |  3 +++
>  4 files changed, 17 insertions(+), 7 deletions(-)
> 
> diff --git a/drivers/gpu/drm/msm/Kconfig b/drivers/gpu/drm/msm/Kconfig
> index 843a9d40c05e..cf549f1ed403 100644
> --- a/drivers/gpu/drm/msm/Kconfig
> +++ b/drivers/gpu/drm/msm/Kconfig
> @@ -2,7 +2,7 @@
>  config DRM_MSM
>  	tristate "MSM DRM"
>  	depends on DRM
> -	depends on ARCH_QCOM || (ARM && COMPILE_TEST)
> +	depends on ARCH_QCOM || SOC_IMX5 || (ARM && COMPILE_TEST)
>  	depends on OF && COMMON_CLK
>  	depends on MMU
>  	select QCOM_MDT_LOADER if ARCH_QCOM
> @@ -11,7 +11,7 @@ config DRM_MSM
>  	select DRM_PANEL
>  	select SHMEM
>  	select TMPFS
> -	select QCOM_SCM
> +	select QCOM_SCM if ARCH_QCOM
>  	select WANT_DEV_COREDUMP
>  	select SND_SOC_HDMI_CODEC if SND_SOC
>  	select SYNC_FILE
> diff --git a/drivers/gpu/drm/msm/msm_debugfs.c b/drivers/gpu/drm/msm/msm_debugfs.c
> index f0da0d3c8a80..1ca99ca356a4 100644
> --- a/drivers/gpu/drm/msm/msm_debugfs.c
> +++ b/drivers/gpu/drm/msm/msm_debugfs.c
> @@ -235,7 +235,7 @@ int msm_debugfs_init(struct drm_minor *minor)
>  	debugfs_create_file("gpu", S_IRUSR, minor->debugfs_root,
>  		dev, &msm_gpu_fops);
>  
> -	if (priv->kms->funcs->debugfs_init) {
> +	if (priv->kms && priv->kms->funcs->debugfs_init) {
>  		ret = priv->kms->funcs->debugfs_init(priv->kms, minor);
>  		if (ret)
>  			return ret;
> diff --git a/drivers/gpu/drm/msm/msm_drv.c b/drivers/gpu/drm/msm/msm_drv.c
> index 9f219e02f3c7..a10cc0298d38 100644
> --- a/drivers/gpu/drm/msm/msm_drv.c
> +++ b/drivers/gpu/drm/msm/msm_drv.c
> @@ -344,6 +344,7 @@ static int msm_drm_uninit(struct device *dev)
>  	return 0;
>  }
>  
> +#define KMS_HEADLESS 1
>  #define KMS_MDP4 4
>  #define KMS_MDP5 5
>  #define KMS_DPU  3
> @@ -495,6 +496,9 @@ static int msm_drm_init(struct device *dev, struct drm_driver *drv)
>  	msm_gem_shrinker_init(ddev);
>  
>  	switch (get_mdp_ver(pdev)) {
> +	case KMS_HEADLESS:
> +		priv->kms = kms = NULL;

I don't think you need to set priv->kms, it should come in as NULL. I would
normally say that you should set kms to NULL when it is declared, but I kind of
like pointing it out to the user.

> +		break;
>  	case KMS_MDP4:
>  		kms = mdp4_kms_init(ddev);
>  		priv->kms = kms;
> @@ -633,7 +637,7 @@ static int msm_drm_init(struct device *dev, struct drm_driver *drv)
>  	drm_mode_config_reset(ddev);
>  
>  #ifdef CONFIG_DRM_FBDEV_EMULATION
> -	if (fbdev)
> +	if (kms && fbdev)
>  		priv->fbdev = msm_fbdev_init(ddev);
>  #endif
>  
> @@ -1315,9 +1319,11 @@ static int msm_pdev_probe(struct platform_device *pdev)
>  	struct component_match *match = NULL;
>  	int ret;
>  
> -	ret = add_display_components(&pdev->dev, &match);
> -	if (ret)
> -		return ret;
> +	if (get_mdp_ver(pdev) != KMS_HEADLESS) {
> +		ret = add_display_components(&pdev->dev, &match);
> +		if (ret)
> +			return ret;
> +	}
>  
>  	ret = add_gpu_components(&pdev->dev, &match);
>  	if (ret)
> @@ -1342,6 +1348,7 @@ static int msm_pdev_remove(struct platform_device *pdev)
>  }
>  
>  static const struct of_device_id dt_match[] = {
> +	{ .compatible = "qcom,adreno-headless", .data = (void *)KMS_HEADLESS },
>  	{ .compatible = "qcom,mdp4", .data = (void *)KMS_MDP4 },
>  	{ .compatible = "qcom,mdss", .data = (void *)KMS_MDP5 },
>  	{ .compatible = "qcom,sdm845-mdss", .data = (void *)KMS_DPU },
> diff --git a/include/linux/qcom_scm.h b/include/linux/qcom_scm.h
> index 06996ad4f2bc..1637385bcc17 100644
> --- a/include/linux/qcom_scm.h
> +++ b/include/linux/qcom_scm.h
> @@ -67,6 +67,9 @@ extern int qcom_scm_iommu_secure_ptbl_init(u64 addr, u32 size, u32 spare);
>  extern int qcom_scm_io_readl(phys_addr_t addr, unsigned int *val);
>  extern int qcom_scm_io_writel(phys_addr_t addr, unsigned int val);
>  #else
> +
> +#include <linux/errno.h>
> +

This looks like a separate patch, albeit a useful one.

>  static inline
>  int qcom_scm_set_cold_boot_addr(void *entry, const cpumask_t *cpus)
>  {

Jordan

-- 
The Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
a Linux Foundation Collaborative Project

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH 6/9] drm/msm/adreno: add a2xx
  2018-11-14 22:24 ` [PATCH 6/9] drm/msm/adreno: add a2xx Jonathan Marek
@ 2018-11-14 22:59   ` Jordan Crouse
  0 siblings, 0 replies; 13+ messages in thread
From: Jordan Crouse @ 2018-11-14 22:59 UTC (permalink / raw)
  To: Jonathan Marek
  Cc: freedreno, Rob Clark, David Airlie, Nicolas Dechesne,
	Arnd Bergmann, Daniel Vetter, Kees Cook, Bjorn Andersson,
	open list, open list:DRM DRIVER FOR MSM ADRENO GPU,
	open list:DRM DRIVER FOR MSM ADRENO GPU

On Wed, Nov 14, 2018 at 05:24:13PM -0500, Jonathan Marek wrote:
> derived from the a3xx driver and tested on the following hardware:
> imx51-zii-rdu1 (a200 with 128kb gmem)
> imx53-qsrb (a200)
> msm8060-tenderloin (a220)

This looks sane but it has been quite a while since I've thought about 2xx.

If this works on real world hardware thats is a pretty good endorsement.

Only nit - I would turn the /* XXX */ comments into real comments. Since KGSL
dropped 2xx support some time in the 3.4 timeframe I think it is a good idea
to record what the old code did for posterity.

With that:
Reviewed-by: Jordan Crouse <jcrouse@codeaurora.org>


> Signed-off-by: Jonathan Marek <jonathan@marek.ca>
> ---
>  drivers/gpu/drm/msm/Makefile               |   1 +
>  drivers/gpu/drm/msm/adreno/a2xx_gpu.c      | 445 +++++++++++++++++++++
>  drivers/gpu/drm/msm/adreno/a2xx_gpu.h      |  21 +
>  drivers/gpu/drm/msm/adreno/adreno_device.c |  33 ++
>  drivers/gpu/drm/msm/adreno/adreno_gpu.c    |  27 +-
>  drivers/gpu/drm/msm/adreno/adreno_gpu.h    |  15 +
>  6 files changed, 534 insertions(+), 8 deletions(-)
>  create mode 100644 drivers/gpu/drm/msm/adreno/a2xx_gpu.c
>  create mode 100644 drivers/gpu/drm/msm/adreno/a2xx_gpu.h
> 
> diff --git a/drivers/gpu/drm/msm/Makefile b/drivers/gpu/drm/msm/Makefile
> index 19ab521d4c3a..0170766393ea 100644
> --- a/drivers/gpu/drm/msm/Makefile
> +++ b/drivers/gpu/drm/msm/Makefile
> @@ -6,6 +6,7 @@ ccflags-$(CONFIG_DRM_MSM_DSI) += -Idrivers/gpu/drm/msm/dsi
>  msm-y := \
>  	adreno/adreno_device.o \
>  	adreno/adreno_gpu.o \
> +	adreno/a2xx_gpu.o \
>  	adreno/a3xx_gpu.o \
>  	adreno/a4xx_gpu.o \
>  	adreno/a5xx_gpu.o \
> diff --git a/drivers/gpu/drm/msm/adreno/a2xx_gpu.c b/drivers/gpu/drm/msm/adreno/a2xx_gpu.c
> new file mode 100644
> index 000000000000..65b2352408fa
> --- /dev/null
> +++ b/drivers/gpu/drm/msm/adreno/a2xx_gpu.c
> @@ -0,0 +1,445 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/* Copyright (c) 2018 The Linux Foundation. All rights reserved. */
> +
> +#include "a2xx_gpu.h"
> +
> +extern bool hang_debug;
> +
> +static void a2xx_dump(struct msm_gpu *gpu);
> +static bool a2xx_idle(struct msm_gpu *gpu);
> +
> +static bool a2xx_me_init(struct msm_gpu *gpu)
> +{
> +	struct msm_ringbuffer *ring = gpu->rb[0];
> +
> +	OUT_PKT3(ring, CP_ME_INIT, 18);
> +
> +	/* All fields present (bits 9:0) */
> +	OUT_RING(ring, 0x000003ff);
> +	/* Disable/Enable Real-Time Stream processing (present but ignored) */
> +	OUT_RING(ring, 0x00000000);
> +	/* Enable (2D <-> 3D) implicit synchronization (present but ignored) */
> +	OUT_RING(ring, 0x00000000);
> +
> +	OUT_RING(ring, REG_A2XX_RB_SURFACE_INFO - 0x2000);
> +	OUT_RING(ring, REG_A2XX_PA_SC_WINDOW_OFFSET - 0x2000);
> +	OUT_RING(ring, REG_A2XX_VGT_MAX_VTX_INDX - 0x2000);
> +	OUT_RING(ring, REG_A2XX_SQ_PROGRAM_CNTL - 0x2000);
> +	OUT_RING(ring, REG_A2XX_RB_DEPTHCONTROL - 0x2000);
> +	OUT_RING(ring, REG_A2XX_PA_SU_POINT_SIZE - 0x2000);
> +	OUT_RING(ring, REG_A2XX_PA_SC_LINE_CNTL - 0x2000);
> +	OUT_RING(ring, REG_A2XX_PA_SU_POLY_OFFSET_FRONT_SCALE - 0x2000);
> +
> +	/* Vertex and Pixel Shader Start Addresses in instructions
> +	 * (3 DWORDS per instruction) */
> +	OUT_RING(ring, 0x80000180);
> +	/* Maximum Contexts */
> +	OUT_RING(ring, 0x00000001);
> +	/* Write Confirm Interval and The CP will wait the
> +	 * wait_interval * 16 clocks between polling  */
> +	OUT_RING(ring, 0x00000000);
> +	/* NQ and External Memory Swap */
> +	OUT_RING(ring, 0x00000000);
> +	/* protected mode error checking (0x1f2 is REG_AXXX_CP_INT_CNTL) */
> +	OUT_RING(ring, 0x200001f2);
> +	/* Disable header dumping and Header dump address */
> +	OUT_RING(ring, 0x00000000);
> +	/* Header dump size */
> +	OUT_RING(ring, 0x00000000);
> +
> +	/* enable protected mode */
> +	OUT_PKT3(ring, CP_SET_PROTECTED_MODE, 1);
> +	OUT_RING(ring, 1);
> +
> +	gpu->funcs->flush(gpu, ring);
> +	return a2xx_idle(gpu);
> +}
> +
> +static int a2xx_hw_init(struct msm_gpu *gpu)
> +{
> +	struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu);
> +	uint32_t *ptr, len;
> +	int i, ret;
> +
> +	DBG("%s", gpu->name);
> +
> +	gpu_write(gpu, REG_A2XX_RBBM_PM_OVERRIDE1, 0xfffffffe);
> +	gpu_write(gpu, REG_A2XX_RBBM_PM_OVERRIDE2, 0xffffffff);
> +
> +	/* XXX kgsl uses 0x00000001 after first reset on a22x */
> +	gpu_write(gpu, REG_A2XX_RBBM_SOFT_RESET, 0xffffffff);
> +	msleep(30);
> +	gpu_write(gpu, REG_A2XX_RBBM_SOFT_RESET, 0x00000000);
> +
> +	if (adreno_is_a225(adreno_gpu))
> +		gpu_write(gpu, REG_A2XX_SQ_FLOW_CONTROL, 0x18000000);
> +
> +	/* XXX kgsl uses 0x0000ffff for a20x */
> +	gpu_write(gpu, REG_A2XX_RBBM_CNTL, 0x00004442);
> +
> +	gpu_write(gpu, REG_A2XX_MH_MMU_CONFIG, 0);
> +	gpu_write(gpu, REG_A2XX_MH_MMU_MPU_BASE, 0);
> +	gpu_write(gpu, REG_A2XX_MH_MMU_MPU_END, 0xfffff000);
> +	gpu_write(gpu, REG_A2XX_MH_ARBITER_CONFIG,
> +		A2XX_MH_ARBITER_CONFIG_SAME_PAGE_LIMIT(16) |
> +		A2XX_MH_ARBITER_CONFIG_L1_ARB_ENABLE |
> +		A2XX_MH_ARBITER_CONFIG_L1_ARB_HOLD_ENABLE |
> +		A2XX_MH_ARBITER_CONFIG_PAGE_SIZE(1) |
> +		A2XX_MH_ARBITER_CONFIG_TC_REORDER_ENABLE |
> +		A2XX_MH_ARBITER_CONFIG_TC_ARB_HOLD_ENABLE |
> +		A2XX_MH_ARBITER_CONFIG_IN_FLIGHT_LIMIT_ENABLE |
> +		A2XX_MH_ARBITER_CONFIG_IN_FLIGHT_LIMIT(8) |
> +		A2XX_MH_ARBITER_CONFIG_CP_CLNT_ENABLE |
> +		A2XX_MH_ARBITER_CONFIG_VGT_CLNT_ENABLE |
> +		A2XX_MH_ARBITER_CONFIG_TC_CLNT_ENABLE |
> +		A2XX_MH_ARBITER_CONFIG_RB_CLNT_ENABLE |
> +		A2XX_MH_ARBITER_CONFIG_PA_CLNT_ENABLE);
> +	if (!adreno_is_a20x(adreno_gpu))
> +		gpu_write(gpu, REG_A2XX_MH_CLNT_INTF_CTRL_CONFIG1, 0x00032f07);
> +
> +	gpu_write(gpu, REG_A2XX_SQ_VS_PROGRAM, 0x00000000);
> +	gpu_write(gpu, REG_A2XX_SQ_PS_PROGRAM, 0x00000000);
> +
> +	gpu_write(gpu, REG_A2XX_RBBM_PM_OVERRIDE1, 0); /* 0x200 for msm8960? */
> +	gpu_write(gpu, REG_A2XX_RBBM_PM_OVERRIDE2, 0); /* 0x80/0x1a0 for a22x? */
> +
> +	/* XXX gsl doesn't set this */
> +	gpu_write(gpu, REG_A2XX_RBBM_DEBUG, 0x00080000);
> +
> +	gpu_write(gpu, REG_A2XX_RBBM_INT_CNTL, 0);
> +	gpu_write(gpu, REG_AXXX_CP_INT_CNTL, 0x80000000); /* RB INT */
> +	gpu_write(gpu, REG_A2XX_SQ_INT_CNTL, 0);
> +
> +	for (i = 3; i <= 5; i++)
> +		if ((SZ_16K << i) == adreno_gpu->gmem)
> +			break;
> +	gpu_write(gpu, REG_A2XX_RB_EDRAM_INFO, i);
> +
> +	ret = adreno_hw_init(gpu);
> +	if (ret)
> +		return ret;
> +
> +	/* NOTE: PM4/micro-engine firmware registers look to be the same
> +	 * for a2xx and a3xx.. we could possibly push that part down to
> +	 * adreno_gpu base class.  Or push both PM4 and PFP but
> +	 * parameterize the pfp ucode addr/data registers..
> +	 */
> +
> +	/* Load PM4: */
> +	ptr = (uint32_t *)(adreno_gpu->fw[ADRENO_FW_PM4]->data);
> +	len = adreno_gpu->fw[ADRENO_FW_PM4]->size / 4;
> +	DBG("loading PM4 ucode version: %x", ptr[1]);
> +
> +	gpu_write(gpu, REG_AXXX_CP_DEBUG, 0x02000000);
> +	gpu_write(gpu, REG_AXXX_CP_ME_RAM_WADDR, 0);
> +	for (i = 1; i < len; i++)
> +		gpu_write(gpu, REG_AXXX_CP_ME_RAM_DATA, ptr[i]);
> +
> +	/* Load PFP: */
> +	ptr = (uint32_t *)(adreno_gpu->fw[ADRENO_FW_PFP]->data);
> +	len = adreno_gpu->fw[ADRENO_FW_PFP]->size / 4;
> +	DBG("loading PFP ucode version: %x", ptr[5]);
> +
> +	gpu_write(gpu, REG_A2XX_CP_PFP_UCODE_ADDR, 0);
> +	for (i = 1; i < len; i++)
> +		gpu_write(gpu, REG_A2XX_CP_PFP_UCODE_DATA, ptr[i]);
> +
> +	gpu_write(gpu, REG_AXXX_CP_QUEUE_THRESHOLDS, 0x000C0804);
> +
> +	/* clear ME_HALT to start micro engine */
> +	gpu_write(gpu, REG_AXXX_CP_ME_CNTL, 0);
> +
> +	return a2xx_me_init(gpu) ? 0 : -EINVAL;
> +}
> +
> +static void a2xx_recover(struct msm_gpu *gpu)
> +{
> +	int i;
> +
> +	adreno_dump_info(gpu);
> +
> +	for (i = 0; i < 8; i++) {
> +		printk("CP_SCRATCH_REG%d: %u\n", i,
> +			gpu_read(gpu, REG_AXXX_CP_SCRATCH_REG0 + i));
> +	}
> +
> +	/* dump registers before resetting gpu, if enabled: */
> +	if (hang_debug)
> +		a2xx_dump(gpu);
> +
> +	gpu_write(gpu, REG_A2XX_RBBM_SOFT_RESET, 1);
> +	gpu_read(gpu, REG_A2XX_RBBM_SOFT_RESET);
> +	gpu_write(gpu, REG_A2XX_RBBM_SOFT_RESET, 0);
> +	adreno_recover(gpu);
> +}
> +
> +static void a2xx_destroy(struct msm_gpu *gpu)
> +{
> +	struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu);
> +	struct a2xx_gpu *a2xx_gpu = to_a2xx_gpu(adreno_gpu);
> +
> +	DBG("%s", gpu->name);
> +
> +	adreno_gpu_cleanup(adreno_gpu);
> +
> +	kfree(a2xx_gpu);
> +}
> +
> +static bool a2xx_idle(struct msm_gpu *gpu)
> +{
> +	/* wait for ringbuffer to drain: */
> +	if (!adreno_idle(gpu, gpu->rb[0]))
> +		return false;
> +
> +	/* then wait for GPU to finish: */
> +	if (spin_until(!(gpu_read(gpu, REG_A2XX_RBBM_STATUS) &
> +			A2XX_RBBM_STATUS_GUI_ACTIVE))) {
> +		DRM_ERROR("%s: timeout waiting for GPU to idle!\n", gpu->name);
> +
> +		/* TODO maybe we need to reset GPU here to recover from hang? */
> +		return false;
> +	}
> +
> +	return true;
> +}
> +
> +static irqreturn_t a2xx_irq(struct msm_gpu *gpu)
> +{
> +
> +	uint32_t mstatus, status;
> +
> +	mstatus = gpu_read(gpu, REG_A2XX_MASTER_INT_SIGNAL);
> +
> +	if (mstatus & A2XX_MASTER_INT_SIGNAL_MH_INT_STAT) {
> +		status = gpu_read(gpu, REG_A2XX_MH_INTERRUPT_STATUS);
> +
> +		dev_warn(gpu->dev->dev, "MH_INT: %08X\n", status);
> +		dev_warn(gpu->dev->dev, "MMU_PAGE_FAULT: %08X\n",
> +			gpu_read(gpu, REG_A2XX_MH_MMU_PAGE_FAULT));
> +		gpu_write(gpu, REG_A2XX_MH_INTERRUPT_CLEAR, status);
> +	}
> +
> +	if (mstatus & A2XX_MASTER_INT_SIGNAL_CP_INT_STAT) {
> +		status = gpu_read(gpu, REG_AXXX_CP_INT_STATUS);
> +
> +		/* only RB_INT is expected */
> +		if (status & ~AXXX_CP_INT_CNTL_RB_INT_MASK)
> +			dev_warn(gpu->dev->dev, "CP_INT: %08X\n", status);
> +
> +		gpu_write(gpu, REG_AXXX_CP_INT_ACK, status);
> +	}
> +
> +	if (mstatus & A2XX_MASTER_INT_SIGNAL_RBBM_INT_STAT) {
> +		status = gpu_read(gpu, REG_A2XX_RBBM_INT_STATUS);
> +
> +		dev_warn(gpu->dev->dev, "RBBM_INT: %08X\n", status);
> +
> +		gpu_write(gpu, REG_A2XX_RBBM_INT_ACK, status);
> +	}
> +
> +	msm_gpu_retire(gpu);
> +
> +	return IRQ_HANDLED;
> +}
> +
> +static const unsigned int a200_registers[] = {
> +	0x0000, 0x0002, 0x0004, 0x000B, 0x003B, 0x003D, 0x0040, 0x0044,
> +	0x0046, 0x0047, 0x01C0, 0x01C1, 0x01C3, 0x01C8, 0x01D5, 0x01D9,
> +	0x01DC, 0x01DD, 0x01EA, 0x01EA, 0x01EE, 0x01F3, 0x01F6, 0x01F7,
> +	0x01FC, 0x01FF, 0x0391, 0x0392, 0x039B, 0x039E, 0x03B2, 0x03B5,
> +	0x03B7, 0x03B7, 0x03F8, 0x03FB, 0x0440, 0x0440, 0x0443, 0x0444,
> +	0x044B, 0x044B, 0x044D, 0x044F, 0x0452, 0x0452, 0x0454, 0x045B,
> +	0x047F, 0x047F, 0x0578, 0x0587, 0x05C9, 0x05C9, 0x05D0, 0x05D0,
> +	0x0601, 0x0604, 0x0606, 0x0609, 0x060B, 0x060E, 0x0613, 0x0614,
> +	0x0A29, 0x0A2B, 0x0A2F, 0x0A31, 0x0A40, 0x0A43, 0x0A45, 0x0A45,
> +	0x0A4E, 0x0A4F, 0x0C2C, 0x0C2C, 0x0C30, 0x0C30, 0x0C38, 0x0C3C,
> +	0x0C40, 0x0C40, 0x0C44, 0x0C44, 0x0C80, 0x0C86, 0x0C88, 0x0C94,
> +	0x0C99, 0x0C9A, 0x0CA4, 0x0CA5, 0x0D00, 0x0D03, 0x0D06, 0x0D06,
> +	0x0D08, 0x0D0B, 0x0D34, 0x0D35, 0x0DAE, 0x0DC1, 0x0DC8, 0x0DD4,
> +	0x0DD8, 0x0DD9, 0x0E00, 0x0E00, 0x0E02, 0x0E04, 0x0E17, 0x0E1E,
> +	0x0EC0, 0x0EC9, 0x0ECB, 0x0ECC, 0x0ED0, 0x0ED0, 0x0ED4, 0x0ED7,
> +	0x0EE0, 0x0EE2, 0x0F01, 0x0F02, 0x0F0C, 0x0F0C, 0x0F0E, 0x0F12,
> +	0x0F26, 0x0F2A, 0x0F2C, 0x0F2C, 0x2000, 0x2002, 0x2006, 0x200F,
> +	0x2080, 0x2082, 0x2100, 0x2109, 0x210C, 0x2114, 0x2180, 0x2184,
> +	0x21F5, 0x21F7, 0x2200, 0x2208, 0x2280, 0x2283, 0x2293, 0x2294,
> +	0x2300, 0x2308, 0x2312, 0x2312, 0x2316, 0x231D, 0x2324, 0x2326,
> +	0x2380, 0x2383, 0x2400, 0x2402, 0x2406, 0x240F, 0x2480, 0x2482,
> +	0x2500, 0x2509, 0x250C, 0x2514, 0x2580, 0x2584, 0x25F5, 0x25F7,
> +	0x2600, 0x2608, 0x2680, 0x2683, 0x2693, 0x2694, 0x2700, 0x2708,
> +	0x2712, 0x2712, 0x2716, 0x271D, 0x2724, 0x2726, 0x2780, 0x2783,
> +	0x4000, 0x4003, 0x4800, 0x4805, 0x4900, 0x4900, 0x4908, 0x4908,
> +	~0   /* sentinel */
> +};
> +
> +static const unsigned int a220_registers[] = {
> +	0x0000, 0x0002, 0x0004, 0x000B, 0x003B, 0x003D, 0x0040, 0x0044,
> +	0x0046, 0x0047, 0x01C0, 0x01C1, 0x01C3, 0x01C8, 0x01D5, 0x01D9,
> +	0x01DC, 0x01DD, 0x01EA, 0x01EA, 0x01EE, 0x01F3, 0x01F6, 0x01F7,
> +	0x01FC, 0x01FF, 0x0391, 0x0392, 0x039B, 0x039E, 0x03B2, 0x03B5,
> +	0x03B7, 0x03B7, 0x03F8, 0x03FB, 0x0440, 0x0440, 0x0443, 0x0444,
> +	0x044B, 0x044B, 0x044D, 0x044F, 0x0452, 0x0452, 0x0454, 0x045B,
> +	0x047F, 0x047F, 0x0578, 0x0587, 0x05C9, 0x05C9, 0x05D0, 0x05D0,
> +	0x0601, 0x0604, 0x0606, 0x0609, 0x060B, 0x060E, 0x0613, 0x0614,
> +	0x0A29, 0x0A2B, 0x0A2F, 0x0A31, 0x0A40, 0x0A40, 0x0A42, 0x0A43,
> +	0x0A45, 0x0A45, 0x0A4E, 0x0A4F, 0x0C30, 0x0C30, 0x0C38, 0x0C39,
> +	0x0C3C, 0x0C3C, 0x0C80, 0x0C81, 0x0C88, 0x0C93, 0x0D00, 0x0D03,
> +	0x0D05, 0x0D06, 0x0D08, 0x0D0B, 0x0D34, 0x0D35, 0x0DAE, 0x0DC1,
> +	0x0DC8, 0x0DD4, 0x0DD8, 0x0DD9, 0x0E00, 0x0E00, 0x0E02, 0x0E04,
> +	0x0E17, 0x0E1E, 0x0EC0, 0x0EC9, 0x0ECB, 0x0ECC, 0x0ED0, 0x0ED0,
> +	0x0ED4, 0x0ED7, 0x0EE0, 0x0EE2, 0x0F01, 0x0F02, 0x2000, 0x2002,
> +	0x2006, 0x200F, 0x2080, 0x2082, 0x2100, 0x2102, 0x2104, 0x2109,
> +	0x210C, 0x2114, 0x2180, 0x2184, 0x21F5, 0x21F7, 0x2200, 0x2202,
> +	0x2204, 0x2204, 0x2208, 0x2208, 0x2280, 0x2282, 0x2294, 0x2294,
> +	0x2300, 0x2308, 0x2309, 0x230A, 0x2312, 0x2312, 0x2316, 0x2316,
> +	0x2318, 0x231D, 0x2324, 0x2326, 0x2380, 0x2383, 0x2400, 0x2402,
> +	0x2406, 0x240F, 0x2480, 0x2482, 0x2500, 0x2502, 0x2504, 0x2509,
> +	0x250C, 0x2514, 0x2580, 0x2584, 0x25F5, 0x25F7, 0x2600, 0x2602,
> +	0x2604, 0x2606, 0x2608, 0x2608, 0x2680, 0x2682, 0x2694, 0x2694,
> +	0x2700, 0x2708, 0x2712, 0x2712, 0x2716, 0x2716, 0x2718, 0x271D,
> +	0x2724, 0x2726, 0x2780, 0x2783, 0x4000, 0x4003, 0x4800, 0x4805,
> +	0x4900, 0x4900, 0x4908, 0x4908,
> +	~0   /* sentinel */
> +};
> +
> +static const unsigned int a225_registers[] = {
> +	0x0000, 0x0002, 0x0004, 0x000B, 0x003B, 0x003D, 0x0040, 0x0044,
> +	0x0046, 0x0047, 0x013C, 0x013C, 0x0140, 0x014F, 0x01C0, 0x01C1,
> +	0x01C3, 0x01C8, 0x01D5, 0x01D9, 0x01DC, 0x01DD, 0x01EA, 0x01EA,
> +	0x01EE, 0x01F3, 0x01F6, 0x01F7, 0x01FC, 0x01FF, 0x0391, 0x0392,
> +	0x039B, 0x039E, 0x03B2, 0x03B5, 0x03B7, 0x03B7, 0x03F8, 0x03FB,
> +	0x0440, 0x0440, 0x0443, 0x0444, 0x044B, 0x044B, 0x044D, 0x044F,
> +	0x0452, 0x0452, 0x0454, 0x045B, 0x047F, 0x047F, 0x0578, 0x0587,
> +	0x05C9, 0x05C9, 0x05D0, 0x05D0, 0x0601, 0x0604, 0x0606, 0x0609,
> +	0x060B, 0x060E, 0x0613, 0x0614, 0x0A29, 0x0A2B, 0x0A2F, 0x0A31,
> +	0x0A40, 0x0A40, 0x0A42, 0x0A43, 0x0A45, 0x0A45, 0x0A4E, 0x0A4F,
> +	0x0C01, 0x0C1D, 0x0C30, 0x0C30, 0x0C38, 0x0C39, 0x0C3C, 0x0C3C,
> +	0x0C80, 0x0C81, 0x0C88, 0x0C93, 0x0D00, 0x0D03, 0x0D05, 0x0D06,
> +	0x0D08, 0x0D0B, 0x0D34, 0x0D35, 0x0DAE, 0x0DC1, 0x0DC8, 0x0DD4,
> +	0x0DD8, 0x0DD9, 0x0E00, 0x0E00, 0x0E02, 0x0E04, 0x0E17, 0x0E1E,
> +	0x0EC0, 0x0EC9, 0x0ECB, 0x0ECC, 0x0ED0, 0x0ED0, 0x0ED4, 0x0ED7,
> +	0x0EE0, 0x0EE2, 0x0F01, 0x0F02, 0x2000, 0x200F, 0x2080, 0x2082,
> +	0x2100, 0x2109, 0x210C, 0x2114, 0x2180, 0x2184, 0x21F5, 0x21F7,
> +	0x2200, 0x2202, 0x2204, 0x2206, 0x2208, 0x2210, 0x2220, 0x2222,
> +	0x2280, 0x2282, 0x2294, 0x2294, 0x2297, 0x2297, 0x2300, 0x230A,
> +	0x2312, 0x2312, 0x2315, 0x2316, 0x2318, 0x231D, 0x2324, 0x2326,
> +	0x2340, 0x2357, 0x2360, 0x2360, 0x2380, 0x2383, 0x2400, 0x240F,
> +	0x2480, 0x2482, 0x2500, 0x2509, 0x250C, 0x2514, 0x2580, 0x2584,
> +	0x25F5, 0x25F7, 0x2600, 0x2602, 0x2604, 0x2606, 0x2608, 0x2610,
> +	0x2620, 0x2622, 0x2680, 0x2682, 0x2694, 0x2694, 0x2697, 0x2697,
> +	0x2700, 0x270A, 0x2712, 0x2712, 0x2715, 0x2716, 0x2718, 0x271D,
> +	0x2724, 0x2726, 0x2740, 0x2757, 0x2760, 0x2760, 0x2780, 0x2783,
> +	0x4000, 0x4003, 0x4800, 0x4806, 0x4808, 0x4808, 0x4900, 0x4900,
> +	0x4908, 0x4908,
> +	~0   /* sentinel */
> +};
> +
> +/* would be nice to not have to duplicate the _show() stuff with printk(): */
> +static void a2xx_dump(struct msm_gpu *gpu)
> +{
> +	printk("status:   %08x\n",
> +			gpu_read(gpu, REG_A2XX_RBBM_STATUS));
> +	adreno_dump(gpu);
> +}
> +
> +static struct msm_gpu_state *a2xx_gpu_state_get(struct msm_gpu *gpu)
> +{
> +	struct msm_gpu_state *state = kzalloc(sizeof(*state), GFP_KERNEL);
> +
> +	if (!state)
> +		return ERR_PTR(-ENOMEM);
> +
> +	adreno_gpu_state_get(gpu, state);
> +
> +	state->rbbm_status = gpu_read(gpu, REG_A2XX_RBBM_STATUS);
> +
> +	return state;
> +}
> +
> +/* Register offset defines for A2XX - copy of A3XX */
> +static const unsigned int a2xx_register_offsets[REG_ADRENO_REGISTER_MAX] = {
> +	REG_ADRENO_DEFINE(REG_ADRENO_CP_RB_BASE, REG_AXXX_CP_RB_BASE),
> +	REG_ADRENO_SKIP(REG_ADRENO_CP_RB_BASE_HI),
> +	REG_ADRENO_DEFINE(REG_ADRENO_CP_RB_RPTR_ADDR, REG_AXXX_CP_RB_RPTR_ADDR),
> +	REG_ADRENO_SKIP(REG_ADRENO_CP_RB_RPTR_ADDR_HI),
> +	REG_ADRENO_DEFINE(REG_ADRENO_CP_RB_RPTR, REG_AXXX_CP_RB_RPTR),
> +	REG_ADRENO_DEFINE(REG_ADRENO_CP_RB_WPTR, REG_AXXX_CP_RB_WPTR),
> +	REG_ADRENO_DEFINE(REG_ADRENO_CP_RB_CNTL, REG_AXXX_CP_RB_CNTL),
> +};
> +
> +static const struct adreno_gpu_funcs funcs = {
> +	.base = {
> +		.get_param = adreno_get_param,
> +		.hw_init = a2xx_hw_init,
> +		.pm_suspend = msm_gpu_pm_suspend,
> +		.pm_resume = msm_gpu_pm_resume,
> +		.recover = a2xx_recover,
> +		.submit = adreno_submit,
> +		.flush = adreno_flush,
> +		.active_ring = adreno_active_ring,
> +		.irq = a2xx_irq,
> +		.destroy = a2xx_destroy,
> +#if defined(CONFIG_DEBUG_FS) || defined(CONFIG_DEV_COREDUMP)
> +		.show = adreno_show,
> +#endif
> +		.gpu_state_get = a2xx_gpu_state_get,
> +		.gpu_state_put = adreno_gpu_state_put,
> +	},
> +};
> +
> +static const struct msm_gpu_perfcntr perfcntrs[] = {
> +/* TODO */
> +};
> +
> +struct msm_gpu *a2xx_gpu_init(struct drm_device *dev)
> +{
> +	struct a2xx_gpu *a2xx_gpu = NULL;
> +	struct adreno_gpu *adreno_gpu;
> +	struct msm_gpu *gpu;
> +	struct msm_drm_private *priv = dev->dev_private;
> +	struct platform_device *pdev = priv->gpu_pdev;
> +	int ret;
> +
> +	if (!pdev) {
> +		dev_err(dev->dev, "no a2xx device\n");
> +		ret = -ENXIO;
> +		goto fail;
> +	}
> +
> +	a2xx_gpu = kzalloc(sizeof(*a2xx_gpu), GFP_KERNEL);
> +	if (!a2xx_gpu) {
> +		ret = -ENOMEM;
> +		goto fail;
> +	}
> +
> +	adreno_gpu = &a2xx_gpu->base;
> +	gpu = &adreno_gpu->base;
> +
> +	gpu->perfcntrs = perfcntrs;
> +	gpu->num_perfcntrs = ARRAY_SIZE(perfcntrs);
> +
> +	if (adreno_is_a20x(adreno_gpu))
> +		adreno_gpu->registers = a200_registers;
> +	else if (adreno_is_a225(adreno_gpu))
> +		adreno_gpu->registers = a225_registers;
> +	else
> +		adreno_gpu->registers = a220_registers;
> +
> +	adreno_gpu->reg_offsets = a2xx_register_offsets;
> +
> +	ret = adreno_gpu_init(dev, pdev, adreno_gpu, &funcs, 1);
> +	if (ret)
> +		goto fail;
> +
> +	if (!gpu->aspace) {
> +		/* MMU is not implemented...  */
> +		dev_err(dev->dev, "No memory protection without MMU\n");
> +	}
> +
> +	return gpu;
> +
> +fail:
> +	if (a2xx_gpu)
> +		a2xx_destroy(&a2xx_gpu->base.base);
> +
> +	return ERR_PTR(ret);
> +}
> diff --git a/drivers/gpu/drm/msm/adreno/a2xx_gpu.h b/drivers/gpu/drm/msm/adreno/a2xx_gpu.h
> new file mode 100644
> index 000000000000..02fba2cb8932
> --- /dev/null
> +++ b/drivers/gpu/drm/msm/adreno/a2xx_gpu.h
> @@ -0,0 +1,21 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/* Copyright (c) 2018 The Linux Foundation. All rights reserved. */
> +
> +#ifndef __A2XX_GPU_H__
> +#define __A2XX_GPU_H__
> +
> +#include "adreno_gpu.h"
> +
> +/* arrg, somehow fb.h is getting pulled in: */
> +#undef ROP_COPY
> +#undef ROP_XOR
> +
> +#include "a2xx.xml.h"
> +
> +struct a2xx_gpu {
> +	struct adreno_gpu base;
> +	bool pm_enabled;
> +};
> +#define to_a2xx_gpu(x) container_of(x, struct a2xx_gpu, base)
> +
> +#endif /* __A2XX_GPU_H__ */
> diff --git a/drivers/gpu/drm/msm/adreno/adreno_device.c b/drivers/gpu/drm/msm/adreno/adreno_device.c
> index 86abdb2b3a9c..6e3f78d4da5d 100644
> --- a/drivers/gpu/drm/msm/adreno/adreno_device.c
> +++ b/drivers/gpu/drm/msm/adreno/adreno_device.c
> @@ -27,6 +27,39 @@ module_param_named(hang_debug, hang_debug, bool, 0600);
>  
>  static const struct adreno_info gpulist[] = {
>  	{
> +		.rev   = ADRENO_REV(2, 0, 0, 0),
> +		.revn  = 200,
> +		.name  = "A200",
> +		.fw = {
> +			[ADRENO_FW_PM4] = "yamato_pm4.fw",
> +			[ADRENO_FW_PFP] = "yamato_pfp.fw",
> +		},
> +		.gmem  = SZ_256K,
> +		.inactive_period = DRM_MSM_INACTIVE_PERIOD,
> +		.init  = a2xx_gpu_init,
> +	}, { /* a200 on i.mx51 has only 128kib gmem */
> +		.rev   = ADRENO_REV(2, 0, 0, 1),
> +		.revn  = 201,
> +		.name  = "A200",
> +		.fw = {
> +			[ADRENO_FW_PM4] = "yamato_pm4.fw",
> +			[ADRENO_FW_PFP] = "yamato_pfp.fw",
> +		},
> +		.gmem  = SZ_128K,
> +		.inactive_period = DRM_MSM_INACTIVE_PERIOD,
> +		.init  = a2xx_gpu_init,
> +	}, {
> +		.rev   = ADRENO_REV(2, 2, 0, ANY_ID),
> +		.revn  = 220,
> +		.name  = "A220",
> +		.fw = {
> +			[ADRENO_FW_PM4] = "leia_pm4_470.fw",
> +			[ADRENO_FW_PFP] = "leia_pfp_470.fw",
> +		},
> +		.gmem  = SZ_512K,
> +		.inactive_period = DRM_MSM_INACTIVE_PERIOD,
> +		.init  = a2xx_gpu_init,
> +	}, {
>  		.rev   = ADRENO_REV(3, 0, 5, ANY_ID),
>  		.revn  = 305,
>  		.name  = "A305",
> diff --git a/drivers/gpu/drm/msm/adreno/adreno_gpu.c b/drivers/gpu/drm/msm/adreno/adreno_gpu.c
> index 93d70f4a2154..e09671324b05 100644
> --- a/drivers/gpu/drm/msm/adreno/adreno_gpu.c
> +++ b/drivers/gpu/drm/msm/adreno/adreno_gpu.c
> @@ -319,16 +319,27 @@ void adreno_submit(struct msm_gpu *gpu, struct msm_gem_submit *submit,
>  		 */
>  		OUT_PKT3(ring, CP_EVENT_WRITE, 1);
>  		OUT_RING(ring, HLSQ_FLUSH);
> -
> -		OUT_PKT3(ring, CP_WAIT_FOR_IDLE, 1);
> -		OUT_RING(ring, 0x00000000);
>  	}
>  
> -	/* BIT(31) of CACHE_FLUSH_TS triggers CACHE_FLUSH_TS IRQ from GPU */
> -	OUT_PKT3(ring, CP_EVENT_WRITE, 3);
> -	OUT_RING(ring, CACHE_FLUSH_TS | BIT(31));
> -	OUT_RING(ring, rbmemptr(ring, fence));
> -	OUT_RING(ring, submit->seqno);
> +	/* wait for idle before cache flush/interrupt */
> +	OUT_PKT3(ring, CP_WAIT_FOR_IDLE, 1);
> +	OUT_RING(ring, 0x00000000);
> +
> +	if (!adreno_is_a2xx(adreno_gpu)) {
> +		/* BIT(31) of CACHE_FLUSH_TS triggers CACHE_FLUSH_TS IRQ from GPU */
> +		OUT_PKT3(ring, CP_EVENT_WRITE, 3);
> +		OUT_RING(ring, CACHE_FLUSH_TS | BIT(31));
> +		OUT_RING(ring, rbmemptr(ring, fence));
> +		OUT_RING(ring, submit->seqno);
> +	} else {
> +		/* BIT(31) means something else on a2xx */
> +		OUT_PKT3(ring, CP_EVENT_WRITE, 3);
> +		OUT_RING(ring, CACHE_FLUSH_TS);
> +		OUT_RING(ring, rbmemptr(ring, fence));
> +		OUT_RING(ring, submit->seqno);
> +		OUT_PKT3(ring, CP_INTERRUPT, 1);
> +		OUT_RING(ring, 0x80000000);
> +	}
>  
>  #if 0
>  	if (adreno_is_a3xx(adreno_gpu)) {
> diff --git a/drivers/gpu/drm/msm/adreno/adreno_gpu.h b/drivers/gpu/drm/msm/adreno/adreno_gpu.h
> index de6e6ee42fba..4adc97a91e1d 100644
> --- a/drivers/gpu/drm/msm/adreno/adreno_gpu.h
> +++ b/drivers/gpu/drm/msm/adreno/adreno_gpu.h
> @@ -154,6 +154,20 @@ struct adreno_platform_config {
>  	__ret;                                             \
>  })
>  
> +static inline bool adreno_is_a2xx(struct adreno_gpu *gpu)
> +{
> +	return (gpu->revn < 300);
> +}
> +
> +static inline bool adreno_is_a20x(struct adreno_gpu *gpu)
> +{
> +	return (gpu->revn < 210);
> +}
> +
> +static inline bool adreno_is_a225(struct adreno_gpu *gpu)
> +{
> +	return gpu->revn == 225;
> +}
>  
>  static inline bool adreno_is_a3xx(struct adreno_gpu *gpu)
>  {
> @@ -334,6 +348,7 @@ static inline void adreno_gpu_write(struct adreno_gpu *gpu,
>  		gpu_write(&gpu->base, reg - 1, data);
>  }
>  
> +struct msm_gpu *a2xx_gpu_init(struct drm_device *dev);
>  struct msm_gpu *a3xx_gpu_init(struct drm_device *dev);
>  struct msm_gpu *a4xx_gpu_init(struct drm_device *dev);
>  struct msm_gpu *a5xx_gpu_init(struct drm_device *dev);
> -- 
> 2.17.1
> 

-- 
The Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
a Linux Foundation Collaborative Project

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH 5/9] drm/msm: add headless gpu device (for imx5)
  2018-11-14 22:47   ` Jordan Crouse
@ 2018-11-14 23:08     ` Jonathan marek
  0 siblings, 0 replies; 13+ messages in thread
From: Jonathan marek @ 2018-11-14 23:08 UTC (permalink / raw)
  To: freedreno, Rob Clark, David Airlie, Bjorn Andersson,
	Niklas Cassel, Andy Gross, Govind Singh,
	open list:DRM DRIVER FOR MSM ADRENO GPU,
	open list:DRM DRIVER FOR MSM ADRENO GPU, open list

On 11/14/2018 05:47 PM, Jordan Crouse wrote:
> Thanks for  the patch. Perhaps a small blurb here for the commit log to let
> folks know what your intent was.
> 

I will add an explanation. The intent is clear to me from the commit 
message, but perhaps not for everyone.

> On Wed, Nov 14, 2018 at 05:24:12PM -0500, Jonathan Marek wrote:
>> Signed-off-by: Jonathan Marek <jonathan@marek.ca>
>> ---
>>   drivers/gpu/drm/msm/Kconfig       |  4 ++--
>>   drivers/gpu/drm/msm/msm_debugfs.c |  2 +-
>>   drivers/gpu/drm/msm/msm_drv.c     | 15 +++++++++++----
>>   include/linux/qcom_scm.h          |  3 +++
>>   4 files changed, 17 insertions(+), 7 deletions(-)
>>
>> diff --git a/drivers/gpu/drm/msm/Kconfig b/drivers/gpu/drm/msm/Kconfig
>> index 843a9d40c05e..cf549f1ed403 100644
>> --- a/drivers/gpu/drm/msm/Kconfig
>> +++ b/drivers/gpu/drm/msm/Kconfig
>> @@ -2,7 +2,7 @@
>>   config DRM_MSM
>>   	tristate "MSM DRM"
>>   	depends on DRM
>> -	depends on ARCH_QCOM || (ARM && COMPILE_TEST)
>> +	depends on ARCH_QCOM || SOC_IMX5 || (ARM && COMPILE_TEST)
>>   	depends on OF && COMMON_CLK
>>   	depends on MMU
>>   	select QCOM_MDT_LOADER if ARCH_QCOM
>> @@ -11,7 +11,7 @@ config DRM_MSM
>>   	select DRM_PANEL
>>   	select SHMEM
>>   	select TMPFS
>> -	select QCOM_SCM
>> +	select QCOM_SCM if ARCH_QCOM
>>   	select WANT_DEV_COREDUMP
>>   	select SND_SOC_HDMI_CODEC if SND_SOC
>>   	select SYNC_FILE
>> diff --git a/drivers/gpu/drm/msm/msm_debugfs.c b/drivers/gpu/drm/msm/msm_debugfs.c
>> index f0da0d3c8a80..1ca99ca356a4 100644
>> --- a/drivers/gpu/drm/msm/msm_debugfs.c
>> +++ b/drivers/gpu/drm/msm/msm_debugfs.c
>> @@ -235,7 +235,7 @@ int msm_debugfs_init(struct drm_minor *minor)
>>   	debugfs_create_file("gpu", S_IRUSR, minor->debugfs_root,
>>   		dev, &msm_gpu_fops);
>>   
>> -	if (priv->kms->funcs->debugfs_init) {
>> +	if (priv->kms && priv->kms->funcs->debugfs_init) {
>>   		ret = priv->kms->funcs->debugfs_init(priv->kms, minor);
>>   		if (ret)
>>   			return ret;
>> diff --git a/drivers/gpu/drm/msm/msm_drv.c b/drivers/gpu/drm/msm/msm_drv.c
>> index 9f219e02f3c7..a10cc0298d38 100644
>> --- a/drivers/gpu/drm/msm/msm_drv.c
>> +++ b/drivers/gpu/drm/msm/msm_drv.c
>> @@ -344,6 +344,7 @@ static int msm_drm_uninit(struct device *dev)
>>   	return 0;
>>   }
>>   
>> +#define KMS_HEADLESS 1
>>   #define KMS_MDP4 4
>>   #define KMS_MDP5 5
>>   #define KMS_DPU  3
>> @@ -495,6 +496,9 @@ static int msm_drm_init(struct device *dev, struct drm_driver *drv)
>>   	msm_gem_shrinker_init(ddev);
>>   
>>   	switch (get_mdp_ver(pdev)) {
>> +	case KMS_HEADLESS:
>> +		priv->kms = kms = NULL;
> 
> I don't think you need to set priv->kms, it should come in as NULL. I would
> normally say that you should set kms to NULL when it is declared, but I kind of
> like pointing it out to the user.
> 

It comes as NULL, but initializing it here matches the other cases in 
the switch (at the cost of 12 characters).

>> +		break;
>>   	case KMS_MDP4:
>>   		kms = mdp4_kms_init(ddev);
>>   		priv->kms = kms;
>> @@ -633,7 +637,7 @@ static int msm_drm_init(struct device *dev, struct drm_driver *drv)
>>   	drm_mode_config_reset(ddev);
>>   
>>   #ifdef CONFIG_DRM_FBDEV_EMULATION
>> -	if (fbdev)
>> +	if (kms && fbdev)
>>   		priv->fbdev = msm_fbdev_init(ddev);
>>   #endif
>>   
>> @@ -1315,9 +1319,11 @@ static int msm_pdev_probe(struct platform_device *pdev)
>>   	struct component_match *match = NULL;
>>   	int ret;
>>   
>> -	ret = add_display_components(&pdev->dev, &match);
>> -	if (ret)
>> -		return ret;
>> +	if (get_mdp_ver(pdev) != KMS_HEADLESS) {
>> +		ret = add_display_components(&pdev->dev, &match);
>> +		if (ret)
>> +			return ret;
>> +	}
>>   
>>   	ret = add_gpu_components(&pdev->dev, &match);
>>   	if (ret)
>> @@ -1342,6 +1348,7 @@ static int msm_pdev_remove(struct platform_device *pdev)
>>   }
>>   
>>   static const struct of_device_id dt_match[] = {
>> +	{ .compatible = "qcom,adreno-headless", .data = (void *)KMS_HEADLESS },
>>   	{ .compatible = "qcom,mdp4", .data = (void *)KMS_MDP4 },
>>   	{ .compatible = "qcom,mdss", .data = (void *)KMS_MDP5 },
>>   	{ .compatible = "qcom,sdm845-mdss", .data = (void *)KMS_DPU },
>> diff --git a/include/linux/qcom_scm.h b/include/linux/qcom_scm.h
>> index 06996ad4f2bc..1637385bcc17 100644
>> --- a/include/linux/qcom_scm.h
>> +++ b/include/linux/qcom_scm.h
>> @@ -67,6 +67,9 @@ extern int qcom_scm_iommu_secure_ptbl_init(u64 addr, u32 size, u32 spare);
>>   extern int qcom_scm_io_readl(phys_addr_t addr, unsigned int *val);
>>   extern int qcom_scm_io_writel(phys_addr_t addr, unsigned int val);
>>   #else
>> +
>> +#include <linux/errno.h>
>> +
> 
> This looks like a separate patch, albeit a useful one.
> 

Yes, that isn't part of this patch. Oops.

>>   static inline
>>   int qcom_scm_set_cold_boot_addr(void *entry, const cpumask_t *cpus)
>>   {
> 
> Jordan
> 

Jonathan

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH 7/9] drm/msm: implement a2xx mmu
  2018-11-14 22:24 ` [PATCH 7/9] drm/msm: implement a2xx mmu Jonathan Marek
@ 2018-11-20 16:29   ` Rob Clark
  0 siblings, 0 replies; 13+ messages in thread
From: Rob Clark @ 2018-11-20 16:29 UTC (permalink / raw)
  To: Jonathan
  Cc: freedreno, David Airlie, Jordan Crouse, Nicolas Dechesne,
	Archit Taneja, Arnd Bergmann, Kees Cook, Bjorn Andersson,
	Linux Kernel Mailing List, linux-arm-msm, dri-devel

thanks, it's nice to see a2xx getting some attention upstream.. few
comments inline..

On Wed, Nov 14, 2018 at 5:28 PM Jonathan Marek <jonathan@marek.ca> wrote:
>
> A2XX has its own very simple MMU.
>
> Added a msm_use_mmu() function because we can't rely on iommu_present to
> decide to use MMU or not.
>
> Signed-off-by: Jonathan Marek <jonathan@marek.ca>
> ---
>  drivers/gpu/drm/msm/Makefile               |   3 +-
>  drivers/gpu/drm/msm/adreno/a2xx_gpu.c      |  57 +++++++++--
>  drivers/gpu/drm/msm/adreno/adreno_device.c |   3 +
>  drivers/gpu/drm/msm/adreno/adreno_gpu.c    |  15 +++
>  drivers/gpu/drm/msm/msm_drv.c              |  11 +-
>  drivers/gpu/drm/msm/msm_drv.h              |   8 ++
>  drivers/gpu/drm/msm/msm_gem.c              |   4 +-
>  drivers/gpu/drm/msm/msm_gem_vma.c          |  23 +++++
>  drivers/gpu/drm/msm/msm_gpu.c              |  26 +++--
>  drivers/gpu/drm/msm/msm_gpummu.c           | 113 +++++++++++++++++++++
>  drivers/gpu/drm/msm/msm_mmu.h              |   3 +
>  11 files changed, 243 insertions(+), 23 deletions(-)
>  create mode 100644 drivers/gpu/drm/msm/msm_gpummu.c
>
> diff --git a/drivers/gpu/drm/msm/Makefile b/drivers/gpu/drm/msm/Makefile
> index 0170766393ea..004574bc9bd3 100644
> --- a/drivers/gpu/drm/msm/Makefile
> +++ b/drivers/gpu/drm/msm/Makefile
> @@ -91,7 +91,8 @@ msm-y := \
>         msm_perf.o \
>         msm_rd.o \
>         msm_ringbuffer.o \
> -       msm_submitqueue.o
> +       msm_submitqueue.o \
> +       msm_gpummu.o
>
>  msm-$(CONFIG_DEBUG_FS) += adreno/a5xx_debugfs.o \
>                           disp/dpu1/dpu_dbg.o
> diff --git a/drivers/gpu/drm/msm/adreno/a2xx_gpu.c b/drivers/gpu/drm/msm/adreno/a2xx_gpu.c
> index 65b2352408fa..dd669f046389 100644
> --- a/drivers/gpu/drm/msm/adreno/a2xx_gpu.c
> +++ b/drivers/gpu/drm/msm/adreno/a2xx_gpu.c
> @@ -2,6 +2,8 @@
>  /* Copyright (c) 2018 The Linux Foundation. All rights reserved. */
>
>  #include "a2xx_gpu.h"
> +#include "msm_gem.h"
> +#include "msm_mmu.h"
>
>  extern bool hang_debug;
>
> @@ -58,9 +60,12 @@ static bool a2xx_me_init(struct msm_gpu *gpu)
>  static int a2xx_hw_init(struct msm_gpu *gpu)
>  {
>         struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu);
> +       dma_addr_t pt_base, tran_error;
>         uint32_t *ptr, len;
>         int i, ret;
>
> +       msm_gpummu_params(gpu->aspace->mmu, &pt_base, &tran_error);
> +
>         DBG("%s", gpu->name);
>
>         gpu_write(gpu, REG_A2XX_RBBM_PM_OVERRIDE1, 0xfffffffe);
> @@ -77,9 +82,34 @@ static int a2xx_hw_init(struct msm_gpu *gpu)
>         /* XXX kgsl uses 0x0000ffff for a20x */
>         gpu_write(gpu, REG_A2XX_RBBM_CNTL, 0x00004442);
>
> -       gpu_write(gpu, REG_A2XX_MH_MMU_CONFIG, 0);
> -       gpu_write(gpu, REG_A2XX_MH_MMU_MPU_BASE, 0);
> +       /* MPU: physical range */
> +       gpu_write(gpu, REG_A2XX_MH_MMU_MPU_BASE, 0x00000000);
>         gpu_write(gpu, REG_A2XX_MH_MMU_MPU_END, 0xfffff000);
> +
> +       gpu_write(gpu, REG_A2XX_MH_MMU_CONFIG, A2XX_MH_MMU_CONFIG_MMU_ENABLE |
> +               A2XX_MH_MMU_CONFIG_RB_W_CLNT_BEHAVIOR(BEH_TRAN_RNG) |
> +               A2XX_MH_MMU_CONFIG_CP_W_CLNT_BEHAVIOR(BEH_TRAN_RNG) |
> +               A2XX_MH_MMU_CONFIG_CP_R0_CLNT_BEHAVIOR(BEH_TRAN_RNG) |
> +               A2XX_MH_MMU_CONFIG_CP_R1_CLNT_BEHAVIOR(BEH_TRAN_RNG) |
> +               A2XX_MH_MMU_CONFIG_CP_R2_CLNT_BEHAVIOR(BEH_TRAN_RNG) |
> +               A2XX_MH_MMU_CONFIG_CP_R3_CLNT_BEHAVIOR(BEH_TRAN_RNG) |
> +               A2XX_MH_MMU_CONFIG_CP_R4_CLNT_BEHAVIOR(BEH_TRAN_RNG) |
> +               A2XX_MH_MMU_CONFIG_VGT_R0_CLNT_BEHAVIOR(BEH_TRAN_RNG) |
> +               A2XX_MH_MMU_CONFIG_VGT_R1_CLNT_BEHAVIOR(BEH_TRAN_RNG) |
> +               A2XX_MH_MMU_CONFIG_TC_R_CLNT_BEHAVIOR(BEH_TRAN_RNG) |
> +               A2XX_MH_MMU_CONFIG_PA_W_CLNT_BEHAVIOR(BEH_TRAN_RNG));
> +
> +       /* same as parameters in adreno_gpu */
> +       gpu_write(gpu, REG_A2XX_MH_MMU_VA_RANGE, SZ_16M |
> +               A2XX_MH_MMU_VA_RANGE_NUM_64KB_REGIONS(0xfff));
> +
> +       gpu_write(gpu, REG_A2XX_MH_MMU_PT_BASE, pt_base);
> +       gpu_write(gpu, REG_A2XX_MH_MMU_TRAN_ERROR, tran_error);
> +
> +       gpu_write(gpu, REG_A2XX_MH_MMU_INVALIDATE,
> +               A2XX_MH_MMU_INVALIDATE_INVALIDATE_ALL |
> +               A2XX_MH_MMU_INVALIDATE_INVALIDATE_TC);
> +
>         gpu_write(gpu, REG_A2XX_MH_ARBITER_CONFIG,
>                 A2XX_MH_ARBITER_CONFIG_SAME_PAGE_LIMIT(16) |
>                 A2XX_MH_ARBITER_CONFIG_L1_ARB_ENABLE |
> @@ -106,9 +136,21 @@ static int a2xx_hw_init(struct msm_gpu *gpu)
>         /* XXX gsl doesn't set this */
>         gpu_write(gpu, REG_A2XX_RBBM_DEBUG, 0x00080000);
>
> -       gpu_write(gpu, REG_A2XX_RBBM_INT_CNTL, 0);
> -       gpu_write(gpu, REG_AXXX_CP_INT_CNTL, 0x80000000); /* RB INT */
> +       gpu_write(gpu, REG_A2XX_RBBM_INT_CNTL,
> +               A2XX_RBBM_INT_CNTL_RDERR_INT_MASK);
> +       gpu_write(gpu, REG_AXXX_CP_INT_CNTL,
> +               AXXX_CP_INT_CNTL_T0_PACKET_IN_IB_MASK |
> +               AXXX_CP_INT_CNTL_OPCODE_ERROR_MASK |
> +               AXXX_CP_INT_CNTL_PROTECTED_MODE_ERROR_MASK |
> +               AXXX_CP_INT_CNTL_RESERVED_BIT_ERROR_MASK |
> +               AXXX_CP_INT_CNTL_IB_ERROR_MASK |
> +               AXXX_CP_INT_CNTL_IB1_INT_MASK |
> +               AXXX_CP_INT_CNTL_RB_INT_MASK);
>         gpu_write(gpu, REG_A2XX_SQ_INT_CNTL, 0);
> +       gpu_write(gpu, REG_A2XX_MH_INTERRUPT_MASK,
> +               A2XX_MH_INTERRUPT_MASK_AXI_READ_ERROR |
> +               A2XX_MH_INTERRUPT_MASK_AXI_WRITE_ERROR |
> +               A2XX_MH_INTERRUPT_MASK_MMU_PAGE_FAULT);
>
>         for (i = 3; i <= 5; i++)
>                 if ((SZ_16K << i) == adreno_gpu->gmem)
> @@ -205,7 +247,6 @@ static bool a2xx_idle(struct msm_gpu *gpu)
>
>  static irqreturn_t a2xx_irq(struct msm_gpu *gpu)
>  {
> -

could you fold this whitespace change back into the patch that adds this?

>         uint32_t mstatus, status;
>
>         mstatus = gpu_read(gpu, REG_A2XX_MASTER_INT_SIGNAL);
> @@ -216,6 +257,7 @@ static irqreturn_t a2xx_irq(struct msm_gpu *gpu)
>                 dev_warn(gpu->dev->dev, "MH_INT: %08X\n", status);
>                 dev_warn(gpu->dev->dev, "MMU_PAGE_FAULT: %08X\n",
>                         gpu_read(gpu, REG_A2XX_MH_MMU_PAGE_FAULT));
> +
>                 gpu_write(gpu, REG_A2XX_MH_INTERRUPT_CLEAR, status);
>         }
>
> @@ -430,11 +472,6 @@ struct msm_gpu *a2xx_gpu_init(struct drm_device *dev)
>         if (ret)
>                 goto fail;
>
> -       if (!gpu->aspace) {
> -               /* MMU is not implemented...  */
> -               dev_err(dev->dev, "No memory protection without MMU\n");
> -       }
> -

hmm, could mmu init still fail?  I guess it looks like it does not
need to request any additional clks/etc.  And hopefully there is
nothing out there with a non-functional gpummu?

>         return gpu;
>
>  fail:
> diff --git a/drivers/gpu/drm/msm/adreno/adreno_device.c b/drivers/gpu/drm/msm/adreno/adreno_device.c
> index 6e3f78d4da5d..f651cd51449b 100644
> --- a/drivers/gpu/drm/msm/adreno/adreno_device.c
> +++ b/drivers/gpu/drm/msm/adreno/adreno_device.c
> @@ -307,6 +307,7 @@ static int adreno_bind(struct device *dev, struct device *master, void *data)
>         static struct adreno_platform_config config = {};
>         const struct adreno_info *info;
>         struct drm_device *drm = dev_get_drvdata(master);
> +       struct msm_drm_private *priv = drm->dev_private;
>         struct msm_gpu *gpu;
>         int ret;
>
> @@ -337,6 +338,8 @@ static int adreno_bind(struct device *dev, struct device *master, void *data)
>
>         dev_set_drvdata(dev, gpu);
>
> +       priv->is_a2xx = config.rev.core == 2;
> +
>         return 0;
>  }
>
> diff --git a/drivers/gpu/drm/msm/adreno/adreno_gpu.c b/drivers/gpu/drm/msm/adreno/adreno_gpu.c
> index e09671324b05..18736637c933 100644
> --- a/drivers/gpu/drm/msm/adreno/adreno_gpu.c
> +++ b/drivers/gpu/drm/msm/adreno/adreno_gpu.c
> @@ -24,6 +24,7 @@
>  #include "adreno_gpu.h"
>  #include "msm_gem.h"
>  #include "msm_mmu.h"
> +#include "a2xx_gpu.h"
>
>  int adreno_get_param(struct msm_gpu *gpu, uint32_t param, uint64_t *value)
>  {
> @@ -290,6 +291,17 @@ void adreno_submit(struct msm_gpu *gpu, struct msm_gem_submit *submit,
>         struct msm_ringbuffer *ring = submit->ring;
>         unsigned i;
>
> +       if (adreno_is_a2xx(adreno_gpu)) {
> +               /* tlb flush for a2xx MMU. TODO: only do this when required */
> +               OUT_PKT3(ring, CP_SET_PROTECTED_MODE, 1);
> +               OUT_RING(ring, 0);
> +               OUT_PKT0(ring, REG_A2XX_MH_MMU_INVALIDATE, 1);
> +               OUT_RING(ring, A2XX_MH_MMU_INVALIDATE_INVALIDATE_ALL |
> +                       A2XX_MH_MMU_INVALIDATE_INVALIDATE_TC);
> +               OUT_PKT3(ring, CP_SET_PROTECTED_MODE, 1);
> +               OUT_RING(ring, 1);

can we only invalidate from the ring?  If so, defn keeping a flag
about whether inv needed would be a good idea.  Userspace tries to use
a bo_cache[1] to re-use already mapped buffers, so I'd expect in
steady-state this wouldn't be needed on every submit.


[1] actually two of them, a separate bo cache is used for things that
get vmap'd on kernel side

> +       }
> +
>         for (i = 0; i < submit->nr_cmds; i++) {
>                 switch (submit->cmd[i].type) {
>                 case MSM_SUBMIT_CMD_IB_TARGET_BUF:
> @@ -728,6 +740,9 @@ int adreno_gpu_init(struct drm_device *drm, struct platform_device *pdev,
>
>         adreno_gpu_config.va_start = SZ_16M;
>         adreno_gpu_config.va_end = 0xffffffff;
> +       /* maximum range of a2xx mmu */
> +       if (adreno_is_a2xx(adreno_gpu))
> +               adreno_gpu_config.va_end = SZ_16M + 0xfff * SZ_64K;
>
>         adreno_gpu_config.nr_rings = nr_rings;
>
> diff --git a/drivers/gpu/drm/msm/msm_drv.c b/drivers/gpu/drm/msm/msm_drv.c
> index a10cc0298d38..bda23011494d 100644
> --- a/drivers/gpu/drm/msm/msm_drv.c
> +++ b/drivers/gpu/drm/msm/msm_drv.c
> @@ -25,6 +25,7 @@
>  #include "msm_fence.h"
>  #include "msm_gpu.h"
>  #include "msm_kms.h"
> +#include "adreno/adreno_gpu.h"
>
>
>  /*
> @@ -358,6 +359,14 @@ static int get_mdp_ver(struct platform_device *pdev)
>
>  #include <linux/of_address.h>
>
> +bool msm_use_mmu(struct drm_device *dev)
> +{
> +       struct msm_drm_private *priv = dev->dev_private;
> +
> +       /* a2xx comes with its own MMU */
> +       return priv->is_a2xx || iommu_present(&platform_bus_type);

tbh, iommu_present(bus) is not even really sufficient for other
devices where some platform devices have iommu and other do not but I
guess this is the best we can do at this point :-(

> +}
> +
>  static int msm_init_vram(struct drm_device *dev)
>  {
>         struct msm_drm_private *priv = dev->dev_private;
> @@ -396,7 +405,7 @@ static int msm_init_vram(struct drm_device *dev)
>                  * Grab the entire CMA chunk carved out in early startup in
>                  * mach-msm:
>                  */
> -       } else if (!iommu_present(&platform_bus_type)) {
> +       } else if (!msm_use_mmu(dev)) {
>                 DRM_INFO("using %s VRAM carveout\n", vram);
>                 size = memparse(vram, NULL);
>         }
> diff --git a/drivers/gpu/drm/msm/msm_drv.h b/drivers/gpu/drm/msm/msm_drv.h
> index 9d11f321f5a9..99a37962e92b 100644
> --- a/drivers/gpu/drm/msm/msm_drv.h
> +++ b/drivers/gpu/drm/msm/msm_drv.h
> @@ -179,6 +179,8 @@ struct msm_drm_private {
>         /* when we have more than one 'msm_gpu' these need to be an array: */
>         struct msm_gpu *gpu;
>         struct msm_file_private *lastctx;
> +       /* gpu is only set on open(), but we need this info earlier */
> +       bool is_a2xx;
>
>         struct drm_fb_helper *fbdev;
>
> @@ -252,9 +254,15 @@ struct msm_gem_address_space *
>  msm_gem_address_space_create(struct device *dev, struct iommu_domain *domain,
>                 const char *name);
>
> +struct msm_gem_address_space *
> +msm_gem_address_space_create_a2xx(struct device *dev, struct msm_gpu *gpu,
> +               const char *name, uint64_t va_start, uint64_t va_end);
> +
>  int msm_register_mmu(struct drm_device *dev, struct msm_mmu *mmu);
>  void msm_unregister_mmu(struct drm_device *dev, struct msm_mmu *mmu);
>
> +bool msm_use_mmu(struct drm_device *dev);
> +
>  void msm_gem_submit_free(struct msm_gem_submit *submit);
>  int msm_ioctl_gem_submit(struct drm_device *dev, void *data,
>                 struct drm_file *file);
> diff --git a/drivers/gpu/drm/msm/msm_gem.c b/drivers/gpu/drm/msm/msm_gem.c
> index 6657453a3a58..c1ef8780f686 100644
> --- a/drivers/gpu/drm/msm/msm_gem.c
> +++ b/drivers/gpu/drm/msm/msm_gem.c
> @@ -912,7 +912,7 @@ static struct drm_gem_object *_msm_gem_new(struct drm_device *dev,
>
>         size = PAGE_ALIGN(size);
>
> -       if (!iommu_present(&platform_bus_type))
> +       if (!msm_use_mmu(dev))
>                 use_vram = true;
>         else if ((flags & (MSM_BO_STOLEN | MSM_BO_SCANOUT)) && priv->vram.size)
>                 use_vram = true;
> @@ -991,7 +991,7 @@ struct drm_gem_object *msm_gem_import(struct drm_device *dev,
>         int ret, npages;
>
>         /* if we don't have IOMMU, don't bother pretending we can import: */
> -       if (!iommu_present(&platform_bus_type)) {
> +       if (!msm_use_mmu(dev)) {
>                 dev_err(dev->dev, "cannot import without IOMMU\n");
>                 return ERR_PTR(-EINVAL);
>         }
> diff --git a/drivers/gpu/drm/msm/msm_gem_vma.c b/drivers/gpu/drm/msm/msm_gem_vma.c
> index ffbec224551b..8075fd699803 100644
> --- a/drivers/gpu/drm/msm/msm_gem_vma.c
> +++ b/drivers/gpu/drm/msm/msm_gem_vma.c
> @@ -114,3 +114,26 @@ msm_gem_address_space_create(struct device *dev, struct iommu_domain *domain,
>
>         return aspace;
>  }
> +
> +struct msm_gem_address_space *
> +msm_gem_address_space_create_a2xx(struct device *dev, struct msm_gpu *gpu,
> +               const char *name, uint64_t va_start, uint64_t va_end)
> +{
> +       struct msm_gem_address_space *aspace;
> +       u64 size = va_end - va_start;
> +
> +       aspace = kzalloc(sizeof(*aspace), GFP_KERNEL);
> +       if (!aspace)
> +               return ERR_PTR(-ENOMEM);
> +
> +       spin_lock_init(&aspace->lock);
> +       aspace->name = name;
> +       aspace->mmu = msm_gpummu_new(dev, gpu);
> +
> +       drm_mm_init(&aspace->mm, (va_start >> PAGE_SHIFT),
> +               size >> PAGE_SHIFT);
> +
> +       kref_init(&aspace->kref);
> +
> +       return aspace;
> +}
> diff --git a/drivers/gpu/drm/msm/msm_gpu.c b/drivers/gpu/drm/msm/msm_gpu.c
> index 11aac8337066..9af24a1a70a0 100644
> --- a/drivers/gpu/drm/msm/msm_gpu.c
> +++ b/drivers/gpu/drm/msm/msm_gpu.c
> @@ -19,6 +19,7 @@
>  #include "msm_gem.h"
>  #include "msm_mmu.h"
>  #include "msm_fence.h"
> +#include "adreno/adreno_gpu.h"
>
>  #include <generated/utsrelease.h>
>  #include <linux/string_helpers.h>
> @@ -800,7 +801,7 @@ static struct msm_gem_address_space *
>  msm_gpu_create_address_space(struct msm_gpu *gpu, struct platform_device *pdev,
>                 uint64_t va_start, uint64_t va_end)
>  {
> -       struct iommu_domain *iommu;
> +       struct iommu_domain *iommu = NULL;
>         struct msm_gem_address_space *aspace;
>         int ret;
>
> @@ -809,20 +810,27 @@ msm_gpu_create_address_space(struct msm_gpu *gpu, struct platform_device *pdev,
>          * and have separate page tables per context.  For now, to keep things
>          * simple and to get something working, just use a single address space:
>          */
> -       iommu = iommu_domain_alloc(&platform_bus_type);
> -       if (!iommu)
> -               return NULL;
> +       if (!adreno_is_a2xx(to_adreno_gpu(gpu))) {
> +               iommu = iommu_domain_alloc(&platform_bus_type);
> +               if (!iommu)
> +                       return NULL;
>
> -       iommu->geometry.aperture_start = va_start;
> -       iommu->geometry.aperture_end = va_end;
> +               iommu->geometry.aperture_start = va_start;
> +               iommu->geometry.aperture_end = va_end;
>
> -       dev_info(gpu->dev->dev, "%s: using IOMMU\n", gpu->name);
> +               dev_info(gpu->dev->dev, "%s: using IOMMU\n", gpu->name);
> +
> +               aspace = msm_gem_address_space_create(&pdev->dev, iommu, "gpu");
> +       } else {
> +               aspace = msm_gem_address_space_create_a2xx(&pdev->dev, gpu, "gpu",
> +                       va_start, va_end);
> +       }
>
> -       aspace = msm_gem_address_space_create(&pdev->dev, iommu, "gpu");
>         if (IS_ERR(aspace)) {
>                 dev_err(gpu->dev->dev, "failed to init iommu: %ld\n",
>                         PTR_ERR(aspace));
> -               iommu_domain_free(iommu);
> +               if (iommu)
> +                       iommu_domain_free(iommu);

minor nit, maybe just move iommu and the iommu_domain_free() into the
if(!a2xx) case?

>                 return ERR_CAST(aspace);
>         }
>
> diff --git a/drivers/gpu/drm/msm/msm_gpummu.c b/drivers/gpu/drm/msm/msm_gpummu.c
> new file mode 100644
> index 000000000000..f14cf7759c7f
> --- /dev/null
> +++ b/drivers/gpu/drm/msm/msm_gpummu.c
> @@ -0,0 +1,113 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/* Copyright (c) 2018 The Linux Foundation. All rights reserved. */
> +
> +#include "msm_drv.h"
> +#include "msm_mmu.h"
> +
> +struct msm_gpummu {
> +       struct msm_mmu base;
> +       struct msm_gpu *gpu;
> +       dma_addr_t pt_base;
> +       uint32_t *table;
> +};
> +#define to_msm_gpummu(x) container_of(x, struct msm_gpummu, base)
> +
> +#define VA_START SZ_16M
> +#define VA_RANGE (0xfff * SZ_64K)
> +#define MMU_PAGE_SIZE SZ_4K
> +#define TABLE_SIZE (sizeof(uint32_t) * VA_RANGE / MMU_PAGE_SIZE)
> +
> +static int msm_gpummu_attach(struct msm_mmu *mmu, const char * const *names,
> +               int cnt)
> +{
> +       return 0;
> +}
> +
> +static void msm_gpummu_detach(struct msm_mmu *mmu, const char * const *names,
> +               int cnt)
> +{
> +}
> +
> +static void update_pt(struct msm_mmu *mmu, uint64_t iova,
> +               struct sg_table *sgt, unsigned len, unsigned prot)
> +{
> +       struct msm_gpummu *gpummu = to_msm_gpummu(mmu);
> +       unsigned idx = (iova - VA_START) / MMU_PAGE_SIZE;
> +       struct scatterlist *sg;
> +       unsigned i, j;
> +
> +       for_each_sg(sgt->sgl, sg, sgt->nents, i) {
> +               dma_addr_t addr = sg->dma_address;
> +               for (j = 0; j < sg->length / MMU_PAGE_SIZE; j++, idx++) {
> +                       gpummu->table[idx] = prot ? addr | prot : 0;
> +                       addr += MMU_PAGE_SIZE;
> +               }
> +       }
> +}
> +
> +static int msm_gpummu_map(struct msm_mmu *mmu, uint64_t iova,
> +               struct sg_table *sgt, unsigned len, int prot)
> +{
> +       unsigned prot_bits = 0;
> +       if (prot & IOMMU_WRITE)
> +               prot_bits |= 1;
> +       if (prot & IOMMU_READ)
> +               prot_bits |= 2;
> +       update_pt(mmu, iova, sgt, len, prot_bits);
> +       return 0;
> +}
> +
> +static int msm_gpummu_unmap(struct msm_mmu *mmu, uint64_t iova,
> +               struct sg_table *sgt, unsigned len)
> +{
> +       update_pt(mmu, iova, sgt, len, 0);

so one thing I'm a bit concerned about is tlb flush on unmap not
happening until the next submit, while meanwhile we've returned the
buffer's pages to the OS.  If we can trigger tlb inv from CPU, then it
is probably a good idea to do so for unmap.  (But map is fine to
defer.)

If we can't tlb inv from the CPU then maybe we need to keep a list of
bo's to defer freeing the pages.

Otherwise this looks fine to me.

BR,
-R

Side note: I have kinda wanted to do something similar for a while for
the IOMMU case, and teach the IOMMU about deferred TLB flush.. since
the common usage pattern is to map N bo's that we haven't used before
in the submit ioctl, and unmap/free M buffers from retire_worker.  For
a2xx and older iommu's (which had to inv on map) batching the mapping
and doing a single inv seems like a win.  And for everyone keeping a
list of "zombie" bo's which are unmapped but waiting to be free'd
until tlb inv, could let us back multiple unmaps and do a single tlb
inv.


> +       return 0;
> +}
> +
> +static void msm_gpummu_destroy(struct msm_mmu *mmu)
> +{
> +       struct msm_gpummu *gpummu = to_msm_gpummu(mmu);
> +
> +       dma_free_attrs(mmu->dev, TABLE_SIZE, gpummu->table, gpummu->pt_base,
> +               DMA_ATTR_FORCE_CONTIGUOUS);
> +
> +       kfree(gpummu);
> +}
> +
> +static const struct msm_mmu_funcs funcs = {
> +               .attach = msm_gpummu_attach,
> +               .detach = msm_gpummu_detach,
> +               .map = msm_gpummu_map,
> +               .unmap = msm_gpummu_unmap,
> +               .destroy = msm_gpummu_destroy,
> +};
> +
> +struct msm_mmu *msm_gpummu_new(struct device *dev, struct msm_gpu *gpu)
> +{
> +       struct msm_gpummu *gpummu;
> +
> +       gpummu = kzalloc(sizeof(*gpummu), GFP_KERNEL);
> +       if (!gpummu)
> +               return ERR_PTR(-ENOMEM);
> +
> +       gpummu->table = dma_alloc_attrs(dev, TABLE_SIZE + 32, &gpummu->pt_base,
> +               GFP_KERNEL | __GFP_ZERO, DMA_ATTR_FORCE_CONTIGUOUS);
> +       if (!gpummu->table) {
> +               kfree(gpummu);
> +               return ERR_PTR(-ENOMEM);
> +       }
> +
> +       gpummu->gpu = gpu;
> +       msm_mmu_init(&gpummu->base, dev, &funcs);
> +
> +       return &gpummu->base;
> +}
> +
> +void msm_gpummu_params(struct msm_mmu *mmu, dma_addr_t *pt_base,
> +               dma_addr_t *tran_error)
> +{
> +       dma_addr_t base = to_msm_gpummu(mmu)->pt_base;
> +
> +       *pt_base = base;
> +       *tran_error = base + TABLE_SIZE; /* 32-byte aligned */
> +}
> diff --git a/drivers/gpu/drm/msm/msm_mmu.h b/drivers/gpu/drm/msm/msm_mmu.h
> index aa2c5d4580c8..c5bbb49dc1be 100644
> --- a/drivers/gpu/drm/msm/msm_mmu.h
> +++ b/drivers/gpu/drm/msm/msm_mmu.h
> @@ -54,4 +54,7 @@ static inline void msm_mmu_set_fault_handler(struct msm_mmu *mmu, void *arg,
>         mmu->handler = handler;
>  }
>
> +void msm_gpummu_params(struct msm_mmu *mmu, dma_addr_t *pt_base,
> +               dma_addr_t *tran_error);
> +
>  #endif /* __MSM_MMU_H__ */
> --
> 2.17.1
>

^ permalink raw reply	[flat|nested] 13+ messages in thread

end of thread, other threads:[~2018-11-20 16:30 UTC | newest]

Thread overview: 13+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2018-11-14 22:24 [PATCH 1/9] drm/msm/mdp4: only use lut_clk on mdp4.2+ Jonathan Marek
2018-11-14 22:24 ` [PATCH 2/9] drm/msm/mdp4: allocate blank_cursor_no with MSM_BO_SCANOUT flag Jonathan Marek
2018-11-14 22:24 ` [PATCH 3/9] drm/msm/mdp4: add lcdc-align-lsb flag to control lane alignment Jonathan Marek
2018-11-14 22:24 ` [PATCH 4/9] drm/msm: use contiguous vram for MSM_BO_SCANOUT when possible Jonathan Marek
2018-11-14 22:24 ` [PATCH 5/9] drm/msm: add headless gpu device (for imx5) Jonathan Marek
2018-11-14 22:47   ` Jordan Crouse
2018-11-14 23:08     ` Jonathan marek
2018-11-14 22:24 ` [PATCH 6/9] drm/msm/adreno: add a2xx Jonathan Marek
2018-11-14 22:59   ` Jordan Crouse
2018-11-14 22:24 ` [PATCH 7/9] drm/msm: implement a2xx mmu Jonathan Marek
2018-11-20 16:29   ` Rob Clark
2018-11-14 22:24 ` [PATCH 8/9] drm/msm/mdp5: add config for msm8917 Jonathan Marek
2018-11-14 22:24 ` [PATCH 9/9] drm/msm: set priv->kms to NULL before uninit Jonathan Marek

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).