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

Commit deca0f34 authored by Girish Mahadevan's avatar Girish Mahadevan Committed by Gerrit - the friendly Code Review server
Browse files

spi: spi_qsd: Make bus vote proportional to core clock



Make the bus bandwidth voting proportional to the core clock that the
driver will set. This will help SPI throughput when the core clock is
voted much higher than the bus clocks.

Change-Id: I8d134a281b322484238620b35757c0d86b86c3f1
Signed-off-by: default avatarGirish Mahadevan <girishm@codeaurora.org>
parent 1a0959e7
Loading
Loading
Loading
Loading
+25 −124
Original line number Diff line number Diff line
@@ -286,106 +286,23 @@ static void msm_spi_clock_set(struct msm_spi *dd, int speed)
		dd->clock_speed = rate;
}

static void msm_spi_clk_path_vote(struct msm_spi *dd)
static void msm_spi_clk_path_vote(struct msm_spi *dd, u32 rate)
{
	if (dd->clk_path_vote.client_hdl)
		msm_bus_scale_client_update_request(
						dd->clk_path_vote.client_hdl,
						MSM_SPI_CLK_PATH_RESUME_VEC);
}
	if (dd->bus_cl_hdl) {
		u64 ib = rate * dd->pdata->bus_width;

static void msm_spi_clk_path_unvote(struct msm_spi *dd)
{
	if (dd->clk_path_vote.client_hdl)
		msm_bus_scale_client_update_request(
						dd->clk_path_vote.client_hdl,
						MSM_SPI_CLK_PATH_SUSPEND_VEC);
}

static void msm_spi_clk_path_teardown(struct msm_spi *dd)
{
	msm_spi_clk_path_unvote(dd);

	if (dd->clk_path_vote.client_hdl) {
		msm_bus_scale_unregister_client(dd->clk_path_vote.client_hdl);
		dd->clk_path_vote.client_hdl = 0;
		msm_bus_scale_update_bw(dd->bus_cl_hdl, 0, ib);
	}
}

/**
 * msm_spi_clk_path_init_structs: internal impl detail of msm_spi_clk_path_init
 *
 * allocates and initilizes the bus scaling vectors.
 */
static int msm_spi_clk_path_init_structs(struct msm_spi *dd)
static void msm_spi_clk_path_teardown(struct msm_spi *dd)
{
	struct msm_bus_vectors *paths    = NULL;
	struct msm_bus_paths   *usecases = NULL;
	msm_spi_clk_path_vote(dd, 0);

	dev_dbg(dd->dev, "initialises path clock voting structs");

	paths = devm_kzalloc(dd->dev, sizeof(*paths) * 2, GFP_KERNEL);
	if (!paths) {
		dev_err(dd->dev,
		"msm_bus_paths.paths memory allocation failed");
		return -ENOMEM;
	}

	usecases = devm_kzalloc(dd->dev, sizeof(*usecases) * 2, GFP_KERNEL);
	if (!usecases) {
		dev_err(dd->dev,
		"msm_bus_scale_pdata.usecases memory allocation failed");
		goto path_init_err;
	if (dd->bus_cl_hdl) {
		msm_bus_scale_unregister(dd->bus_cl_hdl);
		dd->bus_cl_hdl = NULL;
	}

	dd->clk_path_vote.pdata = devm_kzalloc(dd->dev,
					    sizeof(*dd->clk_path_vote.pdata),
					    GFP_KERNEL);
	if (!dd->clk_path_vote.pdata) {
		dev_err(dd->dev,
		"msm_bus_scale_pdata memory allocation failed");
		goto path_init_err;
	}

	paths[MSM_SPI_CLK_PATH_SUSPEND_VEC] = (struct msm_bus_vectors) {
		.src = dd->pdata->master_id,
		.dst = MSM_BUS_SLAVE_EBI_CH0,
		.ab  = 0,
		.ib  = 0,
	};

	paths[MSM_SPI_CLK_PATH_RESUME_VEC]  = (struct msm_bus_vectors) {
		.src = dd->pdata->master_id,
		.dst = MSM_BUS_SLAVE_EBI_CH0,
		.ab  = 0,
		.ib  = MSM_SPI_CLK_PATH_BRST_BW(dd),
	};

	usecases[MSM_SPI_CLK_PATH_SUSPEND_VEC] = (struct msm_bus_paths) {
		.num_paths = 1,
		.vectors   = &paths[MSM_SPI_CLK_PATH_SUSPEND_VEC],
	};

	usecases[MSM_SPI_CLK_PATH_RESUME_VEC] = (struct msm_bus_paths) {
		.num_paths = 1,
		.vectors   = &paths[MSM_SPI_CLK_PATH_RESUME_VEC],
	};

	*dd->clk_path_vote.pdata = (struct msm_bus_scale_pdata) {
		.active_only  = 0,
		.name         = dev_name(dd->dev),
		.num_usecases = 2,
		.usecase      = usecases,
	};

	return 0;

path_init_err:
	devm_kfree(dd->dev, paths);
	devm_kfree(dd->dev, usecases);
	devm_kfree(dd->dev, dd->clk_path_vote.pdata);
	dd->clk_path_vote.pdata = NULL;
	return -ENOMEM;
}

/**
@@ -402,32 +319,19 @@ path_init_err:
 */
static int msm_spi_clk_path_postponed_register(struct msm_spi *dd)
{
	dd->clk_path_vote.client_hdl = msm_bus_scale_register_client(
						dd->clk_path_vote.pdata);

	if (dd->clk_path_vote.client_hdl) {
		if (dd->clk_path_vote.reg_err) {
			/* log a success message if an error msg was logged */
			dd->clk_path_vote.reg_err = false;
			dev_info(dd->dev,
			"msm_bus_scale_register_client(mstr-id:%d): 0x%x",
				dd->pdata->master_id,
				dd->clk_path_vote.client_hdl);
		}
	int ret = 0;

		msm_spi_clk_path_vote(dd);
	} else {
		/* guard to log only one error on multiple failure */
		if (!dd->clk_path_vote.reg_err) {
			dd->clk_path_vote.reg_err = true;
	dd->bus_cl_hdl = msm_bus_scale_register(dd->pdata->master_id,
						MSM_BUS_SLAVE_EBI_CH0,
						(char *)dev_name(dd->dev),
						false);

			dev_info(dd->dev,
				"msm_bus_scale_register_client(mstr-id:%d): 0",
				dd->pdata->master_id);
		}
	if (IS_ERR_OR_NULL(dd->bus_cl_hdl)) {
		ret = (dd->bus_cl_hdl ? PTR_ERR(dd->bus_cl_hdl) : -EAGAIN);
		dev_err(dd->dev, "Failed bus registration Err %d", ret);
	}

	return dd->clk_path_vote.client_hdl ? 0 : -EAGAIN;
	return ret;
}

static void msm_spi_clk_path_init(struct msm_spi *dd)
@@ -436,20 +340,13 @@ static void msm_spi_clk_path_init(struct msm_spi *dd)
	 * bail out if path voting is diabled (master_id == 0) or if it is
	 * already registered (client_hdl != 0)
	 */
	if (!dd->pdata->master_id || dd->clk_path_vote.client_hdl)
	if (!dd->pdata->master_id || dd->bus_cl_hdl)
		return;

	/* if fail once then try no more */
	if (!dd->clk_path_vote.pdata && msm_spi_clk_path_init_structs(dd)) {
		dd->pdata->master_id = 0;
		return;
	};

	/* on failure try again later */
	if (msm_spi_clk_path_postponed_register(dd))
		return;

	msm_spi_clk_path_vote(dd);
}

static int msm_spi_calculate_size(int *fifo_size,
@@ -1554,6 +1451,7 @@ static inline void msm_spi_set_cs(struct spi_device *spi, bool set_flag)
			return;
	}

	msm_spi_clk_path_vote(dd, spi->max_speed_hz);

	if (!(spi->mode & SPI_CS_HIGH))
		set_flag = !set_flag;
@@ -1606,6 +1504,7 @@ static void put_local_resources(struct msm_spi *dd)
	}
	msm_spi_disable_irqs(dd);
	clk_disable_unprepare(dd->clk);
	dd->clock_speed = 0;
	clk_disable_unprepare(dd->pclk);

	/* Free  the spi clk, miso, mosi, cs gpio */
@@ -2246,6 +2145,8 @@ struct msm_spi_platform_data *msm_spi_dt_to_pdata(
			&pdata->infinite_mode,           DT_OPT,  DT_U32,   0},
		{"qcom,master-id",
			&pdata->master_id,               DT_SGST, DT_U32,   0},
		{"qcom,bus-width",
			&pdata->bus_width,               DT_OPT, DT_U32,   8},
		{"qcom,ver-reg-exists",
			&pdata->ver_reg_exists,          DT_OPT,  DT_BOOL,  0},
		{"qcom,use-bam",
@@ -2661,7 +2562,7 @@ static int msm_spi_pm_suspend_runtime(struct device *device)
		put_local_resources(dd);

	if (dd->pdata)
		msm_spi_clk_path_unvote(dd);
		msm_spi_clk_path_vote(dd, 0);

suspend_exit:
	return 0;
@@ -2691,7 +2592,7 @@ static int msm_spi_pm_resume_runtime(struct device *device)
			dd->is_init_complete = true;
	}
	msm_spi_clk_path_init(dd);
	msm_spi_clk_path_vote(dd);
	msm_spi_clk_path_vote(dd, dd->pdata->max_clock_speed);

	if (!dd->pdata->is_shared) {
		ret = get_local_resources(dd);
+1 −17
Original line number Diff line number Diff line
@@ -262,22 +262,6 @@ static struct msm_spi_regs{
};
#endif

/**
 * qup_i2c_clk_path_vote: data to use bus scaling driver for clock path vote
 *
 * @client_hdl when zero, client is not registered with the bus scaling driver,
 *      and bus scaling functionality should not be used. When non zero, it
 *      is a bus scaling client id and may be used to vote for clock path.
 * @reg_err when true, registration error was detected and an error message was
 *      logged. i2c will attempt to re-register but will log error only once.
 *      once registration succeed, the flag is set to false.
 */
struct qup_i2c_clk_path_vote {
	u32                         client_hdl;
	struct msm_bus_scale_pdata *pdata;
	bool                        reg_err;
};

struct msm_spi_bam_pipe {
	const char              *name;
	struct sps_pipe         *handle;
@@ -312,7 +296,7 @@ struct msm_spi {
	struct completion        rx_transfer_complete;
	struct clk              *clk;    /* core clock */
	struct clk              *pclk;   /* interface clock */
	struct qup_i2c_clk_path_vote clk_path_vote;
	struct msm_bus_client_handle *bus_cl_hdl;
	unsigned long            mem_phys_addr;
	size_t                   mem_size;
	int                      input_fifo_size;
+1 −0
Original line number Diff line number Diff line
@@ -39,6 +39,7 @@
struct msm_spi_platform_data {
	u32 max_clock_speed;
	u32  master_id;
	u32 bus_width;
	int (*gpio_config)(void);
	void (*gpio_release)(void);
	int (*dma_config)(void);