Commit 58ffbba6 authored by Akash Asthana's avatar Akash Asthana Committed by Bjorn Andersson
Browse files

soc: qcom: geni: Support for ICC voting



Add necessary macros and structure variables to support ICC BW
voting from individual SE drivers.

Signed-off-by: default avatarAkash Asthana <akashast@codeaurora.org>
Reviewed-by: default avatarMatthias Kaehlcke <mka@chromium.org>
Link: https://lore.kernel.org/r/1592908737-7068-2-git-send-email-akashast@codeaurora.org


Signed-off-by: default avatarBjorn Andersson <bjorn.andersson@linaro.org>
parent be24c6a7
Loading
Loading
Loading
Loading
+82 −0
Original line number Diff line number Diff line
@@ -92,6 +92,9 @@ struct geni_wrapper {
	struct clk_bulk_data ahb_clks[NUM_AHB_CLKS];
};

static const char * const icc_path_names[] = {"qup-core", "qup-config",
						"qup-memory"};

#define QUP_HW_VER_REG			0x4

/* Common SE registers */
@@ -720,6 +723,85 @@ void geni_se_rx_dma_unprep(struct geni_se *se, dma_addr_t iova, size_t len)
}
EXPORT_SYMBOL(geni_se_rx_dma_unprep);

int geni_icc_get(struct geni_se *se, const char *icc_ddr)
{
	int i, err;
	const char *icc_names[] = {"qup-core", "qup-config", icc_ddr};

	for (i = 0; i < ARRAY_SIZE(se->icc_paths); i++) {
		if (!icc_names[i])
			continue;

		se->icc_paths[i].path = devm_of_icc_get(se->dev, icc_names[i]);
		if (IS_ERR(se->icc_paths[i].path))
			goto err;
	}

	return 0;

err:
	err = PTR_ERR(se->icc_paths[i].path);
	if (err != -EPROBE_DEFER)
		dev_err_ratelimited(se->dev, "Failed to get ICC path '%s': %d\n",
					icc_names[i], err);
	return err;

}
EXPORT_SYMBOL(geni_icc_get);

int geni_icc_set_bw(struct geni_se *se)
{
	int i, ret;

	for (i = 0; i < ARRAY_SIZE(se->icc_paths); i++) {
		ret = icc_set_bw(se->icc_paths[i].path,
			se->icc_paths[i].avg_bw, se->icc_paths[i].avg_bw);
		if (ret) {
			dev_err_ratelimited(se->dev, "ICC BW voting failed on path '%s': %d\n",
					icc_path_names[i], ret);
			return ret;
		}
	}

	return 0;
}
EXPORT_SYMBOL(geni_icc_set_bw);

/* To do: Replace this by icc_bulk_enable once it's implemented in ICC core */
int geni_icc_enable(struct geni_se *se)
{
	int i, ret;

	for (i = 0; i < ARRAY_SIZE(se->icc_paths); i++) {
		ret = icc_enable(se->icc_paths[i].path);
		if (ret) {
			dev_err_ratelimited(se->dev, "ICC enable failed on path '%s': %d\n",
					icc_path_names[i], ret);
			return ret;
		}
	}

	return 0;
}
EXPORT_SYMBOL(geni_icc_enable);

int geni_icc_disable(struct geni_se *se)
{
	int i, ret;

	for (i = 0; i < ARRAY_SIZE(se->icc_paths); i++) {
		ret = icc_disable(se->icc_paths[i].path);
		if (ret) {
			dev_err_ratelimited(se->dev, "ICC disable failed on path '%s': %d\n",
					icc_path_names[i], ret);
			return ret;
		}
	}

	return 0;
}
EXPORT_SYMBOL(geni_icc_disable);

static int geni_se_probe(struct platform_device *pdev)
{
	struct device *dev = &pdev->dev;
+38 −0
Original line number Diff line number Diff line
@@ -6,6 +6,8 @@
#ifndef _LINUX_QCOM_GENI_SE
#define _LINUX_QCOM_GENI_SE

#include <linux/interconnect.h>

/* Transfer mode supported by GENI Serial Engines */
enum geni_se_xfer_mode {
	GENI_SE_INVALID,
@@ -25,6 +27,17 @@ enum geni_se_protocol_type {
struct geni_wrapper;
struct clk;

enum geni_icc_path_index {
	GENI_TO_CORE,
	CPU_TO_GENI,
	GENI_TO_DDR
};

struct geni_icc_path {
	struct icc_path *path;
	unsigned int avg_bw;
};

/**
 * struct geni_se - GENI Serial Engine
 * @base:		Base Address of the Serial Engine's register block
@@ -33,6 +46,7 @@ struct clk;
 * @clk:		Handle to the core serial engine clock
 * @num_clk_levels:	Number of valid clock levels in clk_perf_tbl
 * @clk_perf_tbl:	Table of clock frequency input to serial engine clock
 * @icc_paths:		Array of ICC paths for SE
 */
struct geni_se {
	void __iomem *base;
@@ -41,6 +55,7 @@ struct geni_se {
	struct clk *clk;
	unsigned int num_clk_levels;
	unsigned long *clk_perf_tbl;
	struct geni_icc_path icc_paths[3];
};

/* Common SE registers */
@@ -229,6 +244,21 @@ struct geni_se {
#define GENI_SE_VERSION_MINOR(ver) ((ver & HW_VER_MINOR_MASK) >> HW_VER_MINOR_SHFT)
#define GENI_SE_VERSION_STEP(ver) (ver & HW_VER_STEP_MASK)

/*
 * Define bandwidth thresholds that cause the underlying Core 2X interconnect
 * clock to run at the named frequency. These baseline values are recommended
 * by the hardware team, and are not dynamically scaled with GENI bandwidth
 * beyond basic on/off.
 */
#define CORE_2X_19_2_MHZ		960
#define CORE_2X_50_MHZ			2500
#define CORE_2X_100_MHZ			5000
#define CORE_2X_150_MHZ			7500
#define CORE_2X_200_MHZ			10000
#define CORE_2X_236_MHZ			16383

#define GENI_DEFAULT_BW			Bps_to_icc(1000)

#if IS_ENABLED(CONFIG_QCOM_GENI_SE)

u32 geni_se_get_qup_hw_version(struct geni_se *se);
@@ -416,5 +446,13 @@ int geni_se_rx_dma_prep(struct geni_se *se, void *buf, size_t len,
void geni_se_tx_dma_unprep(struct geni_se *se, dma_addr_t iova, size_t len);

void geni_se_rx_dma_unprep(struct geni_se *se, dma_addr_t iova, size_t len);

int geni_icc_get(struct geni_se *se, const char *icc_ddr);

int geni_icc_set_bw(struct geni_se *se);

int geni_icc_enable(struct geni_se *se);

int geni_icc_disable(struct geni_se *se);
#endif
#endif