Merge "drm/msm/sde: Add reg dma programming support for vlut" into msm-4.8
diff --git a/drivers/gpu/drm/msm/Makefile b/drivers/gpu/drm/msm/Makefile
index 2713f67..e84f4ca 100644
--- a/drivers/gpu/drm/msm/Makefile
+++ b/drivers/gpu/drm/msm/Makefile
@@ -47,6 +47,7 @@
sde/sde_vbif.o \
sde_dbg_evtlog.o \
sde_io_util.o \
+ sde/sde_hw_reg_dma_v1_color_proc.o \
# use drm gpu driver only if qcom_kgsl driver not available
ifneq ($(CONFIG_QCOM_KGSL),y)
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_color_processing.h b/drivers/gpu/drm/msm/sde/sde_hw_color_processing.h
index a30e1a5..8ab2209 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_color_processing.h
+++ b/drivers/gpu/drm/msm/sde/sde_hw_color_processing.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -14,5 +14,6 @@
#define _SDE_HW_COLOR_PROCESSING_H
#include "sde_hw_color_processing_v1_7.h"
+#include "sde_hw_reg_dma_v1_color_proc.h"
#endif
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_dspp.c b/drivers/gpu/drm/msm/sde/sde_hw_dspp.c
index 66c03f0..f11c065 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_dspp.c
+++ b/drivers/gpu/drm/msm/sde/sde_hw_dspp.c
@@ -36,33 +36,9 @@
return ERR_PTR(-EINVAL);
}
-void sde_dspp_setup_histogram(struct sde_hw_dspp *ctx, void *cfg)
-{
-}
-
-void sde_dspp_read_histogram(struct sde_hw_dspp *ctx, void *cfg)
-{
-}
-
-void sde_dspp_update_igc(struct sde_hw_dspp *ctx, void *cfg)
-{
-}
-
-void sde_dspp_setup_sharpening(struct sde_hw_dspp *ctx, void *cfg)
-{
-}
-
-void sde_dspp_setup_danger_safe(struct sde_hw_dspp *ctx, void *cfg)
-{
-}
-
-void sde_dspp_setup_dither(struct sde_hw_dspp *ctx, void *cfg)
-{
-}
-
static void _setup_dspp_ops(struct sde_hw_dspp *c, unsigned long features)
{
- int i = 0;
+ int i = 0, ret;
for (i = 0; i < SDE_DSPP_MAX; i++) {
if (!test_bit(i, &features))
@@ -81,8 +57,16 @@
case SDE_DSPP_VLUT:
if (c->cap->sblk->vlut.version ==
(SDE_COLOR_PROCESS_VER(0x1, 0x7))) {
- c->ops.setup_vlut = sde_setup_dspp_pa_vlut_v1_7;
+ c->ops.setup_vlut =
+ sde_setup_dspp_pa_vlut_v1_7;
+ } else if (c->cap->sblk->vlut.version ==
+ (SDE_COLOR_PROCESS_VER(0x1, 0x8))) {
+ ret = reg_dmav1_init_dspp_op_v4(i, c->idx);
+ if (ret)
+ c->ops.setup_vlut =
+ reg_dmav1_setup_dspp_vlutv18;
}
+ break;
default:
break;
}
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_reg_dma_v1_color_proc.c b/drivers/gpu/drm/msm/sde/sde_hw_reg_dma_v1_color_proc.c
new file mode 100644
index 0000000..18986b2
--- /dev/null
+++ b/drivers/gpu/drm/msm/sde/sde_hw_reg_dma_v1_color_proc.c
@@ -0,0 +1,302 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+#include <drm/msm_drm_pp.h>
+#include "sde_reg_dma.h"
+#include "sde_hw_reg_dma_v1_color_proc.h"
+
+/* Reserve space of 128 words for LUT dma payload set-up */
+#define REG_DMA_HEADERS_BUFFER_SZ (sizeof(u32) * 128)
+
+#define VLUT_MEM_SIZE ((128 * sizeof(u32)) + REG_DMA_HEADERS_BUFFER_SZ)
+#define VLUT_LEN (128 * sizeof(u32))
+#define PA_OP_MODE_OFF 0x800
+#define PA_LUTV_OPMODE_OFF 0x84c
+
+#define GAMUT_LUT_MEM_SIZE ((sizeof(struct drm_msm_3d_gamut)) + \
+ REG_DMA_HEADERS_BUFFER_SZ)
+
+#define REG_MASK(n) ((BIT(n)) - 1)
+
+static struct sde_reg_dma_buffer *dspp_buf[REG_DMA_FEATURES_MAX][DSPP_MAX];
+
+static u32 feature_map[SDE_DSPP_MAX] = {
+ [SDE_DSPP_VLUT] = VLUT,
+ [SDE_DSPP_GAMUT] = GAMUT,
+ [SDE_DSPP_IGC] = REG_DMA_FEATURES_MAX,
+ [SDE_DSPP_PCC] = REG_DMA_FEATURES_MAX,
+ [SDE_DSPP_GC] = REG_DMA_FEATURES_MAX,
+ [SDE_DSPP_HSIC] = REG_DMA_FEATURES_MAX,
+ [SDE_DSPP_MEMCOLOR] = REG_DMA_FEATURES_MAX,
+ [SDE_DSPP_SIXZONE] = REG_DMA_FEATURES_MAX,
+ [SDE_DSPP_DITHER] = REG_DMA_FEATURES_MAX,
+ [SDE_DSPP_HIST] = REG_DMA_FEATURES_MAX,
+ [SDE_DSPP_AD] = REG_DMA_FEATURES_MAX,
+};
+
+static u32 feature_reg_dma_sz[SDE_DSPP_MAX] = {
+ [SDE_DSPP_VLUT] = VLUT_MEM_SIZE,
+ [SDE_DSPP_GAMUT] = GAMUT_LUT_MEM_SIZE,
+};
+
+static u32 dspp_mapping[DSPP_MAX] = {
+ [DSPP_0] = DSPP0,
+ [DSPP_1] = DSPP1,
+ [DSPP_2] = DSPP2,
+ [DSPP_3] = DSPP3,
+};
+
+#define REG_DMA_OP_SETUP(cfg, block, reg_dma_feature, op, buf) \
+ do { \
+ (cfg).blk = block; \
+ (cfg).feature = reg_dma_feature; \
+ (cfg).ops = op; \
+ (cfg).dma_buf = buf; \
+ } while (0)
+
+static int reg_dma_buf_init(struct sde_reg_dma_buffer **buf, u32 sz);
+static int reg_dma_dspp_check(struct sde_hw_dspp *ctx, void *cfg,
+ enum sde_reg_dma_features feature);
+static int reg_dma_blk_select(enum sde_reg_dma_features feature,
+ enum sde_reg_dma_blk blk, struct sde_reg_dma_buffer *dma_buf);
+static int reg_dma_write(enum sde_reg_dma_setup_ops ops, u32 off, u32 data_sz,
+ u32 *data, struct sde_reg_dma_buffer *dma_buf,
+ enum sde_reg_dma_features feature,
+ enum sde_reg_dma_blk blk);
+static int reg_dma_kick_off(enum sde_reg_dma_op op, enum sde_reg_dma_queue q,
+ enum sde_reg_dma_trigger_mode mode,
+ struct sde_reg_dma_buffer *dma_buf, struct sde_hw_ctl *ctl);
+
+
+static int reg_dma_buf_init(struct sde_reg_dma_buffer **buf, u32 size)
+{
+ struct sde_hw_reg_dma_ops *dma_ops;
+
+ dma_ops = sde_reg_dma_get_ops();
+ if (IS_ERR_OR_NULL(dma_ops))
+ return -ENOTSUPP;
+
+ if (!buf) {
+ DRM_ERROR("invalid buf\n");
+ return -EINVAL;
+ }
+
+ /* buffer already initialized */
+ if (*buf)
+ return 0;
+
+ *buf = dma_ops->alloc_reg_dma_buf(size);
+ if (IS_ERR_OR_NULL(*buf))
+ return -EINVAL;
+
+ return 0;
+}
+
+static int reg_dma_dspp_check(struct sde_hw_dspp *ctx, void *cfg,
+ enum sde_reg_dma_features feature)
+{
+ struct sde_hw_reg_dma_ops *dma_ops;
+ struct sde_hw_cp_cfg *hw_cfg = cfg;
+
+ if (!cfg || !ctx) {
+ DRM_ERROR("invalid cfg %pK ctx %pK\n", cfg, ctx);
+ return -EINVAL;
+ }
+
+ dma_ops = sde_reg_dma_get_ops();
+ if (IS_ERR_OR_NULL(dma_ops))
+ return -EINVAL;
+
+ if (!hw_cfg->ctl || ctx->idx >= DSPP_MAX ||
+ feature >= REG_DMA_FEATURES_MAX) {
+ DRM_ERROR("invalid ctl %pK dspp idx %d feature %d\n",
+ hw_cfg->ctl, ctx->idx, feature);
+ return -EINVAL;
+ }
+
+ if (!dspp_buf[feature][ctx->idx]) {
+ DRM_ERROR("invalid dma_buf\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+
+static int reg_dma_blk_select(enum sde_reg_dma_features feature,
+ enum sde_reg_dma_blk blk, struct sde_reg_dma_buffer *dma_buf)
+{
+ struct sde_hw_reg_dma_ops *dma_ops;
+ struct sde_reg_dma_setup_ops_cfg dma_write_cfg;
+ int rc = 0;
+
+ dma_ops = sde_reg_dma_get_ops();
+ dma_ops->reset_reg_dma_buf(dma_buf);
+ memset(&dma_write_cfg, 0, sizeof(dma_write_cfg));
+ dma_write_cfg.blk = blk;
+ dma_write_cfg.feature = feature;
+ dma_write_cfg.ops = HW_BLK_SELECT;
+ dma_write_cfg.dma_buf = dma_buf;
+
+ rc = dma_ops->setup_payload(&dma_write_cfg);
+ if (rc)
+ DRM_ERROR("write decode select failed ret %d\n", rc);
+
+ return rc;
+}
+
+static int reg_dma_write(enum sde_reg_dma_setup_ops ops, u32 off, u32 data_sz,
+ u32 *data, struct sde_reg_dma_buffer *dma_buf,
+ enum sde_reg_dma_features feature,
+ enum sde_reg_dma_blk blk)
+{
+ struct sde_hw_reg_dma_ops *dma_ops;
+ struct sde_reg_dma_setup_ops_cfg dma_write_cfg;
+ int rc;
+
+ dma_ops = sde_reg_dma_get_ops();
+ memset(&dma_write_cfg, 0, sizeof(dma_write_cfg));
+
+ dma_write_cfg.ops = ops;
+ dma_write_cfg.blk_offset = off;
+ dma_write_cfg.data_size = data_sz;
+ dma_write_cfg.data = data;
+ dma_write_cfg.dma_buf = dma_buf;
+ dma_write_cfg.feature = feature;
+ dma_write_cfg.blk = blk;
+ rc = dma_ops->setup_payload(&dma_write_cfg);
+ if (rc)
+ DRM_ERROR("write single reg failed ret %d\n", rc);
+
+ return rc;
+}
+
+static int reg_dma_kick_off(enum sde_reg_dma_op op, enum sde_reg_dma_queue q,
+ enum sde_reg_dma_trigger_mode mode,
+ struct sde_reg_dma_buffer *dma_buf, struct sde_hw_ctl *ctl)
+{
+ struct sde_reg_dma_kickoff_cfg kick_off;
+ struct sde_hw_reg_dma_ops *dma_ops;
+ int rc;
+
+ dma_ops = sde_reg_dma_get_ops();
+ memset(&kick_off, 0, sizeof(kick_off));
+ kick_off.ctl = ctl;
+ kick_off.dma_buf = dma_buf;
+ kick_off.op = op;
+ kick_off.queue_select = q;
+ kick_off.trigger_mode = mode;
+ rc = dma_ops->kick_off(&kick_off);
+ if (rc)
+ DRM_ERROR("failed to kick off ret %d\n", rc);
+
+ return rc;
+}
+
+int reg_dmav1_init_dspp_op_v4(int feature, enum sde_dspp idx)
+{
+ int rc = -ENOTSUPP;
+ struct sde_hw_reg_dma_ops *dma_ops;
+ bool is_supported = false;
+
+ if (feature >= SDE_DSPP_MAX || idx >= DSPP_MAX) {
+ DRM_ERROR("invalid feature %x max %x dspp idx %x max %xd\n",
+ feature, SDE_DSPP_MAX, idx, DSPP_MAX);
+ return rc;
+ }
+
+ if (feature_map[feature] >= REG_DMA_FEATURES_MAX) {
+ DRM_ERROR("invalid feature map %d for feature %d\n",
+ feature_map[feature], feature);
+ return -ENOTSUPP;
+ }
+
+ dma_ops = sde_reg_dma_get_ops();
+ if (IS_ERR_OR_NULL(dma_ops))
+ return -ENOTSUPP;
+
+ rc = dma_ops->check_support(feature_map[feature], dspp_mapping[idx],
+ &is_supported);
+ if (!rc)
+ rc = (is_supported) ? 0 : -ENOTSUPP;
+
+ if (!rc)
+ rc = reg_dma_buf_init(&dspp_buf[feature_map[feature]][idx],
+ feature_reg_dma_sz[feature]);
+
+ return rc;
+}
+
+int reg_dmav1_init_sspp_op_v4(int feature, enum sde_sspp idx)
+{
+ return -ENOTSUPP;
+}
+
+void reg_dmav1_setup_dspp_vlutv18(struct sde_hw_dspp *ctx, void *cfg)
+{
+ struct drm_msm_pa_vlut *payload = NULL;
+ struct sde_hw_cp_cfg *hw_cfg = cfg;
+ u32 op_mode;
+ u32 *data = NULL;
+ int i, j, rc = 0;
+
+ rc = reg_dma_dspp_check(ctx, cfg, VLUT);
+ if (rc)
+ return;
+
+ op_mode = SDE_REG_READ(&ctx->hw, PA_OP_MODE_OFF);
+ if (!hw_cfg->payload) {
+ DRM_DEBUG_DRIVER("Disable vlut feature\n");
+ SDE_REG_WRITE(&ctx->hw, PA_LUTV_OPMODE_OFF, 0);
+ if (op_mode & (~(BIT(20))))
+ op_mode = 0;
+ SDE_REG_WRITE(&ctx->hw, PA_OP_MODE_OFF, op_mode);
+ return;
+ }
+
+ rc = reg_dma_blk_select(VLUT, dspp_mapping[ctx->idx],
+ dspp_buf[VLUT][ctx->idx]);
+ if (rc) {
+ DRM_ERROR("write decode select failed ret %d\n", rc);
+ return;
+ }
+
+ data = kzalloc(VLUT_LEN, GFP_KERNEL);
+ if (!data)
+ return;
+
+ payload = hw_cfg->payload;
+ DRM_DEBUG_DRIVER("Enable vlut feature flags %llx\n", payload->flags);
+ for (i = 0, j = 0; i < ARRAY_SIZE(payload->val); i += 2, j++)
+ data[j] = (payload->val[i] & REG_MASK(10)) |
+ ((payload->val[i + 1] & REG_MASK(10)) << 16);
+
+ rc = reg_dma_write(REG_BLK_WRITE_SINGLE, ctx->cap->sblk->vlut.base,
+ VLUT_LEN, data,
+ dspp_buf[VLUT][ctx->idx], VLUT,
+ dspp_mapping[ctx->idx]);
+ if (rc) {
+ DRM_ERROR("write single reg failed ret %d\n", rc);
+ goto exit;
+ }
+
+ rc = reg_dma_kick_off(REG_DMA_WRITE, DMA_CTL_QUEUE0, WRITE_IMMEDIATE,
+ dspp_buf[VLUT][ctx->idx], hw_cfg->ctl);
+ if (rc) {
+ DRM_ERROR("failed to kick off ret %d\n", rc);
+ goto exit;
+ }
+ SDE_REG_WRITE(&ctx->hw, PA_LUTV_OPMODE_OFF, BIT(0));
+ SDE_REG_WRITE(&ctx->hw, PA_OP_MODE_OFF, op_mode | BIT(20));
+
+exit:
+ kfree(data);
+}
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_reg_dma_v1_color_proc.h b/drivers/gpu/drm/msm/sde/sde_hw_reg_dma_v1_color_proc.h
new file mode 100644
index 0000000..b82267c
--- /dev/null
+++ b/drivers/gpu/drm/msm/sde/sde_hw_reg_dma_v1_color_proc.h
@@ -0,0 +1,41 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+#ifndef _SDE_HW_REG_DMA_V1_COLOR_PROC_H
+#define _SDE_HW_REG_DMA_V1_COLOR_PROC_H
+
+#include "sde_hw_util.h"
+#include "sde_hw_catalog.h"
+#include "sde_hw_dspp.h"
+
+/**
+ * reg_dmav1_init_dspp_op_v4() - initialize the dspp feature op for sde v4
+ * using reg dma v1.
+ * @feature: dspp feature
+ * idx: dspp idx
+ */
+int reg_dmav1_init_dspp_op_v4(int feature, enum sde_dspp idx);
+
+/**
+ * reg_dma_init_sspp_op_v4() - initialize the sspp feature op for sde v4
+ * @feature: sspp feature
+ * @idx: sspp idx
+ */
+int reg_dmav1_init_sspp_op_v4(int feature, enum sde_sspp idx);
+
+/**
+ * reg_dmav1_setup_dspp_vlutv18() - vlut v18 implementation using reg dma v1.
+ * @ctx: dspp ctx info
+ * @cfg: pointer to struct sde_hw_cp_cfg
+ */
+void reg_dmav1_setup_dspp_vlutv18(struct sde_hw_dspp *ctx, void *cfg);
+
+#endif /* _SDE_HW_REG_DMA_V1_COLOR_PROC_H */