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

Commit de77a16a authored by Raghu Ananya Arabolu's avatar Raghu Ananya Arabolu
Browse files

msm: kgsl: Use hard coded GMU frequency and CX voltage levels



We only need to specify the CX voltage levels that are needed by GMU.
Hence we do not need to hardcode all the CX voltage levels. This way,
we do not need an OPP table created and queried for this information.

Change-Id: I700fd455020e8ebf653810cec1bce4f53599ff73
Signed-off-by: default avatarRaghu Ananya Arabolu <rarabolu@codeaurora.org>
parent 9b7165c0
Loading
Loading
Loading
Loading
+35 −105
Original line number Diff line number Diff line
@@ -3,6 +3,7 @@
 * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved.
 */

#include <dt-bindings/regulator/qcom,rpmh-regulator-levels.h>
#include <linux/delay.h>
#include <linux/firmware.h>
#include <linux/io.h>
@@ -558,11 +559,6 @@ enum rpmh_vote_type {
	INVALID_ARC_VOTE,
};

static const char debug_strs[][8] = {
	[GPU_ARC_VOTE] = "gpu",
	[GMU_ARC_VOTE] = "gmu",
};

/*
 * rpmh_arc_cmds() - query RPMh command database for GX/CX/MX rail
 * VLVL tables. The index of table will be used by GMU to vote rail
@@ -621,7 +617,7 @@ static int rpmh_arc_cmds(struct gmu_device *gmu,
 */
static int setup_volt_dependency_tbl(uint32_t *votes,
		struct rpmh_arc_vals *pri_rail, struct rpmh_arc_vals *sec_rail,
		unsigned int *vlvl, unsigned int num_entries)
		u16 *vlvl, unsigned int num_entries)
{
	int i, j, k;
	uint16_t cur_vlvl;
@@ -667,9 +663,20 @@ static int setup_volt_dependency_tbl(uint32_t *votes,
	return 0;
}


static int rpmh_gmu_arc_votes_init(struct gmu_device *gmu,
		struct rpmh_arc_vals *pri_rail, struct rpmh_arc_vals *sec_rail)
{
	/* Hardcoded values of GMU CX voltage levels */
	u16 gmu_cx_vlvl[] = { 0, RPMH_REGULATOR_LEVEL_MIN_SVS };

	return setup_volt_dependency_tbl(gmu->rpmh_votes.cx_votes, pri_rail,
						sec_rail, gmu_cx_vlvl, 2);
}

/*
 * rpmh_arc_votes_init() - initialized RPMh votes needed for rails voltage
 * scaling by GMU.
 * rpmh_arc_votes_init() - initialized GX RPMh votes needed for rails
 * voltage scaling by GMU.
 * @device: Pointer to KGSL device
 * @gmu: Pointer to GMU device
 * @pri_rail: Pointer to primary power rail VLVL table
@@ -681,74 +688,50 @@ static int rpmh_arc_votes_init(struct kgsl_device *device,
		struct gmu_device *gmu, struct rpmh_arc_vals *pri_rail,
		struct rpmh_arc_vals *sec_rail, unsigned int type)
{
	struct device *dev;
	unsigned int num_freqs;
	uint32_t *votes;
	unsigned int vlvl_tbl[MAX_GX_LEVELS];
	u16 vlvl_tbl[MAX_GX_LEVELS];
	unsigned int *freq_tbl;
	int i, ret;
	int i;
	struct dev_pm_opp *opp;

	uint16_t cx_vlvl[MAX_GX_LEVELS] = { 64, 128, 192, 256, 384, 416 };
	if (type == GMU_ARC_VOTE)
		return rpmh_gmu_arc_votes_init(gmu, pri_rail, sec_rail);

	if (type == GPU_ARC_VOTE) {
	num_freqs = gmu->num_gpupwrlevels;
		votes = gmu->rpmh_votes.gx_votes;
	freq_tbl = gmu->gpu_freqs;
		dev = &device->pdev->dev;
	} else if (type == GMU_ARC_VOTE) {
		num_freqs = gmu->num_gmupwrlevels;
		votes = gmu->rpmh_votes.cx_votes;
		freq_tbl = gmu->gmu_freqs;
		dev = &gmu->pdev->dev;
	} else {
		return -EINVAL;
	}

	if (num_freqs > pri_rail->num) {
	if (num_freqs > pri_rail->num || num_freqs > MAX_GX_LEVELS) {
		dev_err(&gmu->pdev->dev,
			"%s defined more DCVS levels than RPMh can support\n",
			debug_strs[type]);
			"Defined more GPU DCVS levels than RPMh can support\n");
		return -EINVAL;
	}

	memset(vlvl_tbl, 0, sizeof(vlvl_tbl));

	/* Get the values from OPP API */
	for (i = 0; i < num_freqs; i++) {
		/* Hardcode VLVL for 0 because it is not registered in OPP */
		/* Hardcode VLVL 0 because it is not present in OPP */
		if (freq_tbl[i] == 0) {
			vlvl_tbl[i] = 0;
			continue;
		}

		/* Hardcode GMU ARC Vote levels for A650 */
		if (adreno_is_a650_family(ADRENO_DEVICE(device)) &&
				type == GMU_ARC_VOTE) {
			vlvl_tbl[i] = cx_vlvl[i];
			continue;
		}
		opp = dev_pm_opp_find_freq_exact(&device->pdev->dev,
			freq_tbl[i], true);

		/* Otherwise get the value from the OPP API */
		opp = dev_pm_opp_find_freq_exact(dev, freq_tbl[i], true);
		if (IS_ERR(opp)) {
			dev_err(&gmu->pdev->dev,
				"Failed to find opp freq %d of %s\n",
				freq_tbl[i], debug_strs[type]);
				"Failed to find opp freq %d for GPU\n",
				freq_tbl[i]);
			return PTR_ERR(opp);
		}

		/* Values from OPP framework are offset by 1 */
		vlvl_tbl[i] = dev_pm_opp_get_voltage(opp);
		dev_pm_opp_put(opp);
	}

	ret = setup_volt_dependency_tbl(votes,
			pri_rail, sec_rail, vlvl_tbl, num_freqs);

	if (ret)
		dev_err(&gmu->pdev->dev, "%s rail volt failed to match DT freqs\n",
				debug_strs[type]);

	return ret;
	return setup_volt_dependency_tbl(gmu->rpmh_votes.gx_votes, pri_rail,
						sec_rail, vlvl_tbl, num_freqs);
}

/*
@@ -1000,54 +983,6 @@ static irqreturn_t gmu_irq_handler(int irq, void *data)
	return IRQ_HANDLED;
}

static int gmu_pwrlevel_probe(struct gmu_device *gmu, struct device_node *node)
{
	int ret;
	struct device_node *pwrlevel_node, *child;

	/* Add the GMU OPP table if we define it */
	if (of_find_property(gmu->pdev->dev.of_node,
			"operating-points-v2", NULL)) {
		ret = dev_pm_opp_of_add_table(&gmu->pdev->dev);
		if (ret) {
			dev_err(&gmu->pdev->dev,
					"Unable to set the GMU OPP table: %d\n",
					ret);
			return ret;
		}
	}

	pwrlevel_node = of_find_node_by_name(node, "qcom,gmu-pwrlevels");
	if (pwrlevel_node == NULL) {
		dev_err(&gmu->pdev->dev, "Unable to find 'qcom,gmu-pwrlevels'\n");
		return -EINVAL;
	}

	gmu->num_gmupwrlevels = 0;

	for_each_child_of_node(pwrlevel_node, child) {
		unsigned int index;

		if (of_property_read_u32(child, "reg", &index))
			return -EINVAL;

		if (index >= MAX_CX_LEVELS) {
			dev_err(&gmu->pdev->dev, "gmu pwrlevel %d is out of range\n",
				index);
			continue;
		}

		if (index >= gmu->num_gmupwrlevels)
			gmu->num_gmupwrlevels = index + 1;

		if (of_property_read_u32(child, "qcom,gmu-freq",
					&gmu->gmu_freqs[index]))
			return -EINVAL;
	}

	return 0;
}

static int gmu_reg_probe(struct kgsl_device *device)
{
	struct gmu_device *gmu = KGSL_GMU_DEVICE(device);
@@ -1412,11 +1347,6 @@ static int gmu_probe(struct kgsl_device *device, struct device_node *node)
	tasklet_init(&hfi->tasklet, hfi_receiver, (unsigned long) gmu);
	hfi->kgsldev = device;

	/* Retrieves GMU/GPU power level configurations*/
	ret = gmu_pwrlevel_probe(gmu, node);
	if (ret)
		goto error;

	gmu->num_gpupwrlevels = pwr->num_pwrlevels;

	for (i = 0; i < gmu->num_gpupwrlevels; i++) {
@@ -1486,10 +1416,10 @@ static int gmu_enable_clks(struct kgsl_device *device)
	if (IS_ERR_OR_NULL(gmu->clks[0]))
		return -EINVAL;

	ret = clk_set_rate(gmu->clks[0], gmu->gmu_freqs[DEFAULT_GMU_FREQ_IDX]);
	ret = clk_set_rate(gmu->clks[0], GMU_FREQUENCY);
	if (ret) {
		dev_err(&gmu->pdev->dev, "fail to set default GMU clk freq %d\n",
				gmu->gmu_freqs[DEFAULT_GMU_FREQ_IDX]);
				GMU_FREQUENCY);
		return ret;
	}

+2 −4
Original line number Diff line number Diff line
@@ -8,6 +8,8 @@
#include "kgsl_gmu_core.h"
#include "kgsl_hfi.h"

#define GMU_PWR_LEVELS  2
#define GMU_FREQUENCY   200000000
#define MAX_GMUFW_SIZE	0x8000	/* in bytes */

#define BWMEM_SIZE	(12 + (4 * NUM_BW_LEVELS))	/*in bytes*/
@@ -152,9 +154,7 @@ struct kgsl_mailbox {
 * @dump_mem: pointer to GMU debug dump memory
 * @gmu_log: gmu event log memory
 * @hfi: HFI controller
 * @gmu_freqs: GMU frequency table with lowest freq at index 0
 * @gpu_freqs: GPU frequency table with lowest freq at index 0
 * @num_gmupwrlevels: number GMU frequencies in GMU freq table
 * @num_gpupwrlevels: number GPU frequencies in GPU freq table
 * @num_bwlevel: number of GPU BW levels
 * @num_cnocbwlevel: number CNOC BW levels
@@ -190,9 +190,7 @@ struct gmu_device {
	struct gmu_memdesc *dump_mem;
	struct gmu_memdesc *gmu_log;
	struct kgsl_hfi hfi;
	unsigned int gmu_freqs[MAX_CX_LEVELS];
	unsigned int gpu_freqs[MAX_GX_LEVELS];
	unsigned int num_gmupwrlevels;
	unsigned int num_gpupwrlevels;
	unsigned int num_bwlevels;
	unsigned int num_cnocbwlevels;
+0 −1
Original line number Diff line number Diff line
@@ -22,7 +22,6 @@
#endif

#define MAX_GMU_CLKS 6
#define DEFAULT_GMU_FREQ_IDX 1

/*
 * These are the different ways the GMU can boot. GMU_WARM_BOOT is waking up
+10 −10
Original line number Diff line number Diff line
@@ -430,7 +430,7 @@ static int hfi_send_dcvstbl_v1(struct gmu_device *gmu)
	struct hfi_dcvstable_v1_cmd cmd = {
		.hdr = CMD_MSG_HDR(H2F_MSG_PERF_TBL, sizeof(cmd)),
		.gpu_level_num = gmu->num_gpupwrlevels,
		.gmu_level_num = gmu->num_gmupwrlevels,
		.gmu_level_num = GMU_PWR_LEVELS,
	};
	int i;

@@ -440,10 +440,10 @@ static int hfi_send_dcvstbl_v1(struct gmu_device *gmu)
		cmd.gx_votes[i].freq = gmu->gpu_freqs[i] / 1000;
	}

	for (i = 0; i < gmu->num_gmupwrlevels; i++) {
		cmd.cx_votes[i].vote = gmu->rpmh_votes.cx_votes[i];
		cmd.cx_votes[i].freq = gmu->gmu_freqs[i] / 1000;
	}
	cmd.cx_votes[0].vote = gmu->rpmh_votes.cx_votes[0];
	cmd.cx_votes[0].freq = 0;
	cmd.cx_votes[1].vote = gmu->rpmh_votes.cx_votes[1];
	cmd.cx_votes[1].freq = GMU_FREQUENCY / 1000;

	return hfi_send_generic_req(gmu, HFI_CMD_ID, &cmd);
}
@@ -474,7 +474,7 @@ static int hfi_send_dcvstbl(struct gmu_device *gmu)
	struct hfi_dcvstable_cmd cmd = {
		.hdr = CMD_MSG_HDR(H2F_MSG_PERF_TBL, sizeof(cmd)),
		.gpu_level_num = gmu->num_gpupwrlevels,
		.gmu_level_num = gmu->num_gmupwrlevels,
		.gmu_level_num = GMU_PWR_LEVELS,
	};
	int i;

@@ -486,10 +486,10 @@ static int hfi_send_dcvstbl(struct gmu_device *gmu)
		cmd.gx_votes[i].freq = gmu->gpu_freqs[i] / 1000;
	}

	for (i = 0; i < gmu->num_gmupwrlevels; i++) {
		cmd.cx_votes[i].vote = gmu->rpmh_votes.cx_votes[i];
		cmd.cx_votes[i].freq = gmu->gmu_freqs[i] / 1000;
	}
	cmd.cx_votes[0].vote = gmu->rpmh_votes.cx_votes[0];
	cmd.cx_votes[0].freq = 0;
	cmd.cx_votes[1].vote = gmu->rpmh_votes.cx_votes[1];
	cmd.cx_votes[1].freq = GMU_FREQUENCY / 1000;

	return hfi_send_generic_req(gmu, HFI_CMD_ID, &cmd);
}