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

Commit 8e2329dd authored by Linux Build Service Account's avatar Linux Build Service Account Committed by Gerrit - the friendly Code Review server
Browse files

Merge "drm/msm/sde: Add support to bump up data bus when needed for PP"

parents 962ef86f c51f40bd
Loading
Loading
Loading
Loading
+50 −0
Original line number Diff line number Diff line
@@ -25,6 +25,7 @@
#include "sde_hw_interrupts.h"
#include "sde_core_irq.h"
#include "dsi_panel.h"
#include "sde_hw_color_processing.h"

struct sde_cp_node {
	u32 property_id;
@@ -148,6 +149,24 @@ enum {
	SDE_CP_CRTC_MAX_FEATURES,
};

#define HIGH_BUS_VOTE_NEEDED(feature) ((feature == SDE_CP_CRTC_DSPP_IGC) |\
				 (feature == SDE_CP_CRTC_DSPP_GC) |\
				 (feature == SDE_CP_CRTC_DSPP_SIXZONE) |\
				 (feature == SDE_CP_CRTC_DSPP_GAMUT))

static u32 crtc_feature_map[SDE_CP_CRTC_MAX_FEATURES] = {
	[SDE_CP_CRTC_DSPP_IGC] = SDE_DSPP_IGC,
	[SDE_CP_CRTC_DSPP_PCC] = SDE_DSPP_PCC,
	[SDE_CP_CRTC_DSPP_GC] = SDE_DSPP_GC,
	[SDE_CP_CRTC_DSPP_MEMCOL_SKIN] = SDE_DSPP_MEMCOLOR,
	[SDE_CP_CRTC_DSPP_MEMCOL_SKY] = SDE_DSPP_MEMCOLOR,
	[SDE_CP_CRTC_DSPP_MEMCOL_FOLIAGE] = SDE_DSPP_MEMCOLOR,
	[SDE_CP_CRTC_DSPP_SIXZONE] = SDE_DSPP_SIXZONE,
	[SDE_CP_CRTC_DSPP_GAMUT] = SDE_DSPP_GAMUT,
	[SDE_CP_CRTC_DSPP_DITHER] = SDE_DSPP_DITHER,
	[SDE_CP_CRTC_DSPP_VLUT] = SDE_DSPP_VLUT,
};

#define INIT_PROP_ATTACH(p, crtc, prop, node, feature, val) \
	do { \
		(p)->crtc = crtc; \
@@ -859,6 +878,10 @@ void sde_cp_crtc_apply_properties(struct drm_crtc *crtc)
	struct sde_hw_ctl *ctl;
	uint32_t flush_mask = 0;
	u32 num_mixers = 0, i = 0;
	u32 sde_dspp_feature = SDE_DSPP_MAX;
	struct msm_drm_private *priv = NULL;
	struct sde_kms *sde_kms = NULL;
	bool mdss_bus_vote = false;

	if (!crtc || !crtc->dev) {
		DRM_ERROR("invalid crtc %pK dev %pK\n", crtc,
@@ -878,6 +901,17 @@ void sde_cp_crtc_apply_properties(struct drm_crtc *crtc)
		return;
	}

	priv = crtc->dev->dev_private;
	if (!priv || !priv->kms) {
		SDE_ERROR("invalid kms\n");
		return;
	}
	sde_kms = to_sde_kms(priv->kms);
	if (!sde_kms) {
		SDE_ERROR("invalid sde kms\n");
		return;
	}

	mutex_lock(&sde_crtc->crtc_cp_lock);

	/* Check if dirty lists are empty and ad features are disabled for
@@ -896,6 +930,16 @@ void sde_cp_crtc_apply_properties(struct drm_crtc *crtc)

	list_for_each_entry_safe(prop_node, n, &sde_crtc->dirty_list,
				dirty_list) {
		sde_dspp_feature = crtc_feature_map[prop_node->feature];
		if (!mdss_bus_vote && HIGH_BUS_VOTE_NEEDED(prop_node->feature)
			&& !reg_dmav1_dspp_feature_support(sde_dspp_feature)) {
			sde_power_scale_reg_bus(&priv->phandle,
				sde_kms->core_client,
				VOTE_INDEX_HIGH, false);
			pr_debug("Vote HIGH for data bus: feature %d\n",
					prop_node->feature);
			mdss_bus_vote = true;
		}
		sde_cp_crtc_setfeature(prop_node, sde_crtc);
		/* Set the flush flag to true */
		if (prop_node->is_dspp_feature)
@@ -903,6 +947,12 @@ void sde_cp_crtc_apply_properties(struct drm_crtc *crtc)
		else
			set_lm_flush = true;
	}
	if (mdss_bus_vote) {
		sde_power_scale_reg_bus(&priv->phandle, sde_kms->core_client,
			VOTE_INDEX_LOW, false);
		pr_debug("Vote LOW for data bus\n");
		mdss_bus_vote = false;
	}

	list_for_each_entry_safe(prop_node, n, &sde_crtc->ad_dirty,
				dirty_list) {
+27 −1
Original line number Diff line number Diff line
/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
/* Copyright (c) 2017-2018, 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
@@ -248,6 +248,32 @@ static int reg_dma_kick_off(enum sde_reg_dma_op op, enum sde_reg_dma_queue q,
	return rc;
}

bool reg_dmav1_dspp_feature_support(int feature)
{
	struct sde_hw_reg_dma_ops *dma_ops;
	bool is_supported = false;

	if (feature >= SDE_DSPP_MAX) {
		DRM_ERROR("invalid feature %x max %x\n",
			feature, SDE_DSPP_MAX);
		return is_supported;
	}

	if (feature_map[feature] >= REG_DMA_FEATURES_MAX) {
		DRM_ERROR("invalid feature map %d for feature %d\n",
			feature_map[feature], feature);
		return is_supported;
	}

	dma_ops = sde_reg_dma_get_ops();
	if (IS_ERR_OR_NULL(dma_ops))
		return is_supported;

	dma_ops->check_support(feature_map[feature], DSPP0, &is_supported);

	return is_supported;
}

int reg_dmav1_init_dspp_op_v4(int feature, enum sde_dspp idx)
{
	int rc = -ENOTSUPP;
+8 −1
Original line number Diff line number Diff line
/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
/* Copyright (c) 2017-2018, 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
@@ -24,6 +24,13 @@
 */
int reg_dmav1_init_dspp_op_v4(int feature, enum sde_dspp idx);

/**
 * reg_dmav1_dspp_feature_support() - check if dspp feature using REG_DMA
 *                                    or not.
 * @feature: dspp feature
 */
bool reg_dmav1_dspp_feature_support(int feature);

/**
 * reg_dma_init_sspp_op_v4() - initialize the sspp feature op for sde v4
 * @feature: sspp feature
+77 −7
Original line number Diff line number Diff line
/* Copyright (c) 2014-2017, The Linux Foundation. All rights reserved.
/* Copyright (c) 2014-2018, 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
@@ -844,6 +844,68 @@ void sde_power_resource_deinit(struct platform_device *pdev,
		sde_rsc_client_destroy(phandle->rsc_client);
}


int sde_power_scale_reg_bus(struct sde_power_handle *phandle,
	struct sde_power_client *pclient, u32 usecase_ndx, bool skip_lock)
{
	struct sde_power_client *client;
	int rc = 0;
	u32 max_usecase_ndx = VOTE_INDEX_DISABLE;

	if (!skip_lock) {
		mutex_lock(&phandle->phandle_lock);

		if (WARN_ON(pclient->refcount == 0)) {
			/*
			 * This is not expected, clients calling without skip
			 * lock are outside the power resource enable, which
			 * means that they should have enabled the power
			 * resource before trying to scale.
			 */
			rc = -EINVAL;
			goto exit;
		}
	}

	pr_debug("%pS: current idx:%d requested:%d client:%d\n",
		__builtin_return_address(0), pclient->usecase_ndx,
		usecase_ndx, pclient->id);

	pclient->usecase_ndx = usecase_ndx;

	list_for_each_entry(client, &phandle->power_client_clist, list) {
		if (client->usecase_ndx < VOTE_INDEX_MAX &&
		    client->usecase_ndx > max_usecase_ndx)
			max_usecase_ndx = client->usecase_ndx;
	}

	rc = sde_power_reg_bus_update(phandle->reg_bus_hdl,
						max_usecase_ndx);
	if (rc)
		pr_err("failed to set reg bus vote rc=%d\n", rc);

exit:
	if (!skip_lock)
		mutex_unlock(&phandle->phandle_lock);

	return rc;
}

static inline bool _resource_changed(u32 current_usecase_ndx,
		u32 max_usecase_ndx)
{
	WARN_ON((current_usecase_ndx >= VOTE_INDEX_MAX)
		|| (max_usecase_ndx >= VOTE_INDEX_MAX));

	if (((current_usecase_ndx >= VOTE_INDEX_LOW) && /*current enabled */
		(max_usecase_ndx == VOTE_INDEX_DISABLE)) || /* max disabled */
		((current_usecase_ndx == VOTE_INDEX_DISABLE) && /* disabled */
		(max_usecase_ndx >= VOTE_INDEX_LOW))) /* max enabled */
		return true;

	return false;
}

int sde_power_resource_enable(struct sde_power_handle *phandle,
	struct sde_power_client *pclient, bool enable)
{
@@ -877,7 +939,15 @@ int sde_power_resource_enable(struct sde_power_handle *phandle,
			max_usecase_ndx = client->usecase_ndx;
	}

	if (phandle->current_usecase_ndx != max_usecase_ndx) {
	/*
	 * Check if we need to enable/disable the power resource, we won't
	 * only-scale up/down the AHB vote in this API; if a client wants to
	 * bump up the AHB clock above the LOW (default) level, it needs to
	 * call 'sde_power_scale_reg_bus' with the desired vote after the power
	 * resource was enabled.
	 */
	if (_resource_changed(phandle->current_usecase_ndx,
			max_usecase_ndx)) {
		changed = true;
		prev_usecase_ndx = phandle->current_usecase_ndx;
		phandle->current_usecase_ndx = max_usecase_ndx;
@@ -920,8 +990,8 @@ int sde_power_resource_enable(struct sde_power_handle *phandle,
			}
		}

		rc = sde_power_reg_bus_update(phandle->reg_bus_hdl,
							max_usecase_ndx);
		rc = sde_power_scale_reg_bus(phandle, pclient,
				max_usecase_ndx, true);
		if (rc) {
			pr_err("failed to set reg bus vote rc=%d\n", rc);
			goto reg_bus_hdl_err;
@@ -952,8 +1022,8 @@ int sde_power_resource_enable(struct sde_power_handle *phandle,

		sde_power_rsc_update(phandle, false);

		sde_power_reg_bus_update(phandle->reg_bus_hdl,
							max_usecase_ndx);
		sde_power_scale_reg_bus(phandle, pclient,
				max_usecase_ndx, true);

		if (!phandle->rsc_client)
			msm_dss_enable_vreg(mp->vreg_config, mp->num_vreg,
@@ -975,7 +1045,7 @@ int sde_power_resource_enable(struct sde_power_handle *phandle,
clk_err:
	sde_power_rsc_update(phandle, false);
rsc_err:
	sde_power_reg_bus_update(phandle->reg_bus_hdl, prev_usecase_ndx);
	sde_power_scale_reg_bus(phandle, pclient, max_usecase_ndx, true);
reg_bus_hdl_err:
	if (!phandle->rsc_client)
		msm_dss_enable_vreg(mp->vreg_config, mp->num_vreg, 0);
+18 −1
Original line number Diff line number Diff line
/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
/* Copyright (c) 2016-2018, 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
@@ -43,11 +43,15 @@
 * mdss_bus_vote_type: register bus vote type
 * VOTE_INDEX_DISABLE: removes the client vote
 * VOTE_INDEX_LOW: keeps the lowest vote for register bus
 * VOTE_INDEX_MEDIUM: keeps medium vote for register bus
 * VOTE_INDEX_HIGH: keeps the highest vote for register bus
 * VOTE_INDEX_MAX: invalid
 */
enum mdss_bus_vote_type {
	VOTE_INDEX_DISABLE,
	VOTE_INDEX_LOW,
	VOTE_INDEX_MEDIUM,
	VOTE_INDEX_HIGH,
	VOTE_INDEX_MAX,
};

@@ -227,6 +231,19 @@ void sde_power_client_destroy(struct sde_power_handle *phandle,
int sde_power_resource_enable(struct sde_power_handle *pdata,
	struct sde_power_client *pclient, bool enable);

/**
 * sde_power_scale_reg_bus() - Scale the registers bus for the specified client
 * @pdata:  power handle containing the resources
 * @client: client information to scale its vote
 * @usecase_ndx: new use case to scale the reg bus
 * @skip_lock: will skip holding the power rsrc mutex during the call, this is
 *		for internal callers that already hold this required lock.
 *
 * Return: error code.
 */
int sde_power_scale_reg_bus(struct sde_power_handle *phandle,
	struct sde_power_client *pclient, u32 usecase_ndx, bool skip_lock);

/**
 * sde_power_resource_is_enabled() - return true if power resource is enabled
 * @pdata:  power handle containing the resources