Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit ed189cd0 authored by Gopikrishnaiah Anandan's avatar Gopikrishnaiah Anandan
Browse files

drm/msm/sde: Add reg dma programming support for vlut



If platform supports reg dma feature, dspp lut programming can be done
through axi interface. Change adds support to dynamically check for reg
dma presence and install appropriate ops during driver probe.

Change-Id: I6d9dc268d3422b80870ed6249ec086d9e3ae5c8b
Signed-off-by: default avatarGopikrishnaiah Anandan <agopik@codeaurora.org>
parent 7e3e3f5e
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -47,6 +47,7 @@ msm_drm-y := \
	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)
+2 −1
Original line number Diff line number Diff line
/* 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
+10 −26
Original line number Diff line number Diff line
@@ -36,33 +36,9 @@ static struct sde_dspp_cfg *_dspp_offset(enum sde_dspp dspp,
	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 @@ static void _setup_dspp_ops(struct sde_hw_dspp *c, unsigned long features)
		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;
		}
+302 −0
Original line number Diff line number Diff line
/* 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);
}
+41 −0
Original line number Diff line number Diff line
/* 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 */