Commit 8b9d9e9f authored by Stephen Boyd's avatar Stephen Boyd
Browse files

Merge tag 'for-5.19-clk' of...

Merge tag 'for-5.19-clk' of git://git.kernel.org/pub/scm/linux/kernel/git/tegra/linux into clk-tegra

Pull Tegra clk driver updates from Thierry Reding:

This contains a boot time optimization for Tegra chips with BPMP and a
switch from .round_rate() to .determine_rate() to take into account any
maximum rate that might have been set.

Other than that this contains a fix for a DFLL regression on Tegra210
and kerneldoc fixups to avoid build warnings.

* tag 'for-5.19-clk' of git://git.kernel.org/pub/scm/linux/kernel/git/tegra/linux:
  clk: tegra: Update kerneldoc to match prototypes
  clk: tegra: Replace .round_rate() with .determine_rate()
  clk: tegra: Register clocks from root to leaf
  clk: tegra: Add missing reset deassertion
parents 31231092 6f6baf69
Loading
Loading
Loading
Loading
+66 −21
Original line number Diff line number Diff line
@@ -164,15 +164,18 @@ static unsigned long tegra_bpmp_clk_recalc_rate(struct clk_hw *hw,
	return response.rate;
}

static long tegra_bpmp_clk_round_rate(struct clk_hw *hw, unsigned long rate,
				      unsigned long *parent_rate)
static int tegra_bpmp_clk_determine_rate(struct clk_hw *hw,
					 struct clk_rate_request *rate_req)
{
	struct tegra_bpmp_clk *clk = to_tegra_bpmp_clk(hw);
	struct cmd_clk_round_rate_response response;
	struct cmd_clk_round_rate_request request;
	struct tegra_bpmp_clk_message msg;
	unsigned long rate;
	int err;

	rate = min(max(rate_req->rate, rate_req->min_rate), rate_req->max_rate);

	memset(&request, 0, sizeof(request));
	request.rate = min_t(u64, rate, S64_MAX);

@@ -188,7 +191,9 @@ static long tegra_bpmp_clk_round_rate(struct clk_hw *hw, unsigned long rate,
	if (err < 0)
		return err;

	return response.rate;
	rate_req->rate = (unsigned long)response.rate;

	return 0;
}

static int tegra_bpmp_clk_set_parent(struct clk_hw *hw, u8 index)
@@ -290,7 +295,7 @@ static const struct clk_ops tegra_bpmp_clk_rate_ops = {
	.unprepare = tegra_bpmp_clk_unprepare,
	.is_prepared = tegra_bpmp_clk_is_prepared,
	.recalc_rate = tegra_bpmp_clk_recalc_rate,
	.round_rate = tegra_bpmp_clk_round_rate,
	.determine_rate = tegra_bpmp_clk_determine_rate,
	.set_rate = tegra_bpmp_clk_set_rate,
};

@@ -299,7 +304,7 @@ static const struct clk_ops tegra_bpmp_clk_mux_rate_ops = {
	.unprepare = tegra_bpmp_clk_unprepare,
	.is_prepared = tegra_bpmp_clk_is_prepared,
	.recalc_rate = tegra_bpmp_clk_recalc_rate,
	.round_rate = tegra_bpmp_clk_round_rate,
	.determine_rate = tegra_bpmp_clk_determine_rate,
	.set_parent = tegra_bpmp_clk_set_parent,
	.get_parent = tegra_bpmp_clk_get_parent,
	.set_rate = tegra_bpmp_clk_set_rate,
@@ -448,14 +453,28 @@ static int tegra_bpmp_probe_clocks(struct tegra_bpmp *bpmp,
	return count;
}

static const struct tegra_bpmp_clk_info *
tegra_bpmp_clk_find(const struct tegra_bpmp_clk_info *clocks,
static unsigned int
tegra_bpmp_clk_id_to_index(const struct tegra_bpmp_clk_info *clocks,
			   unsigned int num_clocks, unsigned int id)
{
	unsigned int i;

	for (i = 0; i < num_clocks; i++)
		if (clocks[i].id == id)
			return i;

	return UINT_MAX;
}

static const struct tegra_bpmp_clk_info *
tegra_bpmp_clk_find(const struct tegra_bpmp_clk_info *clocks,
		    unsigned int num_clocks, unsigned int id)
{
	unsigned int i;

	i = tegra_bpmp_clk_id_to_index(clocks, num_clocks, id);

	if (i < num_clocks)
		return &clocks[i];

	return NULL;
@@ -539,33 +558,59 @@ tegra_bpmp_clk_register(struct tegra_bpmp *bpmp,
	return clk;
}

static int tegra_bpmp_register_clocks(struct tegra_bpmp *bpmp,
static void tegra_bpmp_register_clocks_one(struct tegra_bpmp *bpmp,
					   struct tegra_bpmp_clk_info *infos,
					   unsigned int i,
					   unsigned int count)
{
	unsigned int j;
	struct tegra_bpmp_clk_info *info;
	struct tegra_bpmp_clk *clk;
	unsigned int i;

	bpmp->num_clocks = count;

	bpmp->clocks = devm_kcalloc(bpmp->dev, count, sizeof(clk), GFP_KERNEL);
	if (!bpmp->clocks)
		return -ENOMEM;
	if (bpmp->clocks[i]) {
		/* already registered */
		return;
	}

	for (i = 0; i < count; i++) {
		struct tegra_bpmp_clk_info *info = &infos[i];
	info = &infos[i];
	for (j = 0; j < info->num_parents; ++j) {
		unsigned int p_id = info->parents[j];
		unsigned int p_i = tegra_bpmp_clk_id_to_index(infos, count,
							      p_id);
		if (p_i < count)
			tegra_bpmp_register_clocks_one(bpmp, infos, p_i, count);
	}

	clk = tegra_bpmp_clk_register(bpmp, info, infos, count);
	if (IS_ERR(clk)) {
		dev_err(bpmp->dev,
			"failed to register clock %u (%s): %ld\n",
			info->id, info->name, PTR_ERR(clk));
			continue;
		/* intentionally store the error pointer to
		 * bpmp->clocks[i] to avoid re-attempting the
		 * registration later
		 */
	}

	bpmp->clocks[i] = clk;
}

static int tegra_bpmp_register_clocks(struct tegra_bpmp *bpmp,
				      struct tegra_bpmp_clk_info *infos,
				      unsigned int count)
{
	unsigned int i;

	bpmp->num_clocks = count;

	bpmp->clocks = devm_kcalloc(bpmp->dev, count, sizeof(struct tegra_bpmp_clk), GFP_KERNEL);
	if (!bpmp->clocks)
		return -ENOMEM;

	for (i = 0; i < count; i++) {
		tegra_bpmp_register_clocks_one(bpmp, infos, i, count);
	}

	return 0;
}

+16 −4
Original line number Diff line number Diff line
@@ -271,6 +271,7 @@ struct tegra_dfll {
	struct clk			*ref_clk;
	struct clk			*i2c_clk;
	struct clk			*dfll_clk;
	struct reset_control		*dfll_rst;
	struct reset_control		*dvco_rst;
	unsigned long			ref_rate;
	unsigned long			i2c_clk_rate;
@@ -666,7 +667,7 @@ static int dfll_force_output(struct tegra_dfll *td, unsigned int out_sel)
}

/**
 * dfll_load_lut - load the voltage lookup table
 * dfll_load_i2c_lut - load the voltage lookup table
 * @td: struct tegra_dfll *
 *
 * Load the voltage-to-PMIC register value lookup table into the DFLL
@@ -897,7 +898,7 @@ static void dfll_set_frequency_request(struct tegra_dfll *td,
}

/**
 * tegra_dfll_request_rate - set the next rate for the DFLL to tune to
 * dfll_request_rate - set the next rate for the DFLL to tune to
 * @td: DFLL instance
 * @rate: clock rate to target
 *
@@ -1005,7 +1006,7 @@ static void dfll_set_open_loop_config(struct tegra_dfll *td)
}

/**
 * tegra_dfll_lock - switch from open-loop to closed-loop mode
 * dfll_lock - switch from open-loop to closed-loop mode
 * @td: DFLL instance
 *
 * Switch from OPEN_LOOP state to CLOSED_LOOP state. Returns 0 upon success,
@@ -1046,7 +1047,7 @@ static int dfll_lock(struct tegra_dfll *td)
}

/**
 * tegra_dfll_unlock - switch from closed-loop to open-loop mode
 * dfll_unlock - switch from closed-loop to open-loop mode
 * @td: DFLL instance
 *
 * Switch from CLOSED_LOOP state to OPEN_LOOP state. Returns 0 upon success,
@@ -1464,6 +1465,7 @@ static int dfll_init(struct tegra_dfll *td)
		return -EINVAL;
	}

	reset_control_deassert(td->dfll_rst);
	reset_control_deassert(td->dvco_rst);

	ret = clk_prepare(td->ref_clk);
@@ -1509,6 +1511,7 @@ static int dfll_init(struct tegra_dfll *td)
	clk_unprepare(td->ref_clk);

	reset_control_assert(td->dvco_rst);
	reset_control_assert(td->dfll_rst);

	return ret;
}
@@ -1530,6 +1533,7 @@ int tegra_dfll_suspend(struct device *dev)
	}

	reset_control_assert(td->dvco_rst);
	reset_control_assert(td->dfll_rst);

	return 0;
}
@@ -1548,6 +1552,7 @@ int tegra_dfll_resume(struct device *dev)
{
	struct tegra_dfll *td = dev_get_drvdata(dev);

	reset_control_deassert(td->dfll_rst);
	reset_control_deassert(td->dvco_rst);

	pm_runtime_get_sync(td->dev);
@@ -1951,6 +1956,12 @@ int tegra_dfll_register(struct platform_device *pdev,

	td->soc = soc;

	td->dfll_rst = devm_reset_control_get_optional(td->dev, "dfll");
	if (IS_ERR(td->dfll_rst)) {
		dev_err(td->dev, "couldn't get dfll reset\n");
		return PTR_ERR(td->dfll_rst);
	}

	td->dvco_rst = devm_reset_control_get(td->dev, "dvco");
	if (IS_ERR(td->dvco_rst)) {
		dev_err(td->dev, "couldn't get dvco reset\n");
@@ -2087,6 +2098,7 @@ struct tegra_dfll_soc_data *tegra_dfll_unregister(struct platform_device *pdev)
	clk_unprepare(td->i2c_clk);

	reset_control_assert(td->dvco_rst);
	reset_control_assert(td->dfll_rst);

	return td->soc;
}