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

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

Merge "clk: qcom: clk-rpmh: Add QPIC clock support"

parents 9db58734 5a4abba6
Loading
Loading
Loading
Loading
+144 −1
Original line number Diff line number Diff line
/*
 * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
 * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 and
@@ -39,6 +39,31 @@
				      BIT(RPMH_ACTIVE_ONLY_STATE) | \
				      BIT(RPMH_SLEEP_STATE))

#define BCM_TCS_CMD_COMMIT_MASK		0x40000000
#define BCM_TCS_CMD_VALID_SHIFT		29
#define BCM_TCS_CMD_VOTE_MASK		0x3fff
#define BCM_TCS_CMD_VOTE_SHIFT		0

#define BCM_TCS_CMD(valid, vote)				\
	(BCM_TCS_CMD_COMMIT_MASK |				\
	((valid) << BCM_TCS_CMD_VALID_SHIFT) |			\
	((vote & BCM_TCS_CMD_VOTE_MASK)				\
	<< BCM_TCS_CMD_VOTE_SHIFT))

/**
 * struct bcm_db - Auxiliary data pertaining to each Bus Clock Manager(BCM)
 * @unit: divisor used to convert Hz value to an RPMh msg
 * @width: multiplier used to convert Hz value to an RPMh msg
 * @vcd: virtual clock domain that this bcm belongs to
 * @reserved: reserved to pad the struct
 */
struct bcm_db {
	__le32 unit;
	__le16 width;
	u8 vcd;
	u8 reserved;
};

struct clk_rpmh {
	const char *res_name;
	u32 res_addr;
@@ -49,6 +74,7 @@ struct clk_rpmh {
	u32 aggr_state;
	u32 last_sent_aggr_state;
	u32 valid_state_mask;
	u32 unit;
	struct rsc_type *rsc;
	unsigned long rate;
	struct clk_rpmh *peer;
@@ -120,6 +146,17 @@ static DEFINE_MUTEX(rpmh_clk_lock);
			  CLK_RPMH_VRM_OFF_VAL, _rsc_id, _rate, _state_mask, \
			  _state_on_mask)

#define DEFINE_CLK_RPMH_BCM(_platform, _name, _res_name, _rsc_id)	\
	static struct clk_rpmh _platform##_##_name = {			\
		.res_name = _res_name,					\
		.valid_state_mask = BIT(RPMH_ACTIVE_ONLY_STATE),	\
		.rsc = _rsc_id,						\
		.hw.init = &(struct clk_init_data){			\
			.ops = &clk_rpmh_bcm_ops,			\
			.name = #_name,					\
		},							\
	}

#define DEFINE_RSC_TYPE(name, mbox_id, awake_state)	\
	static struct rsc_type name = {			\
		.rpmh_client = NULL,			\
@@ -271,6 +308,99 @@ static const struct clk_ops clk_rpmh_ops = {
	.recalc_rate	= clk_rpmh_recalc_rate,
};

static int clk_rpmh_bcm_send_cmd(struct clk_rpmh *c, bool enable)
{
	struct tcs_cmd cmd = { 0 };
	u32 cmd_state;
	int ret;

	mutex_lock(&rpmh_clk_lock);

	cmd_state = 0;
	if (enable) {
		cmd_state = 1;
		if (c->aggr_state)
			cmd_state = c->aggr_state;
	}

	cmd_state = min_t(u32, cmd_state, BCM_TCS_CMD_VOTE_MASK);

	if (c->last_sent_aggr_state == cmd_state) {
		mutex_unlock(&rpmh_clk_lock);
		return 0;
	}

	cmd.addr = c->res_addr;
	cmd.data = BCM_TCS_CMD(enable, cmd_state);

	ret = rpmh_write_async(c->rsc->rpmh_client, RPMH_ACTIVE_ONLY_STATE,
				&cmd, 1);
	if (ret) {
		pr_err("set active state of %s failed: (%d)\n",
			c->res_name, ret);
		mutex_unlock(&rpmh_clk_lock);
		return ret;
	}

	c->last_sent_aggr_state = cmd_state;

	mutex_unlock(&rpmh_clk_lock);

	return 0;
}

static int clk_rpmh_bcm_prepare(struct clk_hw *hw)
{
	struct clk_rpmh *c = to_clk_rpmh(hw);

	return clk_rpmh_bcm_send_cmd(c, true);
};

static void clk_rpmh_bcm_unprepare(struct clk_hw *hw)
{
	struct clk_rpmh *c = to_clk_rpmh(hw);

	clk_rpmh_bcm_send_cmd(c, false);
};

static int clk_rpmh_bcm_set_rate(struct clk_hw *hw, unsigned long rate,
				 unsigned long parent_rate)
{
	struct clk_rpmh *c = to_clk_rpmh(hw);

	c->aggr_state = rate / c->unit;
	/*
	 * Since any non-zero value sent to hw would result in enabling the
	 * clock, only send the value if the clock has already been prepared.
	 */
	if (clk_hw_is_prepared(hw))
		clk_rpmh_bcm_send_cmd(c, true);

	return 0;
};

static long clk_rpmh_round_rate(struct clk_hw *hw, unsigned long rate,
				unsigned long *parent_rate)
{
	return rate;
}

static unsigned long clk_rpmh_bcm_recalc_rate(struct clk_hw *hw,
					unsigned long prate)
{
	struct clk_rpmh *c = to_clk_rpmh(hw);

	return c->aggr_state * c->unit;
}

static const struct clk_ops clk_rpmh_bcm_ops = {
	.prepare	= clk_rpmh_bcm_prepare,
	.unprepare	= clk_rpmh_bcm_unprepare,
	.set_rate	= clk_rpmh_bcm_set_rate,
	.round_rate	= clk_rpmh_round_rate,
	.recalc_rate	= clk_rpmh_bcm_recalc_rate,
};

/* Use awake state instead of active-only on RSCs that do not have an AMC. */
DEFINE_RSC_TYPE(apps_rsc, "apps", false);
DEFINE_RSC_TYPE(disp_rsc, "display", true);
@@ -306,6 +436,7 @@ DEFINE_CLK_RPMH_VRM(sdmshrike, rf_clk3, rf_clk3_ao, "rfclkd3", &apps_rsc,
DEFINE_CLK_RPMH_VRM(sdmshrike, rf_clk4, rf_clk4_ao, "rfclkd4", &apps_rsc,
		    38400000, CLK_RPMH_APPS_RSC_STATE_MASK,
		    CLK_RPMH_APPS_RSC_AO_STATE_MASK);
DEFINE_CLK_RPMH_BCM(sdxprairie, qpic_clk, "QP0", &apps_rsc);

static struct clk_hw *sm8150_rpmh_clocks[] = {
	[RPMH_CXO_CLK]		= &sm8150_bi_tcxo.hw,
@@ -374,6 +505,7 @@ static struct clk_hw *sdxprairie_rpmh_clocks[] = {
	[RPMH_RF_CLK1_A]        = &sdmshrike_rf_clk1_ao.hw,
	[RPMH_RF_CLK2]          = &sdmshrike_rf_clk2.hw,
	[RPMH_RF_CLK2_A]        = &sdmshrike_rf_clk2_ao.hw,
	[RPMH_QPIC_CLK]		= &sdxprairie_qpic_clk.hw,
};

static const struct clk_rpmh_desc clk_rpmh_sdxprairie = {
@@ -405,6 +537,8 @@ static int clk_rpmh_probe(struct platform_device *pdev)
	const struct clk_rpmh_desc *desc;
	struct property *prop;
	const char *mbox_name;
	size_t aux_data_len;
	struct bcm_db db = {0};

	desc = of_device_get_match_data(&pdev->dev);
	if (!desc) {
@@ -489,6 +623,15 @@ static int clk_rpmh_probe(struct platform_device *pdev)
			goto err2;
		}

		rpmh_clk->unit = 1000ULL;
		aux_data_len = cmd_db_get_aux_data_len(rpmh_clk->res_name);
		if (aux_data_len) {
			cmd_db_get_aux_data(rpmh_clk->res_name, (u8 *)&db,
				sizeof(struct bcm_db));
			if (db.unit)
				rpmh_clk->unit *= le32_to_cpu(db.unit);
		}

		clk = devm_clk_register(&pdev->dev, hw_clks[i]);
		if (IS_ERR(clk)) {
			ret = PTR_ERR(clk);
+2 −1
Original line number Diff line number Diff line
/*
 * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
 * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 and
@@ -29,5 +29,6 @@
#define RPMH_RF_CLK3_A						11
#define RPMH_RF_CLK4						12
#define RPMH_RF_CLK4_A						13
#define RPMH_QPIC_CLK						14

#endif