msm: kgsl: split mh and mmu initialization

The MH block should be initialized even if the gpu mmu
is not enabled so that AXI error interrupts will still
be generated.

Signed-off-by: Jeremy Gebben <jgebben@codeaurora.org>
diff --git a/drivers/gpu/msm/a200_reg.h b/drivers/gpu/msm/a200_reg.h
index e1681f9..2bd4902 100644
--- a/drivers/gpu/msm/a200_reg.h
+++ b/drivers/gpu/msm/a200_reg.h
@@ -307,10 +307,6 @@
 
 #define REG_MASTER_INT_SIGNAL            0x03B7
 
-#define REG_MH_ARBITER_CONFIG            0x0A40
-#define REG_MH_CLNT_INTF_CTRL_CONFIG1    0x0A54
-#define REG_MH_CLNT_INTF_CTRL_CONFIG2    0x0A55
-
 #define REG_PA_CL_VPORT_XSCALE           0x210F
 #define REG_PA_CL_VPORT_ZOFFSET          0x2114
 #define REG_PA_CL_VPORT_ZSCALE           0x2113
@@ -399,8 +395,6 @@
 #define REG_SQ_CONSTANT_0                0x4000
 #define REG_SQ_FETCH_0                   0x4800
 
-#define REG_MH_DEBUG_CTRL                0xA4E
-#define REG_MH_DEBUG_DATA                0xA4F
 #define REG_COHER_BASE_PM4               0xA2A
 #define REG_COHER_STATUS_PM4             0xA2B
 #define REG_COHER_SIZE_PM4               0xA29
diff --git a/drivers/gpu/msm/adreno.c b/drivers/gpu/msm/adreno.c
index b2c8ae3..d5d6a1d 100644
--- a/drivers/gpu/msm/adreno.c
+++ b/drivers/gpu/msm/adreno.c
@@ -76,14 +76,22 @@
 		.id = KGSL_DEVICE_3D0,
 		.ver_major = DRIVER_VERSION_MAJOR,
 		.ver_minor = DRIVER_VERSION_MINOR,
-		.mmu = {
-			.config = ADRENO_MMU_CONFIG,
+		.mh = {
+			.mharb  = ADRENO_CFG_MHARB,
+			/* Remove 1k boundary check in z470 to avoid a GPU
+			 * hang.  Notice that this solution won't work if
+			 * both EBI and SMI are used
+			 */
+			.mh_intf_cfg1 = 0x00032f07,
 			/* turn off memory protection unit by setting
 			   acceptable physical address range to include
 			   all pages. */
 			.mpu_base = 0x00000000,
 			.mpu_range =  0xFFFFF000,
 		},
+		.mmu = {
+			.config = ADRENO_MMU_CONFIG,
+		},
 		.pwrctrl = {
 			.regulator_name = "fs_gfx3d",
 			.irq_name = KGSL_3D0_IRQ,
@@ -108,7 +116,6 @@
 	},
 	.pfp_fw = NULL,
 	.pm4_fw = NULL,
-	.mharb  = ADRENO_CFG_MHARB,
 };
 
 static int adreno_gmeminit(struct adreno_device *adreno_dev)
@@ -478,6 +485,17 @@
 	/* Identify the specific GPU */
 	adreno_identify_gpu(adreno_dev);
 
+	if (adreno_is_a20x(adreno_dev)) {
+		/*
+		 * the MH_CLNT_INTF_CTRL_CONFIG registers aren't present
+		 * on older gpus
+		 */
+		device->mh.mh_intf_cfg1 = 0;
+		device->mh.mh_intf_cfg2 = 0;
+	}
+
+	kgsl_mh_start(device);
+
 	if (kgsl_mmu_start(device))
 		goto error_clk_off;
 
@@ -504,16 +522,6 @@
 
 	adreno_regwrite(device, REG_RBBM_CNTL, 0x00004442);
 
-	adreno_regwrite(device, REG_MH_ARBITER_CONFIG,
-				adreno_dev->mharb);
-
-	/* Remove 1k boundary check in z470 to avoid GPU hang.
-	   Notice that, this solution won't work if both EBI and SMI are used */
-	if (adreno_is_a220(adreno_dev)) {
-		adreno_regwrite(device, REG_MH_CLNT_INTF_CTRL_CONFIG1,
-				 0x00032f07);
-	}
-
 	adreno_regwrite(device, REG_SQ_VS_PROGRAM, 0x00000000);
 	adreno_regwrite(device, REG_SQ_PS_PROGRAM, 0x00000000);
 
@@ -552,9 +560,9 @@
 
 error_irq_off:
 	kgsl_pwrctrl_irq(device, KGSL_PWRFLAGS_OFF);
+	kgsl_mmu_stop(device);
 error_clk_off:
 	kgsl_pwrctrl_disable(device);
-	kgsl_mmu_stop(device);
 
 	return status;
 }
diff --git a/drivers/gpu/msm/adreno_debugfs.c b/drivers/gpu/msm/adreno_debugfs.c
index b897e10..85f45c1 100644
--- a/drivers/gpu/msm/adreno_debugfs.c
+++ b/drivers/gpu/msm/adreno_debugfs.c
@@ -396,8 +396,8 @@
 	int j;
 
 	for (j = 0; j < linec; ++j) {
-		kgsl_regwrite(device, REG_MH_DEBUG_CTRL, i+j);
-		kgsl_regread(device, REG_MH_DEBUG_DATA, vals+j);
+		kgsl_regwrite(device, MH_DEBUG_CTRL, i+j);
+		kgsl_regread(device, MH_DEBUG_DATA, vals+j);
 	}
 }
 
diff --git a/drivers/gpu/msm/kgsl_device.h b/drivers/gpu/msm/kgsl_device.h
index 692a9ec..afe3a6d 100644
--- a/drivers/gpu/msm/kgsl_device.h
+++ b/drivers/gpu/msm/kgsl_device.h
@@ -109,6 +109,15 @@
 	unsigned int sizebytes;
 };
 
+/* MH register values */
+struct kgsl_mh {
+	unsigned int     mharb;
+	unsigned int     mh_intf_cfg1;
+	unsigned int     mh_intf_cfg2;
+	uint32_t         mpu_base;
+	int              mpu_range;
+};
+
 struct kgsl_device {
 	struct device *dev;
 	const char *name;
@@ -120,6 +129,7 @@
 	struct kgsl_memdesc memstore;
 	const char *iomemname;
 
+	struct kgsl_mh mh;
 	struct kgsl_mmu mmu;
 	struct completion hwaccess_gate;
 	const struct kgsl_functable *ftbl;
diff --git a/drivers/gpu/msm/kgsl_mmu.c b/drivers/gpu/msm/kgsl_mmu.c
index 15ec0ec..22c3467 100644
--- a/drivers/gpu/msm/kgsl_mmu.c
+++ b/drivers/gpu/msm/kgsl_mmu.c
@@ -591,6 +591,31 @@
 	return ret;
 }
 
+void kgsl_mmu_pagefault(struct kgsl_device *device)
+{
+	unsigned int reg;
+	unsigned int ptbase;
+	struct kgsl_pagetable *pt;
+	int ptid = -1;
+
+	kgsl_regread(device, MH_MMU_PAGE_FAULT, &reg);
+	kgsl_regread(device, MH_MMU_PT_BASE, &ptbase);
+
+	spin_lock(&kgsl_driver.ptlock);
+	list_for_each_entry(pt, &kgsl_driver.pagetable_list, list) {
+		if (ptbase == pt->base.gpuaddr) {
+			ptid = (int) pt->name;
+			break;
+		}
+	}
+	spin_unlock(&kgsl_driver.ptlock);
+
+	KGSL_MEM_CRIT(device,
+			"mmu page fault: page=0x%lx pt=%d op=%s axi=%d\n",
+			reg & ~(PAGE_SIZE - 1), ptid,
+			reg & 0x02 ? "WRITE" : "READ", (reg >> 4) & 0xF);
+}
+
 void kgsl_mh_intrcallback(struct kgsl_device *device)
 {
 	unsigned int status = 0;
@@ -601,39 +626,12 @@
 
 	if (status & MH_INTERRUPT_MASK__AXI_READ_ERROR)
 		KGSL_MEM_CRIT(device, "axi read error interrupt: %08x\n", reg);
-	else if (status & MH_INTERRUPT_MASK__AXI_WRITE_ERROR)
+	if (status & MH_INTERRUPT_MASK__AXI_WRITE_ERROR)
 		KGSL_MEM_CRIT(device, "axi write error interrupt: %08x\n", reg);
-	else if (status & MH_INTERRUPT_MASK__MMU_PAGE_FAULT) {
-		unsigned int ptbase;
-		struct kgsl_pagetable *pt;
-		int ptid = -1;
-
-		kgsl_regread(device, MH_MMU_PAGE_FAULT, &reg);
-		kgsl_regread(device, MH_MMU_PT_BASE, &ptbase);
-
-		spin_lock(&kgsl_driver.ptlock);
-		list_for_each_entry(pt, &kgsl_driver.pagetable_list, list) {
-			if (ptbase == pt->base.gpuaddr) {
-				ptid = (int) pt->name;
-				break;
-			}
-		}
-		spin_unlock(&kgsl_driver.ptlock);
-
-		KGSL_MEM_CRIT(device,
-			"mmu page fault: page=0x%lx pt=%d op=%s axi=%d\n",
-			reg & ~(PAGE_SIZE - 1), ptid,
-			reg & 0x02 ? "WRITE" : "READ", (reg >> 4) & 0xF);
-	} else
-		KGSL_MEM_WARN(device,
-			"bad bits in REG_MH_INTERRUPT_STATUS %08x\n", status);
+	if (status & MH_INTERRUPT_MASK__MMU_PAGE_FAULT)
+		kgsl_mmu_pagefault(device);
 
 	kgsl_regwrite(device, MH_INTERRUPT_CLEAR, status);
-
-	/*TODO: figure out how to handle errror interupts.
-	* specifically, page faults should probably nuke the client that
-	* caused them, but we don't have enough info to figure that out yet.
-	*/
 }
 EXPORT_SYMBOL(kgsl_mh_intrcallback);
 
@@ -826,8 +824,8 @@
 	mmu->device = device;
 
 	/* make sure aligned to pagesize */
-	BUG_ON(mmu->mpu_base & (PAGE_SIZE - 1));
-	BUG_ON((mmu->mpu_base + mmu->mpu_range) & (PAGE_SIZE - 1));
+	BUG_ON(device->mh.mpu_base & (PAGE_SIZE - 1));
+	BUG_ON((device->mh.mpu_base + device->mh.mpu_range) & (PAGE_SIZE - 1));
 
 	/* sub-client MMU lookups require address translation */
 	if ((mmu->config & ~0x1) > 0) {
@@ -846,6 +844,33 @@
 	return status;
 }
 
+void kgsl_mh_start(struct kgsl_device *device)
+{
+	struct kgsl_mh *mh = &device->mh;
+	/* force mmu off to for now*/
+	kgsl_regwrite(device, MH_MMU_CONFIG, 0);
+	kgsl_idle(device,  KGSL_TIMEOUT_DEFAULT);
+
+	/* define physical memory range accessible by the core */
+	kgsl_regwrite(device, MH_MMU_MPU_BASE, mh->mpu_base);
+	kgsl_regwrite(device, MH_MMU_MPU_END,
+			mh->mpu_base + mh->mpu_range);
+	kgsl_regwrite(device, MH_ARBITER_CONFIG, mh->mharb);
+
+	if (mh->mh_intf_cfg1 != 0)
+		kgsl_regwrite(device, MH_CLNT_INTF_CTRL_CONFIG1,
+				mh->mh_intf_cfg1);
+
+	if (mh->mh_intf_cfg2 != 0)
+		kgsl_regwrite(device, MH_CLNT_INTF_CTRL_CONFIG2,
+				mh->mh_intf_cfg2);
+
+	/*
+	 * Interrupts are enabled on a per-device level when
+	 * kgsl_pwrctrl_irq() is called
+	 */
+}
+
 int kgsl_mmu_start(struct kgsl_device *device)
 {
 	/*
@@ -858,61 +883,38 @@
 
 	if (mmu->flags & KGSL_FLAGS_STARTED)
 		return 0;
-
-	/* MMU not enabled */
-	if ((mmu->config & 0x1) == 0)
-		return 0;
-
-	mmu->flags |= KGSL_FLAGS_STARTED;
-
 	/* setup MMU and sub-client behavior */
 	kgsl_regwrite(device, MH_MMU_CONFIG, mmu->config);
-
-	/*
-	 * Interrupts are enabled on a per-device level when
-	 * kgsl_pwrctrl_irq() is called
-	*/
-
-	/* idle device */
 	kgsl_idle(device,  KGSL_TIMEOUT_DEFAULT);
 
-	/* define physical memory range accessible by the core */
-	kgsl_regwrite(device, MH_MMU_MPU_BASE, mmu->mpu_base);
-	kgsl_regwrite(device, MH_MMU_MPU_END,
-			mmu->mpu_base + mmu->mpu_range);
+	kgsl_sharedmem_set(&mmu->dummyspace, 0, 0,
+			mmu->dummyspace.size);
 
-	/* sub-client MMU lookups require address translation */
-	if ((mmu->config & ~0x1) > 0) {
-
-		kgsl_sharedmem_set(&mmu->dummyspace, 0, 0,
-				   mmu->dummyspace.size);
-
-		/* TRAN_ERROR needs a 32 byte (32 byte aligned) chunk of memory
-		 * to complete transactions in case of an MMU fault. Note that
-		 * we'll leave the bottom 32 bytes of the dummyspace for other
-		 * purposes (e.g. use it when dummy read cycles are needed
-		 * for other blocks */
-		kgsl_regwrite(device, MH_MMU_TRAN_ERROR,
+	/* TRAN_ERROR needs a 32 byte (32 byte aligned) chunk of memory
+	 * to complete transactions in case of an MMU fault. Note that
+	 * we'll leave the bottom 32 bytes of the dummyspace for other
+	 * purposes (e.g. use it when dummy read cycles are needed
+	 * for other blocks */
+	kgsl_regwrite(device, MH_MMU_TRAN_ERROR,
 			mmu->dummyspace.physaddr + 32);
 
-		if (mmu->defaultpagetable == NULL)
-			mmu->defaultpagetable =
-				kgsl_mmu_getpagetable(KGSL_MMU_GLOBAL_PT);
+	if (mmu->defaultpagetable == NULL)
+		mmu->defaultpagetable =
+			kgsl_mmu_getpagetable(KGSL_MMU_GLOBAL_PT);
 
-		/* Return error if the default pagetable doesn't exist */
-		if (mmu->defaultpagetable == NULL)
-			return -ENOMEM;
+	/* Return error if the default pagetable doesn't exist */
+	if (mmu->defaultpagetable == NULL)
+		return -ENOMEM;
 
-		mmu->hwpagetable = mmu->defaultpagetable;
+	mmu->hwpagetable = mmu->defaultpagetable;
 
-		kgsl_regwrite(device, MH_MMU_PT_BASE,
-			      mmu->hwpagetable->base.gpuaddr);
-		kgsl_regwrite(device, MH_MMU_VA_RANGE,
-			      (mmu->hwpagetable->va_base |
-			      (mmu->hwpagetable->va_range >> 16)));
-		kgsl_setstate(device, KGSL_MMUFLAGS_TLBFLUSH);
-	}
-
+	kgsl_regwrite(device, MH_MMU_PT_BASE,
+			mmu->hwpagetable->base.gpuaddr);
+	kgsl_regwrite(device, MH_MMU_VA_RANGE,
+			(mmu->hwpagetable->va_base |
+			 (mmu->hwpagetable->va_range >> 16)));
+	kgsl_setstate(device, KGSL_MMUFLAGS_TLBFLUSH);
+	mmu->flags |= KGSL_FLAGS_STARTED;
 	return 0;
 }
 EXPORT_SYMBOL(kgsl_mmu_start);
@@ -1114,20 +1116,9 @@
 
 int kgsl_mmu_stop(struct kgsl_device *device)
 {
-	/*
-	 *  stop device mmu
-	 *
-	 *  call this with the global lock held
-	 */
 	struct kgsl_mmu *mmu = &device->mmu;
-
-	if (mmu->flags & KGSL_FLAGS_STARTED) {
-		/* disable MMU */
-		kgsl_regwrite(device, MH_MMU_CONFIG, 0x00000000);
-
-		mmu->flags &= ~KGSL_FLAGS_STARTED;
-	}
-
+	kgsl_regwrite(device, MH_MMU_CONFIG, 0x00000000);
+	mmu->flags &= ~KGSL_FLAGS_STARTED;
 	return 0;
 }
 EXPORT_SYMBOL(kgsl_mmu_stop);
diff --git a/drivers/gpu/msm/kgsl_mmu.h b/drivers/gpu/msm/kgsl_mmu.h
index 3425277..775fb95 100644
--- a/drivers/gpu/msm/kgsl_mmu.h
+++ b/drivers/gpu/msm/kgsl_mmu.h
@@ -42,6 +42,12 @@
 #define MH_INTERRUPT_STATUS          0x0A43
 #define MH_INTERRUPT_CLEAR           0x0A44
 #define MH_AXI_ERROR                 0x0A45
+#define MH_ARBITER_CONFIG            0x0A40
+#define MH_DEBUG_CTRL                0x0A4E
+#define MH_DEBUG_DATA                0x0A4F
+#define MH_AXI_HALT_CONTROL          0x0A50
+#define MH_CLNT_INTF_CTRL_CONFIG1    0x0A54
+#define MH_CLNT_INTF_CTRL_CONFIG2    0x0A55
 
 /* MH_MMU_CONFIG bit definitions */
 
@@ -128,8 +134,6 @@
 	uint32_t      flags;
 	struct kgsl_device     *device;
 	unsigned int     config;
-	uint32_t        mpu_base;
-	int              mpu_range;
 	struct kgsl_memdesc    dummyspace;
 	/* current page table object being used by device mmu */
 	struct kgsl_pagetable  *defaultpagetable;
@@ -150,6 +154,9 @@
 
 struct kgsl_pagetable *kgsl_mmu_getpagetable(unsigned long name);
 
+void kgsl_mh_start(struct kgsl_device *device);
+void kgsl_mh_intrcallback(struct kgsl_device *device);
+
 #ifdef CONFIG_MSM_KGSL_MMU
 
 int kgsl_mmu_init(struct kgsl_device *device);
@@ -167,7 +174,6 @@
 		    struct kgsl_memdesc *memdesc);
 void kgsl_ptpool_destroy(struct kgsl_ptpool *pool);
 int kgsl_ptpool_init(struct kgsl_ptpool *pool, int ptsize, int entries);
-void kgsl_mh_intrcallback(struct kgsl_device *device);
 void kgsl_mmu_putpagetable(struct kgsl_pagetable *pagetable);
 unsigned int kgsl_virtaddr_to_physaddr(void *virtaddr);
 void kgsl_setstate(struct kgsl_device *device, uint32_t flags);
diff --git a/drivers/gpu/msm/z180.c b/drivers/gpu/msm/z180.c
index d56785d..7c0b6cc 100644
--- a/drivers/gpu/msm/z180.c
+++ b/drivers/gpu/msm/z180.c
@@ -134,14 +134,19 @@
 		.id = KGSL_DEVICE_2D0,
 		.ver_major = DRIVER_VERSION_MAJOR,
 		.ver_minor = DRIVER_VERSION_MINOR,
-		.mmu = {
-			.config = Z180_MMU_CONFIG,
+		.mh = {
+			.mharb = Z180_CFG_MHARB,
+			.mh_intf_cfg1 = 0x00032f07,
+			.mh_intf_cfg2 = 0x004b274f,
 			/* turn off memory protection unit by setting
 			   acceptable physical address range to include
 			   all pages. */
 			.mpu_base = 0x00000000,
 			.mpu_range =  0xFFFFF000,
 		},
+		.mmu = {
+			.config = Z180_MMU_CONFIG,
+		},
 		.pwrctrl = {
 			.regulator_name = "fs_gfx2d0",
 			.irq_name = KGSL_2D0_IRQ,
@@ -167,14 +172,19 @@
 		.id = KGSL_DEVICE_2D1,
 		.ver_major = DRIVER_VERSION_MAJOR,
 		.ver_minor = DRIVER_VERSION_MINOR,
-		.mmu = {
-			.config = Z180_MMU_CONFIG,
+		.mh = {
+			.mharb = Z180_CFG_MHARB,
+			.mh_intf_cfg1 = 0x00032f07,
+			.mh_intf_cfg2 = 0x004b274f,
 			/* turn off memory protection unit by setting
 			   acceptable physical address range to include
 			   all pages. */
 			.mpu_base = 0x00000000,
 			.mpu_range =  0xFFFFF000,
 		},
+		.mmu = {
+			.config = Z180_MMU_CONFIG,
+		},
 		.pwrctrl = {
 			.regulator_name = "fs_gfx2d1",
 			.irq_name = KGSL_2D1_IRQ,
@@ -546,16 +556,11 @@
 
 	kgsl_pwrctrl_enable(device);
 
-	/* Set up MH arbiter.  MH offsets are considered to be dword
-	 * based, therefore no down shift. */
-	z180_regwrite(device, ADDR_MH_ARBITER_CONFIG, Z180_CFG_MHARB);
-
-	z180_regwrite(device, ADDR_MH_CLNT_INTF_CTRL_CONFIG1, 0x00030F27);
-	z180_regwrite(device, ADDR_MH_CLNT_INTF_CTRL_CONFIG2, 0x004B274F);
-
 	/* Set interrupts to 0 to ensure a good state */
 	z180_regwrite(device, (ADDR_VGC_IRQENABLE >> 2), 0x0);
 
+	kgsl_mh_start(device);
+
 	status = kgsl_mmu_start(device);
 	if (status)
 		goto error_clk_off;
@@ -755,8 +760,8 @@
 	if (!in_interrupt())
 		kgsl_pre_hwaccess(device);
 
-	if ((offsetwords >= ADDR_MH_ARBITER_CONFIG &&
-	     offsetwords <= ADDR_MH_AXI_HALT_CONTROL) ||
+	if ((offsetwords >= MH_ARBITER_CONFIG &&
+	     offsetwords <= MH_AXI_HALT_CONTROL) ||
 	    (offsetwords >= MH_MMU_CONFIG &&
 	     offsetwords <= MH_MMU_MPU_END)) {
 		_z180_regread_mmu(device, offsetwords, value);
@@ -772,8 +777,8 @@
 	if (!in_interrupt())
 		kgsl_pre_hwaccess(device);
 
-	if ((offsetwords >= ADDR_MH_ARBITER_CONFIG &&
-	     offsetwords <= ADDR_MH_CLNT_INTF_CTRL_CONFIG2) ||
+	if ((offsetwords >= MH_ARBITER_CONFIG &&
+	     offsetwords <= MH_CLNT_INTF_CTRL_CONFIG2) ||
 	    (offsetwords >= MH_MMU_CONFIG &&
 	     offsetwords <= MH_MMU_MPU_END)) {
 		_z180_regwrite_mmu(device, offsetwords, value);
diff --git a/drivers/gpu/msm/z180_reg.h b/drivers/gpu/msm/z180_reg.h
index a3b0412..5b6c001 100644
--- a/drivers/gpu/msm/z180_reg.h
+++ b/drivers/gpu/msm/z180_reg.h
@@ -32,10 +32,6 @@
 #define	MH_ARBITER_CONFIG__RB_CLNT_ENABLE__SHIFT           0x00000019
 #define	MH_ARBITER_CONFIG__PA_CLNT_ENABLE__SHIFT           0x0000001a
 
-#define ADDR_MH_ARBITER_CONFIG           0x0A40
-#define ADDR_MH_AXI_HALT_CONTROL         0x0A50
-#define ADDR_MH_CLNT_INTF_CTRL_CONFIG1   0x0A54
-#define ADDR_MH_CLNT_INTF_CTRL_CONFIG2   0x0A55
 #define ADDR_VGC_MH_READ_ADDR            0x0510
 #define ADDR_VGC_MH_DATA_ADDR            0x0518
 #define ADDR_VGC_COMMANDSTREAM           0x0000