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

Commit 6cb205cb authored by Yuan Zhao's avatar Yuan Zhao Committed by Gerrit - the friendly Code Review server
Browse files

disp: msm: sde: migrated new sde icb bus scaling driver for lahaina



Migrate to icb framework API in drm and sde driver. And
also removes old msm_bus custom APIs from the driver.

Change-Id: Ifcf6d6f157594638075742fe328b29a9be065bca
Signed-off-by: default avatarYuan Zhao <yzhao@codeaurora.org>
parent b7d71e15
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -19,6 +19,7 @@
#define pr_fmt(fmt)	"[drm:%s:%d] " fmt, __func__, __LINE__
#include <linux/kthread.h>
#include <linux/debugfs.h>
#include <linux/input.h>
#include <linux/seq_file.h>
#include <linux/sde_rsc.h>

+0 −1
Original line number Diff line number Diff line
@@ -10,7 +10,6 @@
#include <linux/bug.h>
#include <linux/bitmap.h>
#include <linux/err.h>
#include <linux/msm-bus.h>
#include <linux/of_fdt.h>
#include <drm/drmP.h>
#include "sde_hw_mdss.h"
+101 −153
Original line number Diff line number Diff line
@@ -14,8 +14,6 @@
#include <linux/mutex.h>
#include <linux/of_platform.h>

#include <linux/msm-bus.h>
#include <linux/msm-bus-board.h>
#include <linux/sde_io_util.h>
#include <linux/sde_rsc.h>

@@ -23,6 +21,13 @@
#include "sde_trace.h"
#include "sde_dbg.h"

static const struct sde_power_bus_scaling_data sde_reg_bus_table[] = {
	{0, 0},
	{0, 76800},
	{0, 150000},
	{0, 300000},
};

static const char *data_bus_name[SDE_POWER_HANDLE_DBUS_ID_MAX] = {
	[SDE_POWER_HANDLE_DBUS_ID_MNOC] = "qcom,sde-data-bus",
	[SDE_POWER_HANDLE_DBUS_ID_LLCC] = "qcom,sde-llcc-bus",
@@ -277,67 +282,49 @@ static int sde_power_parse_dt_clock(struct platform_device *pdev,
	return rc;
}

#ifdef CONFIG_QCOM_BUS_SCALING

#define MAX_AXI_PORT_COUNT 3

static int _sde_power_data_bus_set_quota(
	struct sde_power_data_bus_handle *pdbus,
	u64 in_ab_quota, u64 in_ib_quota)
{
	int new_uc_idx;
	u64 ab_quota[MAX_AXI_PORT_COUNT] = {0, 0};
	u64 ib_quota[MAX_AXI_PORT_COUNT] = {0, 0};
	int rc;
	int rc = 0, i = 0, j = 0;

	if (pdbus->data_bus_hdl < 1) {
		pr_err("invalid bus handle %d\n", pdbus->data_bus_hdl);
	if (!pdbus->data_paths_cnt) {
		pr_err("invalid data bus handle\n");
		return -EINVAL;
	}

	if (!in_ab_quota && !in_ib_quota)  {
		new_uc_idx = 0;
	} else {
		int i;
		struct msm_bus_vectors *vect = NULL;
		struct msm_bus_scale_pdata *bw_table =
			pdbus->data_bus_scale_table;
		u32 total_data_paths_cnt = pdbus->data_paths_cnt;

		if (!bw_table || !total_data_paths_cnt ||
		    total_data_paths_cnt > MAX_AXI_PORT_COUNT) {
			pr_err("invalid input\n");
			return -EINVAL;
		}
	pr_debug("ab=%llu ib=%llu\n", in_ab_quota, in_ib_quota);

		ab_quota[0] = div_u64(in_ab_quota, total_data_paths_cnt);
		ib_quota[0] = div_u64(in_ib_quota, total_data_paths_cnt);
	in_ab_quota = div_u64(in_ab_quota, pdbus->data_paths_cnt);

		for (i = 1; i < total_data_paths_cnt; i++) {
			ab_quota[i] = ab_quota[0];
			ib_quota[i] = ib_quota[0];
	SDE_ATRACE_BEGIN("msm_bus_scale_req");
	for (i = 0; i < pdbus->data_paths_cnt; i++) {
		if (pdbus->data_bus_hdl[i]) {
			rc = icc_set_bw(pdbus->data_bus_hdl[i],
				in_ab_quota, in_ib_quota);
			if (rc)
				goto err;
		}
	}

		new_uc_idx = (pdbus->curr_bw_uc_idx %
			(bw_table->num_usecases - 1)) + 1;
	pdbus->curr_val.ab = in_ab_quota;
	pdbus->curr_val.ib = in_ib_quota;

		for (i = 0; i < total_data_paths_cnt; i++) {
			vect = &bw_table->usecase[new_uc_idx].vectors[i];
			vect->ab = ab_quota[i];
			vect->ib = ib_quota[i];
	SDE_ATRACE_END("msm_bus_scale_req");

			pr_debug(
				"%s uc_idx=%d idx=%d ab=%llu ib=%llu\n",
				bw_table->name, new_uc_idx, i, vect->ab,
				vect->ib);
		}
	}
	pdbus->curr_bw_uc_idx = new_uc_idx;
	return rc;
err:
	for (j = 0; j < i; j++)
		if (pdbus->data_bus_hdl[j])
			icc_set_bw(pdbus->data_bus_hdl[j],
				   pdbus->curr_val.ab,
				   pdbus->curr_val.ib);

	SDE_ATRACE_BEGIN("msm_bus_scale_req");
	rc = msm_bus_scale_client_update_request(pdbus->data_bus_hdl,
			new_uc_idx);
	SDE_ATRACE_END("msm_bus_scale_req");
	pr_err("failed to set data bus vote ab=%llu ib=%llu rc=%d\n",
	       rc, in_ab_quota, in_ib_quota);

	return rc;
}
@@ -356,7 +343,7 @@ int sde_power_data_bus_set_quota(struct sde_power_handle *phandle,

	trace_sde_perf_update_bus(bus_id, ab_quota, ib_quota);

	if (phandle->data_bus_handle[bus_id].data_bus_hdl)
	if (phandle->data_bus_handle[bus_id].data_paths_cnt > 0)
		rc = _sde_power_data_bus_set_quota(
			&phandle->data_bus_handle[bus_id], ab_quota, ib_quota);

@@ -368,96 +355,96 @@ int sde_power_data_bus_set_quota(struct sde_power_handle *phandle,
static void sde_power_data_bus_unregister(
		struct sde_power_data_bus_handle *pdbus)
{
	if (pdbus->data_bus_hdl) {
		msm_bus_scale_unregister_client(pdbus->data_bus_hdl);
		pdbus->data_bus_hdl = 0;
	int i = 0;

	for (i = 0; i < pdbus->data_paths_cnt; i++) {
		if (pdbus->data_bus_hdl[i]) {
			icc_put(pdbus->data_bus_hdl[i]);
			pdbus->data_bus_hdl[i] = NULL;
		}
	}
}

static int sde_power_data_bus_parse(struct platform_device *pdev,
	struct sde_power_data_bus_handle *pdbus, const char *name)
{
	struct device_node *node;
	int rc = 0;
	int paths;
	char bus_name[32];
	int i = 0, ret = 0;

	node = of_get_child_by_name(pdev->dev.of_node, name);
	if (!node)
	for (i = 0; i < DATA_BUS_PATH_MAX; i++) {
		snprintf(bus_name, sizeof(bus_name), "%s%d", name, i);
		ret = of_property_match_string(pdev->dev.of_node,
			"interconnect-names", bus_name);
		if (ret < 0) {
			if (!pdbus->data_paths_cnt) {
				pr_debug("sde: bus %s dt node missing\n", bus_name);
				return 0;
			} else
				goto end;
		} else
			pdbus->data_bus_hdl[i] = of_icc_get(&pdev->dev, bus_name);

	rc = of_property_read_u32(node, "qcom,msm-bus,num-paths", &paths);
	if (rc) {
		pr_err("Error. qcom,msm-bus,num-paths not found\n");
		return rc;
		if (IS_ERR_OR_NULL(pdbus->data_bus_hdl[i])) {
			pr_debug("icc get path failed for %s\n", bus_name);
			break;
		}
	pdbus->data_paths_cnt = paths;

	pdbus->data_bus_scale_table = msm_bus_pdata_from_node(pdev, node);
	if (IS_ERR_OR_NULL(pdbus->data_bus_scale_table)) {
		pr_err("reg bus handle parsing failed\n");
		rc = PTR_ERR(pdbus->data_bus_scale_table);
		if (!pdbus->data_bus_scale_table)
			rc = -EINVAL;
		goto end;
		pdbus->data_paths_cnt++;
	}
	pdbus->data_bus_hdl = msm_bus_scale_register_client(
			pdbus->data_bus_scale_table);
	if (!pdbus->data_bus_hdl) {
		pr_err("data_bus_client register failed\n");
		rc = -EINVAL;
		goto end;

	if (!pdbus->data_paths_cnt) {
		pr_err("get none data bus path for %s\n", name);
		return -EINVAL;
	}
	pr_debug("register %s data_bus_hdl=%x\n", name, pdbus->data_bus_hdl);

end:
	return rc;
	if (of_find_property(pdev->dev.of_node,
			     "qcom,msm-bus,active-only", NULL)) {
		pdbus->bus_active_only = true;
		for (i = 0; i < pdbus->data_paths_cnt; i++) {
			icc_set_tag(pdbus->data_bus_hdl[i],
				    QCOM_ICC_TAG_ACTIVE_ONLY);
		}
	}

	pr_debug("register %s data_bus success, path number=%d\n",
		name, pdbus->data_paths_cnt);

	return 0;
}

static int sde_power_reg_bus_parse(struct platform_device *pdev,
	struct sde_power_handle *phandle)
{
	struct device_node *node;
	struct msm_bus_scale_pdata *bus_scale_table;
	int rc = 0;

	node = of_get_child_by_name(pdev->dev.of_node, "qcom,sde-reg-bus");
	if (node) {
		bus_scale_table = msm_bus_pdata_from_node(pdev, node);
		if (IS_ERR_OR_NULL(bus_scale_table)) {
	phandle->reg_bus_hdl = of_icc_get(&pdev->dev, "qcom,sde-reg-bus");
	if (IS_ERR_OR_NULL(phandle->reg_bus_hdl)) {
		pr_err("reg bus handle parsing failed\n");
			rc = PTR_ERR(bus_scale_table);
			if (!bus_scale_table)
				rc = -EINVAL;
			goto end;
		}
		phandle->reg_bus_hdl = msm_bus_scale_register_client(
			      bus_scale_table);
		if (!phandle->reg_bus_hdl) {
			pr_err("reg_bus_client register failed\n");
		phandle->reg_bus_hdl = NULL;
		rc = -EINVAL;
			goto end;
		}
		pr_debug("register reg_bus_hdl=%x\n", phandle->reg_bus_hdl);
	} else {
		pr_debug("reg_bus_hdl parsing success\n");
	}

end:
	return rc;
}

static void sde_power_reg_bus_unregister(u32 reg_bus_hdl)
static void sde_power_reg_bus_unregister(struct icc_path *reg_bus_hdl)
{
	if (reg_bus_hdl)
		msm_bus_scale_unregister_client(reg_bus_hdl);
		icc_put(reg_bus_hdl);
}

static int sde_power_reg_bus_update(u32 reg_bus_hdl, u32 usecase_ndx)
static int sde_power_reg_bus_update(struct icc_path *reg_bus_hdl,
	u32 usecase_ndx)
{
	int rc = 0;

	if (reg_bus_hdl) {
		SDE_ATRACE_BEGIN("msm_bus_scale_req");
		rc = msm_bus_scale_client_update_request(reg_bus_hdl,
								usecase_ndx);
		rc = icc_set_bw(reg_bus_hdl,
			sde_reg_bus_table[usecase_ndx].ab,
			sde_reg_bus_table[usecase_ndx].ib);
		SDE_ATRACE_END("msm_bus_scale_req");
	}

@@ -466,52 +453,6 @@ static int sde_power_reg_bus_update(u32 reg_bus_hdl, u32 usecase_ndx)

	return rc;
}
#else
static int _sde_power_data_bus_set_quota(
	struct sde_power_data_bus_handle *pdbus,
	u64 in_ab_quota, u64 in_ib_quota)
{
	return 0;
}

static int sde_power_data_bus_parse(struct platform_device *pdev,
		struct sde_power_data_bus_handle *pdbus, const char *name)
{
	return 0;
}

static void sde_power_data_bus_unregister(
		struct sde_power_data_bus_handle *pdbus)
{
}

int sde_power_data_bus_set_quota(struct sde_power_handle *phandle,
	u32 bus_id, u64 ab_quota, u64 ib_quota)
{
	return 0;
}

static int sde_power_reg_bus_parse(struct platform_device *pdev,
	struct sde_power_handle *phandle)
{
	return 0;
}

static void sde_power_reg_bus_unregister(u32 reg_bus_hdl)
{
}

static int sde_power_reg_bus_update(u32 reg_bus_hdl, u32 usecase_ndx)
{
	return 0;
}

int sde_power_data_bus_state_update(struct sde_power_handle *phandle,
							bool enable)
{
	return 0;
}
#endif

int sde_power_resource_init(struct platform_device *pdev,
	struct sde_power_handle *phandle)
@@ -675,6 +616,13 @@ int sde_power_scale_reg_bus(struct sde_power_handle *phandle,
						usecase_ndx);
	if (rc)
		pr_err("failed to set reg bus vote rc=%d\n", rc);
	else {
		phandle->reg_bus_curr_val.ab =
			sde_reg_bus_table[usecase_ndx].ab;
		phandle->reg_bus_curr_val.ib =
			sde_reg_bus_table[usecase_ndx].ib;
		phandle->current_usecase_ndx = usecase_ndx;
	}

	if (!skip_lock)
		mutex_unlock(&phandle->phandle_lock);
@@ -723,7 +671,7 @@ int sde_power_resource_enable(struct sde_power_handle *phandle, bool enable)
				SDE_POWER_EVENT_PRE_ENABLE);

		for (i = 0; i < SDE_POWER_HANDLE_DBUS_ID_MAX &&
		     phandle->data_bus_handle[i].data_bus_hdl; i++) {
			phandle->data_bus_handle[i].data_paths_cnt > 0; i++) {
			rc = _sde_power_data_bus_set_quota(
				&phandle->data_bus_handle[i],
				SDE_POWER_HANDLE_ENABLE_BUS_AB_QUOTA,
@@ -777,7 +725,7 @@ int sde_power_resource_enable(struct sde_power_handle *phandle, bool enable)
		msm_dss_enable_vreg(mp->vreg_config, mp->num_vreg, enable);

		for (i = SDE_POWER_HANDLE_DBUS_ID_MAX - 1; i >= 0; i--)
			if (phandle->data_bus_handle[i].data_bus_hdl)
			if (phandle->data_bus_handle[i].data_paths_cnt > 0)
				_sde_power_data_bus_set_quota(
					&phandle->data_bus_handle[i],
					SDE_POWER_HANDLE_DISABLE_BUS_AB_QUOTA,
@@ -799,7 +747,7 @@ int sde_power_resource_enable(struct sde_power_handle *phandle, bool enable)
reg_bus_hdl_err:
	msm_dss_enable_vreg(mp->vreg_config, mp->num_vreg, 0);
vreg_err:
	for (i-- ; i >= 0 && phandle->data_bus_handle[i].data_bus_hdl; i--)
	for (i-- ; i >= 0 && phandle->data_bus_handle[i].data_paths_cnt > 0; i--)
		_sde_power_data_bus_set_quota(
			&phandle->data_bus_handle[i],
			SDE_POWER_HANDLE_DISABLE_BUS_AB_QUOTA,
+35 −18
Original line number Diff line number Diff line
@@ -18,6 +18,7 @@
#define SDE_POWER_HANDLE_CONT_SPLASH_BUS_AB_QUOTA	3000000000ULL

#include <linux/sde_io_util.h>
#include <linux/interconnect.h>
#include <soc/qcom/cx_ipeak.h>

/* event will be triggered before power handler disable */
@@ -31,6 +32,23 @@

/* event will be triggered after power handler enable */
#define SDE_POWER_EVENT_POST_ENABLE	0x8
#define DATA_BUS_PATH_MAX	0x2

/*
 * The AMC bucket denotes constraints that are applied to hardware when
 * icc_set_bw() completes, whereas the WAKE and SLEEP constraints are applied
 * when the execution environment transitions between active and low power mode.
 */
#define QCOM_ICC_BUCKET_AMC            0
#define QCOM_ICC_BUCKET_WAKE           1
#define QCOM_ICC_BUCKET_SLEEP          2
#define QCOM_ICC_NUM_BUCKETS           3
#define QCOM_ICC_TAG_AMC               BIT(QCOM_ICC_BUCKET_AMC)
#define QCOM_ICC_TAG_WAKE              BIT(QCOM_ICC_BUCKET_WAKE)
#define QCOM_ICC_TAG_SLEEP             BIT(QCOM_ICC_BUCKET_SLEEP)
#define QCOM_ICC_TAG_ACTIVE_ONLY       (QCOM_ICC_TAG_AMC | QCOM_ICC_TAG_WAKE)
#define QCOM_ICC_TAG_ALWAYS            (QCOM_ICC_TAG_AMC | QCOM_ICC_TAG_WAKE |\
                                        QCOM_ICC_TAG_SLEEP)

/**
 * mdss_bus_vote_type: register bus vote type
@@ -73,30 +91,27 @@ enum SDE_POWER_HANDLE_DBUS_ID {
	SDE_POWER_HANDLE_DBUS_ID_MAX,
};

/**
 * struct sde_power_bus_scaling_data: struct for bus setting
 * @ab: average bandwidth in kilobytes per second
 * @ib: peak bandwidth in kilobytes per second
 */
struct sde_power_bus_scaling_data {
	uint64_t ab; /* Arbitrated bandwidth */
	uint64_t ib; /* Instantaneous bandwidth */
};

/**
 * struct sde_power_data_handle: power handle struct for data bus
 * @data_bus_scale_table: pointer to bus scaling table
 * @data_bus_hdl: current data bus handle
 * @curr_val : save the current bus value
 * @data_paths_cnt: number of rt data path ports
 * @curr_bw_uc_idx: current use case index of data bus
 * @ao_bw_uc_idx: active only use case index of data bus
 * @ab_rt: realtime ab quota
 * @ib_rt: realtime ib quota
 * @ab_nrt: non-realtime ab quota
 * @ib_nrt: non-realtime ib quota
 * @enable: true if bus is enabled
 */
struct sde_power_data_bus_handle {
	struct msm_bus_scale_pdata *data_bus_scale_table;
	u32 data_bus_hdl;
	struct icc_path *data_bus_hdl[DATA_BUS_PATH_MAX];
	struct sde_power_bus_scaling_data curr_val;
	u32 data_paths_cnt;
	u32 curr_bw_uc_idx;
	u32 ao_bw_uc_idx;
	u64 ab_rt;
	u64 ib_rt;
	u64 ab_nrt;
	u64 ib_nrt;
	bool enable;
	bool bus_active_only;
};

/*
@@ -124,6 +139,7 @@ struct sde_power_event {
 * @dev: pointer to device structure
 * @usecase_ndx: current usecase index
 * @reg_bus_hdl: current register bus handle
 * @reg_bus_curr_val: save currecnt reg bus value
 * @data_bus_handle: context structure for data bus control
 * @event_list: current power handle event list
 * @rsc_client: sde rsc client pointer
@@ -135,7 +151,8 @@ struct sde_power_handle {
	struct mutex phandle_lock;
	struct device *dev;
	u32 current_usecase_ndx;
	u32 reg_bus_hdl;
	struct icc_path *reg_bus_hdl;
	struct sde_power_bus_scaling_data reg_bus_curr_val;
	struct sde_power_data_bus_handle data_bus_handle
		[SDE_POWER_HANDLE_DBUS_ID_MAX];
	struct list_head event_list;
+32 −5
Original line number Diff line number Diff line
@@ -15,7 +15,6 @@
#include <linux/mutex.h>
#include <linux/of_platform.h>
#include <linux/module.h>
#include <linux/msm-bus.h>

#include <soc/qcom/rpmh.h>
#include <drm/drmP.h>
@@ -64,6 +63,21 @@
static struct sde_rsc_priv *rsc_prv_list[MAX_RSC_COUNT];
static struct device *rpmh_dev[MAX_RSC_COUNT];

static void sde_rsc_set_data_bus_mode(struct sde_power_handle *phandle, u32 tag)
{
	int i = 0, j = 0;

	for (i = 0; i < SDE_POWER_HANDLE_DBUS_ID_MAX; i++) {
		if (!phandle->data_bus_handle[i].bus_active_only)
			continue;

		for (j = 0; j < phandle->data_bus_handle[i].data_paths_cnt; j++)
			icc_set_tag(phandle->data_bus_handle[i].data_bus_hdl[j],
				    tag);

	}
}

/**
 * sde_rsc_client_create() - create the client for sde rsc.
 * Different displays like DSI, HDMI, DP, WB, etc should call this
@@ -523,8 +537,11 @@ static int sde_rsc_switch_to_cmd(struct sde_rsc_priv *rsc,

	if (rsc->hw_ops.state_update) {
		rc = rsc->hw_ops.state_update(rsc, SDE_RSC_CMD_STATE);
		if (!rc)
		if (!rc) {
			rpmh_mode_solver_set(rsc->rpmh_dev, true);
			sde_rsc_set_data_bus_mode(&rsc->phandle,
						  QCOM_ICC_TAG_WAKE);
		}
	}

vsync_wait:
@@ -574,8 +591,11 @@ static int sde_rsc_switch_to_clk(struct sde_rsc_priv *rsc,

	if (rsc->hw_ops.state_update) {
		rc = rsc->hw_ops.state_update(rsc, SDE_RSC_CLK_STATE);
		if (!rc)
		if (!rc) {
			rpmh_mode_solver_set(rsc->rpmh_dev, false);
			sde_rsc_set_data_bus_mode(&rsc->phandle,
						  QCOM_ICC_TAG_AMC);
		}
	}

	/* indicate wait for vsync for cmd/vid to clk state switch */
@@ -661,9 +681,13 @@ static int sde_rsc_switch_to_vid(struct sde_rsc_priv *rsc,

	if (rsc->hw_ops.state_update) {
		rc = rsc->hw_ops.state_update(rsc, SDE_RSC_VID_STATE);
		if (!rc)
		if (!rc) {
			rpmh_mode_solver_set(rsc->rpmh_dev,
				rsc->version == SDE_RSC_REV_3 ? true : false);
			sde_rsc_set_data_bus_mode(&rsc->phandle,
				rsc->version == SDE_RSC_REV_3 ?
				QCOM_ICC_TAG_WAKE : QCOM_ICC_TAG_AMC);
		}
	}

vsync_wait:
@@ -737,8 +761,11 @@ static int sde_rsc_switch_to_idle(struct sde_rsc_priv *rsc,
			rc = CLK_MODE_SWITCH_SUCCESS;
	} else if (rsc->hw_ops.state_update) {
		rc = rsc->hw_ops.state_update(rsc, SDE_RSC_IDLE_STATE);
		if (!rc)
		if (!rc) {
			rpmh_mode_solver_set(rsc->rpmh_dev, true);
			sde_rsc_set_data_bus_mode(&rsc->phandle,
						  QCOM_ICC_TAG_WAKE);
		}
	}

	return rc;