Commit e47a4f55 authored by Varadarajan Narayanan's avatar Varadarajan Narayanan Committed by Bjorn Andersson
Browse files

clk: qcom: clk-alpha-pll: Add support for Stromer PLLs

parent bfb23a53
Loading
Loading
Loading
Loading
+127 −1
Original line number Diff line number Diff line
// SPDX-License-Identifier: GPL-2.0
/*
 * Copyright (c) 2015, 2018, The Linux Foundation. All rights reserved.
 * Copyright (c) 2021, Qualcomm Innovation Center, Inc. All rights reserved.
 * Copyright (c) 2021, 2023, Qualcomm Innovation Center, Inc. All rights reserved.
 */

#include <linux/kernel.h>
@@ -204,6 +204,18 @@ const u8 clk_alpha_pll_regs[][PLL_OFF_MAX_REGS] = {
		[PLL_OFF_CONFIG_CTL] = 0x1C,
		[PLL_OFF_STATUS] = 0x20,
	},
	[CLK_ALPHA_PLL_TYPE_STROMER] = {
		[PLL_OFF_L_VAL] = 0x08,
		[PLL_OFF_ALPHA_VAL] = 0x10,
		[PLL_OFF_ALPHA_VAL_U] = 0x14,
		[PLL_OFF_USER_CTL] = 0x18,
		[PLL_OFF_USER_CTL_U] = 0x1c,
		[PLL_OFF_CONFIG_CTL] = 0x20,
		[PLL_OFF_CONFIG_CTL_U] = 0xff,
		[PLL_OFF_TEST_CTL] = 0x30,
		[PLL_OFF_TEST_CTL_U] = 0x34,
		[PLL_OFF_STATUS] = 0x28,
	},
};
EXPORT_SYMBOL_GPL(clk_alpha_pll_regs);

@@ -215,6 +227,8 @@ EXPORT_SYMBOL_GPL(clk_alpha_pll_regs);
#define ALPHA_BITWIDTH		32U
#define ALPHA_SHIFT(w)		min(w, ALPHA_BITWIDTH)

#define	ALPHA_PLL_STATUS_REG_SHIFT	8

#define PLL_HUAYRA_M_WIDTH		8
#define PLL_HUAYRA_M_SHIFT		8
#define PLL_HUAYRA_M_MASK		0xff
@@ -2329,3 +2343,115 @@ const struct clk_ops clk_alpha_pll_rivian_evo_ops = {
	.round_rate = clk_rivian_evo_pll_round_rate,
};
EXPORT_SYMBOL_GPL(clk_alpha_pll_rivian_evo_ops);

void clk_stromer_pll_configure(struct clk_alpha_pll *pll, struct regmap *regmap,
			       const struct alpha_pll_config *config)
{
	u32 val, val_u, mask, mask_u;

	regmap_write(regmap, PLL_L_VAL(pll), config->l);
	regmap_write(regmap, PLL_ALPHA_VAL(pll), config->alpha);
	regmap_write(regmap, PLL_CONFIG_CTL(pll), config->config_ctl_val);

	if (pll_has_64bit_config(pll))
		regmap_write(regmap, PLL_CONFIG_CTL_U(pll),
			     config->config_ctl_hi_val);

	if (pll_alpha_width(pll) > 32)
		regmap_write(regmap, PLL_ALPHA_VAL_U(pll), config->alpha_hi);

	val = config->main_output_mask;
	val |= config->aux_output_mask;
	val |= config->aux2_output_mask;
	val |= config->early_output_mask;
	val |= config->pre_div_val;
	val |= config->post_div_val;
	val |= config->vco_val;
	val |= config->alpha_en_mask;
	val |= config->alpha_mode_mask;

	mask = config->main_output_mask;
	mask |= config->aux_output_mask;
	mask |= config->aux2_output_mask;
	mask |= config->early_output_mask;
	mask |= config->pre_div_mask;
	mask |= config->post_div_mask;
	mask |= config->vco_mask;
	mask |= config->alpha_en_mask;
	mask |= config->alpha_mode_mask;

	regmap_update_bits(regmap, PLL_USER_CTL(pll), mask, val);

	/* Stromer APSS PLL does not enable LOCK_DET by default, so enable it */
	val_u = config->status_val << ALPHA_PLL_STATUS_REG_SHIFT;
	val_u |= config->lock_det;

	mask_u = config->status_mask;
	mask_u |= config->lock_det;

	regmap_update_bits(regmap, PLL_USER_CTL_U(pll), mask_u, val_u);
	regmap_write(regmap, PLL_TEST_CTL(pll), config->test_ctl_val);
	regmap_write(regmap, PLL_TEST_CTL_U(pll), config->test_ctl_hi_val);

	if (pll->flags & SUPPORTS_FSM_MODE)
		qcom_pll_set_fsm_mode(regmap, PLL_MODE(pll), 6, 0);
}
EXPORT_SYMBOL_GPL(clk_stromer_pll_configure);

static int clk_alpha_pll_stromer_determine_rate(struct clk_hw *hw,
						struct clk_rate_request *req)
{
	u32 l;
	u64 a;

	req->rate = alpha_pll_round_rate(req->rate, req->best_parent_rate,
					 &l, &a, ALPHA_REG_BITWIDTH);

	return 0;
}

static int clk_alpha_pll_stromer_set_rate(struct clk_hw *hw, unsigned long rate,
					  unsigned long prate)
{
	struct clk_alpha_pll *pll = to_clk_alpha_pll(hw);
	int ret;
	u32 l;
	u64 a;

	rate = alpha_pll_round_rate(rate, prate, &l, &a, ALPHA_REG_BITWIDTH);

	regmap_write(pll->clkr.regmap, PLL_L_VAL(pll), l);
	regmap_write(pll->clkr.regmap, PLL_ALPHA_VAL(pll), a);
	regmap_write(pll->clkr.regmap, PLL_ALPHA_VAL_U(pll),
		     a >> ALPHA_BITWIDTH);

	regmap_update_bits(pll->clkr.regmap, PLL_USER_CTL(pll),
			   PLL_ALPHA_EN, PLL_ALPHA_EN);

	if (!clk_hw_is_enabled(hw))
		return 0;

	/*
	 * Stromer PLL supports Dynamic programming.
	 * It allows the PLL frequency to be changed on-the-fly without first
	 * execution of a shutdown procedure followed by a bring up procedure.
	 */
	regmap_update_bits(pll->clkr.regmap, PLL_MODE(pll), PLL_UPDATE,
			   PLL_UPDATE);

	ret = wait_for_pll_update(pll);
	if (ret)
		return ret;

	return wait_for_pll_enable_lock(pll);
}

const struct clk_ops clk_alpha_pll_stromer_ops = {
	.enable = clk_alpha_pll_enable,
	.disable = clk_alpha_pll_disable,
	.is_enabled = clk_alpha_pll_is_enabled,
	.recalc_rate = clk_alpha_pll_recalc_rate,
	.determine_rate = clk_alpha_pll_stromer_determine_rate,
	.set_rate = clk_alpha_pll_stromer_set_rate,
};
EXPORT_SYMBOL_GPL(clk_alpha_pll_stromer_ops);
+12 −1
Original line number Diff line number Diff line
/* SPDX-License-Identifier: GPL-2.0 */
/* Copyright (c) 2015, 2018, The Linux Foundation. All rights reserved. */
/*
 * Copyright (c) 2015, 2018, 2021 The Linux Foundation. All rights reserved.
 * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved.
 */


#ifndef __QCOM_CLK_ALPHA_PLL_H__
#define __QCOM_CLK_ALPHA_PLL_H__
@@ -22,6 +26,7 @@ enum {
	CLK_ALPHA_PLL_TYPE_RIVIAN_EVO,
	CLK_ALPHA_PLL_TYPE_DEFAULT_EVO,
	CLK_ALPHA_PLL_TYPE_BRAMMO_EVO,
	CLK_ALPHA_PLL_TYPE_STROMER,
	CLK_ALPHA_PLL_TYPE_MAX,
};

@@ -131,6 +136,9 @@ struct alpha_pll_config {
	u32 post_div_mask;
	u32 vco_val;
	u32 vco_mask;
	u32 status_val;
	u32 status_mask;
	u32 lock_det;
};

extern const struct clk_ops clk_alpha_pll_ops;
@@ -139,6 +147,7 @@ extern const struct clk_ops clk_alpha_pll_hwfsm_ops;
extern const struct clk_ops clk_alpha_pll_postdiv_ops;
extern const struct clk_ops clk_alpha_pll_huayra_ops;
extern const struct clk_ops clk_alpha_pll_postdiv_ro_ops;
extern const struct clk_ops clk_alpha_pll_stromer_ops;

extern const struct clk_ops clk_alpha_pll_fabia_ops;
extern const struct clk_ops clk_alpha_pll_fixed_fabia_ops;
@@ -188,5 +197,7 @@ void clk_lucid_evo_pll_configure(struct clk_alpha_pll *pll, struct regmap *regma
				 const struct alpha_pll_config *config);
void clk_rivian_evo_pll_configure(struct clk_alpha_pll *pll, struct regmap *regmap,
				  const struct alpha_pll_config *config);
void clk_stromer_pll_configure(struct clk_alpha_pll *pll, struct regmap *regmap,
			       const struct alpha_pll_config *config);

#endif