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

Commit 3bf343ac authored by qctecmdr's avatar qctecmdr Committed by Gerrit - the friendly Code Review server
Browse files

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

parents 90633cf3 de77a16a
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);
@@ -1417,11 +1352,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++) {
@@ -1491,10 +1421,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);
}