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, ®);
+ 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, ®);
- 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