msm: kgsl: Add support for GBIF for A615 GPU
Add initial version of GBIF changes for A615
to handle perf and power counters on SDM670.
Change-Id: I0408c3b7b84c1c259501c70c9674c6d2386f1a30
Signed-off-by: Rajesh Kemisetti <rajeshk@codeaurora.org>
diff --git a/drivers/gpu/msm/a6xx_reg.h b/drivers/gpu/msm/a6xx_reg.h
index e112fd1..5dbfbda 100644
--- a/drivers/gpu/msm/a6xx_reg.h
+++ b/drivers/gpu/msm/a6xx_reg.h
@@ -764,6 +764,29 @@
#define A6XX_VBIF_PERF_PWR_CNT_HIGH1 0x3119
#define A6XX_VBIF_PERF_PWR_CNT_HIGH2 0x311a
+/* GBIF registers */
+#define A6XX_GBIF_HALT 0x3c45
+#define A6XX_GBIF_HALT_ACK 0x3c46
+#define A6XX_GBIF_HALT_MASK 0x1
+
+#define A6XX_GBIF_PERF_PWR_CNT_EN 0x3cc0
+#define A6XX_GBIF_PERF_CNT_SEL 0x3cc2
+#define A6XX_GBIF_PERF_CNT_LOW0 0x3cc4
+#define A6XX_GBIF_PERF_CNT_LOW1 0x3cc5
+#define A6XX_GBIF_PERF_CNT_LOW2 0x3cc6
+#define A6XX_GBIF_PERF_CNT_LOW3 0x3cc7
+#define A6XX_GBIF_PERF_CNT_HIGH0 0x3cc8
+#define A6XX_GBIF_PERF_CNT_HIGH1 0x3cc9
+#define A6XX_GBIF_PERF_CNT_HIGH2 0x3cca
+#define A6XX_GBIF_PERF_CNT_HIGH3 0x3ccb
+#define A6XX_GBIF_PWR_CNT_LOW0 0x3ccc
+#define A6XX_GBIF_PWR_CNT_LOW1 0x3ccd
+#define A6XX_GBIF_PWR_CNT_LOW2 0x3cce
+#define A6XX_GBIF_PWR_CNT_HIGH0 0x3ccf
+#define A6XX_GBIF_PWR_CNT_HIGH1 0x3cd0
+#define A6XX_GBIF_PWR_CNT_HIGH2 0x3cd1
+
+
/* CX_DBGC_CFG registers */
#define A6XX_CX_DBGC_CFG_DBGBUS_SEL_A 0x18400
#define A6XX_CX_DBGC_CFG_DBGBUS_SEL_B 0x18401
diff --git a/drivers/gpu/msm/adreno.h b/drivers/gpu/msm/adreno.h
index 8349a9f..0192acd 100644
--- a/drivers/gpu/msm/adreno.h
+++ b/drivers/gpu/msm/adreno.h
@@ -636,6 +636,8 @@
ADRENO_REG_VBIF_XIN_HALT_CTRL0,
ADRENO_REG_VBIF_XIN_HALT_CTRL1,
ADRENO_REG_VBIF_VERSION,
+ ADRENO_REG_GBIF_HALT,
+ ADRENO_REG_GBIF_HALT_ACK,
ADRENO_REG_GMU_AO_INTERRUPT_EN,
ADRENO_REG_GMU_AO_HOST_INTERRUPT_CLR,
ADRENO_REG_GMU_AO_HOST_INTERRUPT_STATUS,
@@ -1795,6 +1797,47 @@
kgsl_active_count_put(KGSL_DEVICE(adreno_dev));
}
+static inline bool adreno_has_gbif(struct adreno_device *adreno_dev)
+{
+ if (adreno_is_a615(adreno_dev))
+ return true;
+ else
+ return false;
+}
+
+/**
+ * adreno_wait_for_vbif_halt_ack() - wait for VBIF acknowledgment
+ * for given HALT request.
+ * @ack_reg: register offset to wait for acknowledge
+ */
+static inline int adreno_wait_for_vbif_halt_ack(struct kgsl_device *device,
+ int ack_reg)
+{
+ struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
+ struct adreno_gpudev *gpudev = ADRENO_GPU_DEVICE(adreno_dev);
+ unsigned long wait_for_vbif;
+ unsigned int mask = gpudev->vbif_xin_halt_ctrl0_mask;
+ unsigned int val;
+ int ret = 0;
+
+ /* wait for the transactions to clear */
+ wait_for_vbif = jiffies + msecs_to_jiffies(100);
+ while (1) {
+ adreno_readreg(adreno_dev, ack_reg,
+ &val);
+ if ((val & mask) == mask)
+ break;
+ if (time_after(jiffies, wait_for_vbif)) {
+ KGSL_DRV_ERR(device,
+ "Wait limit reached for VBIF XIN Halt\n");
+ ret = -ETIMEDOUT;
+ break;
+ }
+ }
+
+ return ret;
+}
+
/**
* adreno_vbif_clear_pending_transactions() - Clear transactions in VBIF pipe
* @device: Pointer to the device whose VBIF pipe is to be cleared
@@ -1805,26 +1848,20 @@
struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
struct adreno_gpudev *gpudev = ADRENO_GPU_DEVICE(adreno_dev);
unsigned int mask = gpudev->vbif_xin_halt_ctrl0_mask;
- unsigned int val;
- unsigned long wait_for_vbif;
int ret = 0;
- adreno_writereg(adreno_dev, ADRENO_REG_VBIF_XIN_HALT_CTRL0, mask);
- /* wait for the transactions to clear */
- wait_for_vbif = jiffies + msecs_to_jiffies(100);
- while (1) {
- adreno_readreg(adreno_dev,
- ADRENO_REG_VBIF_XIN_HALT_CTRL1, &val);
- if ((val & mask) == mask)
- break;
- if (time_after(jiffies, wait_for_vbif)) {
- KGSL_DRV_ERR(device,
- "Wait limit reached for VBIF XIN Halt\n");
- ret = -ETIMEDOUT;
- break;
- }
+ if (adreno_has_gbif(adreno_dev)) {
+ adreno_writereg(adreno_dev, ADRENO_REG_GBIF_HALT, mask);
+ ret = adreno_wait_for_vbif_halt_ack(device,
+ ADRENO_REG_GBIF_HALT_ACK);
+ adreno_writereg(adreno_dev, ADRENO_REG_GBIF_HALT, 0);
+ } else {
+ adreno_writereg(adreno_dev, ADRENO_REG_VBIF_XIN_HALT_CTRL0,
+ mask);
+ ret = adreno_wait_for_vbif_halt_ack(device,
+ ADRENO_REG_VBIF_XIN_HALT_CTRL1);
+ adreno_writereg(adreno_dev, ADRENO_REG_VBIF_XIN_HALT_CTRL0, 0);
}
- adreno_writereg(adreno_dev, ADRENO_REG_VBIF_XIN_HALT_CTRL0, 0);
return ret;
}
diff --git a/drivers/gpu/msm/adreno_a6xx.c b/drivers/gpu/msm/adreno_a6xx.c
index da168dc..87627f8 100644
--- a/drivers/gpu/msm/adreno_a6xx.c
+++ b/drivers/gpu/msm/adreno_a6xx.c
@@ -50,10 +50,15 @@
{0, 0},
};
-static const struct adreno_vbif_platform a6xx_vbif_platforms[] = {
- { adreno_is_a630, a630_vbif },
+static const struct adreno_vbif_data a615_gbif[] = {
+ {A6XX_RBBM_VBIF_CLIENT_QOS_CNTL, 0x3},
+ {0, 0},
};
+static const struct adreno_vbif_platform a6xx_vbif_platforms[] = {
+ { adreno_is_a630, a630_vbif },
+ { adreno_is_a615, a615_gbif },
+};
struct kgsl_hwcg_reg {
unsigned int off;
@@ -244,18 +249,6 @@
{ A6XX_RB_CONTEXT_SWITCH_GMEM_SAVE_RESTORE, 0x0 },
};
-static void a6xx_platform_setup(struct adreno_device *adreno_dev)
-{
- uint64_t addr;
- struct adreno_gpudev *gpudev = ADRENO_GPU_DEVICE(adreno_dev);
-
- /* Calculate SP local and private mem addresses */
- addr = ALIGN(ADRENO_UCHE_GMEM_BASE + adreno_dev->gmem_size, SZ_64K);
- adreno_dev->sp_local_gpuaddr = addr;
- adreno_dev->sp_pvt_gpuaddr = addr + SZ_64K;
- gpudev->vbif_xin_halt_ctrl0_mask = A6XX_VBIF_XIN_HALT_CTRL0_MASK;
-}
-
static void _update_always_on_regs(struct adreno_device *adreno_dev)
{
struct adreno_gpudev *gpudev = ADRENO_GPU_DEVICE(adreno_dev);
@@ -2690,6 +2683,27 @@
A6XX_VBIF_PERF_PWR_CNT_HIGH2, -1, A6XX_VBIF_PERF_PWR_CNT_EN2 },
};
+
+static struct adreno_perfcount_register a6xx_perfcounters_gbif[] = {
+ { KGSL_PERFCOUNTER_NOT_USED, 0, 0, A6XX_GBIF_PERF_CNT_LOW0,
+ A6XX_GBIF_PERF_CNT_HIGH0, -1, A6XX_GBIF_PERF_CNT_SEL },
+ { KGSL_PERFCOUNTER_NOT_USED, 0, 0, A6XX_GBIF_PERF_CNT_LOW1,
+ A6XX_GBIF_PERF_CNT_HIGH1, -1, A6XX_GBIF_PERF_CNT_SEL },
+ { KGSL_PERFCOUNTER_NOT_USED, 0, 0, A6XX_GBIF_PERF_CNT_LOW2,
+ A6XX_GBIF_PERF_CNT_HIGH2, -1, A6XX_GBIF_PERF_CNT_SEL },
+ { KGSL_PERFCOUNTER_NOT_USED, 0, 0, A6XX_GBIF_PERF_CNT_LOW3,
+ A6XX_GBIF_PERF_CNT_HIGH3, -1, A6XX_GBIF_PERF_CNT_SEL },
+};
+
+static struct adreno_perfcount_register a6xx_perfcounters_gbif_pwr[] = {
+ { KGSL_PERFCOUNTER_NOT_USED, 0, 0, A6XX_GBIF_PWR_CNT_LOW0,
+ A6XX_GBIF_PWR_CNT_HIGH0, -1, A6XX_GBIF_PERF_PWR_CNT_EN },
+ { KGSL_PERFCOUNTER_NOT_USED, 0, 0, A6XX_GBIF_PWR_CNT_LOW1,
+ A6XX_GBIF_PWR_CNT_HIGH1, -1, A6XX_GBIF_PERF_PWR_CNT_EN },
+ { KGSL_PERFCOUNTER_NOT_USED, 0, 0, A6XX_GBIF_PWR_CNT_LOW2,
+ A6XX_GBIF_PWR_CNT_HIGH2, -1, A6XX_GBIF_PERF_PWR_CNT_EN },
+};
+
static struct adreno_perfcount_register a6xx_perfcounters_pwr[] = {
{ KGSL_PERFCOUNTER_BROKEN, 0, 0, 0, 0, -1, 0 },
{ KGSL_PERFCOUNTER_NOT_USED, 0, 0,
@@ -2800,6 +2814,35 @@
return 0;
}
+static void a6xx_platform_setup(struct adreno_device *adreno_dev)
+{
+ uint64_t addr;
+ struct adreno_gpudev *gpudev = ADRENO_GPU_DEVICE(adreno_dev);
+
+ /* Calculate SP local and private mem addresses */
+ addr = ALIGN(ADRENO_UCHE_GMEM_BASE + adreno_dev->gmem_size, SZ_64K);
+ adreno_dev->sp_local_gpuaddr = addr;
+ adreno_dev->sp_pvt_gpuaddr = addr + SZ_64K;
+
+ if (adreno_has_gbif(adreno_dev)) {
+ a6xx_perfcounter_groups[KGSL_PERFCOUNTER_GROUP_VBIF].regs =
+ a6xx_perfcounters_gbif;
+ a6xx_perfcounter_groups[KGSL_PERFCOUNTER_GROUP_VBIF].reg_count
+ = ARRAY_SIZE(a6xx_perfcounters_gbif);
+
+ a6xx_perfcounter_groups[KGSL_PERFCOUNTER_GROUP_VBIF_PWR].regs =
+ a6xx_perfcounters_gbif_pwr;
+ a6xx_perfcounter_groups[KGSL_PERFCOUNTER_GROUP_VBIF].reg_count
+ = ARRAY_SIZE(a6xx_perfcounters_gbif_pwr);
+
+ gpudev->vbif_xin_halt_ctrl0_mask =
+ A6XX_GBIF_HALT_MASK;
+ } else
+ gpudev->vbif_xin_halt_ctrl0_mask =
+ A6XX_VBIF_XIN_HALT_CTRL0_MASK;
+}
+
+
/* Register offset defines for A6XX, in order of enum adreno_regs */
static unsigned int a6xx_register_offsets[ADRENO_REG_REGISTER_MAX] = {
@@ -2859,6 +2902,8 @@
A6XX_VBIF_XIN_HALT_CTRL0),
ADRENO_REG_DEFINE(ADRENO_REG_VBIF_XIN_HALT_CTRL1,
A6XX_VBIF_XIN_HALT_CTRL1),
+ ADRENO_REG_DEFINE(ADRENO_REG_GBIF_HALT, A6XX_GBIF_HALT),
+ ADRENO_REG_DEFINE(ADRENO_REG_GBIF_HALT_ACK, A6XX_GBIF_HALT_ACK),
ADRENO_REG_DEFINE(ADRENO_REG_RBBM_ALWAYSON_COUNTER_LO,
A6XX_GMU_ALWAYS_ON_COUNTER_L),
ADRENO_REG_DEFINE(ADRENO_REG_RBBM_ALWAYSON_COUNTER_HI,
diff --git a/drivers/gpu/msm/adreno_a6xx_snapshot.c b/drivers/gpu/msm/adreno_a6xx_snapshot.c
index 880ee13..755fc7f 100644
--- a/drivers/gpu/msm/adreno_a6xx_snapshot.c
+++ b/drivers/gpu/msm/adreno_a6xx_snapshot.c
@@ -1357,6 +1357,7 @@
struct kgsl_snapshot *snapshot)
{
int i;
+ struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
kgsl_regwrite(device, A6XX_DBGC_CFG_DBGBUS_CNTLT,
(0xf << A6XX_DBGC_CFG_DBGBUS_CNTLT_SEGT_SHIFT) |
@@ -1447,9 +1448,12 @@
(void *) &a6xx_dbgc_debugbus_blocks[i]);
}
- kgsl_snapshot_add_section(device, KGSL_SNAPSHOT_SECTION_DEBUGBUS,
- snapshot, a6xx_snapshot_vbif_debugbus_block,
- (void *) &a6xx_vbif_debugbus_blocks);
+ /* Skip if GPU has GBIF */
+ if (!adreno_has_gbif(adreno_dev))
+ kgsl_snapshot_add_section(device,
+ KGSL_SNAPSHOT_SECTION_DEBUGBUS,
+ snapshot, a6xx_snapshot_vbif_debugbus_block,
+ (void *) &a6xx_vbif_debugbus_blocks);
if (a6xx_cx_dbgc) {
for (i = 0; i < ARRAY_SIZE(a6xx_cx_dbgc_debugbus_blocks); i++) {
@@ -1584,9 +1588,10 @@
snapshot, a6xx_snapshot_pre_crashdump_regs, NULL);
/* Dump vbif registers as well which get affected by crash dumper */
- adreno_snapshot_vbif_registers(device, snapshot,
- a6xx_vbif_snapshot_registers,
- ARRAY_SIZE(a6xx_vbif_snapshot_registers));
+ if (!adreno_has_gbif(adreno_dev))
+ adreno_snapshot_vbif_registers(device, snapshot,
+ a6xx_vbif_snapshot_registers,
+ ARRAY_SIZE(a6xx_vbif_snapshot_registers));
/* Try to run the crash dumper */
if (sptprac_on)
diff --git a/drivers/gpu/msm/adreno_perfcounter.c b/drivers/gpu/msm/adreno_perfcounter.c
index 0da4da9..dfce3eb 100644
--- a/drivers/gpu/msm/adreno_perfcounter.c
+++ b/drivers/gpu/msm/adreno_perfcounter.c
@@ -28,6 +28,20 @@
/* offset of enable register from select register */
#define VBIF2_PERF_EN_REG_SEL_OFF 16
+/* offset of clear register from select register for GBIF */
+#define GBIF_PERF_CLR_REG_SEL_OFF 1
+
+/* offset of enable register from select register for GBIF*/
+#define GBIF_PERF_EN_REG_SEL_OFF 2
+
+/* offset of clear register from the power enable register for GBIF*/
+#define GBIF_PWR_CLR_REG_EN_OFF 1
+
+/* */
+#define GBIF_PERF_RMW_MASK 0xFF
+/* */
+#define GBIF_PWR_RMW_MASK 0x10000
+
/* offset of clear register from the enable register */
#define VBIF2_PERF_PWR_CLR_REG_EN_OFF 8
@@ -612,14 +626,41 @@
{
struct kgsl_device *device = KGSL_DEVICE(adreno_dev);
struct adreno_perfcount_register *reg;
+ unsigned int shift = counter << 3;
reg = &counters->groups[KGSL_PERFCOUNTER_GROUP_VBIF].regs[counter];
- /* Write 1, followed by 0 to CLR register for clearing the counter */
- kgsl_regwrite(device, reg->select - VBIF2_PERF_CLR_REG_SEL_OFF, 1);
- kgsl_regwrite(device, reg->select - VBIF2_PERF_CLR_REG_SEL_OFF, 0);
- kgsl_regwrite(device, reg->select, countable & VBIF2_PERF_CNT_SEL_MASK);
- /* enable reg is 8 DWORDS before select reg */
- kgsl_regwrite(device, reg->select - VBIF2_PERF_EN_REG_SEL_OFF, 1);
+
+ if (adreno_has_gbif(adreno_dev)) {
+ /*
+ * Write 1, followed by 0 to CLR register for
+ * clearing the counter
+ */
+ kgsl_regrmw(device, reg->select - GBIF_PERF_CLR_REG_SEL_OFF,
+ 1 << counter, 1);
+ kgsl_regrmw(device, reg->select - GBIF_PERF_CLR_REG_SEL_OFF,
+ 1 << counter, 0);
+ /* select the desired countable */
+ kgsl_regrmw(device, reg->select,
+ GBIF_PERF_RMW_MASK << shift, countable << shift);
+ /* enable counter */
+ kgsl_regrmw(device, reg->select - GBIF_PERF_EN_REG_SEL_OFF,
+ 1 << counter, 1);
+
+ } else {
+ /*
+ * Write 1, followed by 0 to CLR register for
+ * clearing the counter
+ */
+ kgsl_regwrite(device,
+ reg->select - VBIF2_PERF_CLR_REG_SEL_OFF, 1);
+ kgsl_regwrite(device,
+ reg->select - VBIF2_PERF_CLR_REG_SEL_OFF, 0);
+ kgsl_regwrite(device,
+ reg->select, countable & VBIF2_PERF_CNT_SEL_MASK);
+ /* enable reg is 8 DWORDS before select reg */
+ kgsl_regwrite(device,
+ reg->select - VBIF2_PERF_EN_REG_SEL_OFF, 1);
+ }
reg->value = 0;
}
@@ -630,10 +671,30 @@
struct adreno_perfcount_register *reg;
reg = &counters->groups[KGSL_PERFCOUNTER_GROUP_VBIF_PWR].regs[counter];
- /* Write 1, followed by 0 to CLR register for clearing the counter */
- kgsl_regwrite(device, reg->select + VBIF2_PERF_PWR_CLR_REG_EN_OFF, 1);
- kgsl_regwrite(device, reg->select + VBIF2_PERF_PWR_CLR_REG_EN_OFF, 0);
- kgsl_regwrite(device, reg->select, 1);
+
+ if (adreno_has_gbif(adreno_dev)) {
+ /*
+ * Write 1, followed by 0 to CLR register for
+ * clearing the counter
+ */
+ kgsl_regrmw(device, reg->select + GBIF_PWR_CLR_REG_EN_OFF,
+ GBIF_PWR_RMW_MASK << counter, 1);
+ kgsl_regrmw(device, reg->select + GBIF_PWR_CLR_REG_EN_OFF,
+ GBIF_PWR_RMW_MASK << counter, 0);
+ /* Enable the counter */
+ kgsl_regrmw(device, reg->select,
+ GBIF_PWR_RMW_MASK << counter, 1);
+ } else {
+ /*
+ * Write 1, followed by 0 to CLR register for
+ * clearing the counter
+ */
+ kgsl_regwrite(device, reg->select +
+ VBIF2_PERF_PWR_CLR_REG_EN_OFF, 1);
+ kgsl_regwrite(device, reg->select +
+ VBIF2_PERF_PWR_CLR_REG_EN_OFF, 0);
+ kgsl_regwrite(device, reg->select, 1);
+ }
reg->value = 0;
}