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

Commit 4e9682c3 authored by Patrick Daly's avatar Patrick Daly Committed by Deepak Katragadda
Browse files

clk: clock-alpha-pll: Support parsing alpha-pll clocks from dt



Alpha PLL clocks are a type of PLLs which provide an output rate of
output = input * ( L + a * 2 ^-40).
Allow defining this clock type in dt.

Change-Id: I062e502d9217332bca4e7df6fa6b8c62ac313d23
Signed-off-by: default avatarPatrick Daly <pdaly@codeaurora.org>
parent a0bba46a
Loading
Loading
Loading
Loading
+71 −0
Original line number Diff line number Diff line
@@ -654,3 +654,74 @@ pcie0_reset_clk: pcie0_reset_clk {
	compatible = "qcom,reset-clk";
	qcom,base-offset = <GCC_PCIE0_BCR>;
};

*****************************************************************************

"qcom,alpha-pll"

Alpha PLL clocks are a type of PLL which produces an output rate of
output = input * ( L + a * 2 ^-40).

Required Properties:
- compatible:		"qcom,alpha-pll-20t", "qcom,alpha-pll-20p"
- qcom,base-offset:	Register offset from top level clock controller.

Recommended Properties:
- qcom,clk-fmax:	See "General Optional Properties"
- qcom,supply-group:	See "General Optional Properties"
- qcom,parent:		See "General Optional Properties"

Optional Properties:
- qcom,output-enable:	Masked PLL output setting.
- qcom,post-div-config:	Masked post divider setting.

cci_pll: cci_pll {
	compatible = "qcom,alpha-pll-20p";
	qcom,base-offset = <CCI_PLL_MODE>;
	qcom,parent = <&ao_xo>;
	qcom,supply-group = <&mmss_vdd_dig>;
	qcom,clk-fmax =
		<FMAX_LOW 1000000000>;
	qcom,output-enable = <0x9>;
	qcom,post-div-config = <0x100>;
};

*****************************************************************************

"qcom,fixed-alpha-pll"

This particular instance of alpha-pll allows setting a rate once at bootup, after
which the rate is immutable.

Required Properties:
- compatible:		"qcom,fixed-alpha-pll-20t", "qcom,fixed-alpha-pll-20p"
- qcom,base-offset:	Register offset from top level clock controller.
- qcom,pll-config-rate:	Indicates that the pll should be configured to a fixed rate
			at initialization.
- qcom,output-enable:	Masked PLL output setting.

Recommended Properties:
- qcom,clk-fmax:	See "General Optional Properties"
- qcom,supply-group:	See "General Optional Properties"
- qcom,parent:		See "General Optional Properties"

Optional Properties:
- qcom,fsm-en-bit:	Indicates that the pll is votable; the timing between
			the steps to enable the pll is handled by a fsm.
- qcom,fsm-en-offset:	Register offset for the vote register.
			If fsm-en-bit is defined, this property is required.
- qcom,post-div-config:	Masked post divider setting.

mmpll8: mmpll8 {
	compatible = "qcom,fixed-alpha-pll-20p";
	qcom,base-offset = <MMSS_MMPLL8_MODE>;
	qcom,pll-config-rate = <1050000000>;
	qcom,parent = <&mmsscc_xo>;
	qcom,supply-group = <&mmss_vdd_dig>;
	qcom,clk-fmax =
		<FMAX_LOWER 650000000>,
		<FMAX_LOW 650000000>,
		<FMAX_NOM 1300000000>,
		<FMAX_TURBO 1300000000>;
	qcom,output-enable = <0x1>;
};
+140 −0
Original line number Diff line number Diff line
@@ -12,12 +12,15 @@
 *
 */

#define pr_fmt(fmt) "%s: " fmt, __func__

#include <linux/kernel.h>
#include <linux/delay.h>
#include <linux/err.h>
#include <linux/clk.h>
#include <linux/io.h>
#include <soc/qcom/clock-alpha-pll.h>
#include <soc/qcom/msm-clock-controller.h>

#include "clock.h"

@@ -454,3 +457,140 @@ struct clk_ops clk_ops_fixed_alpha_pll = {
	.handoff = alpha_pll_handoff,
};

static struct alpha_pll_masks masks_20nm_p = {
	.lock_mask = BIT(31),
	.active_mask = BIT(30),
	.vco_mask = BM(21, 20) >> 20,
	.vco_shift = 20,
	.alpha_en_mask = BIT(24),
	.output_mask = 0xF,
	.post_div_mask = 0xF00,
};

static struct alpha_pll_vco_tbl vco_20nm_p[] = {
	VCO(3,  250000000,  500000000),
	VCO(2,  500000000, 1000000000),
	VCO(1, 1000000000, 1500000000),
	VCO(0, 1500000000, 2000000000),
};

static struct alpha_pll_masks masks_20nm_t = {
	.lock_mask = BIT(31),
	.alpha_en_mask = BIT(24),
	.output_mask = 0xf,
};

static struct alpha_pll_vco_tbl vco_20nm_t[] = {
	VCO(0, 500000000, 1250000000),
};

static struct alpha_pll_clk *alpha_pll_dt_parser(struct device *dev,
						struct device_node *np)
{
	struct alpha_pll_clk *pll;
	struct msmclk_data *drv;

	pll = devm_kzalloc(dev, sizeof(*pll), GFP_KERNEL);
	if (!pll) {
		dt_err(np, "memory alloc failure\n");
		return ERR_PTR(-ENOMEM);
	}

	if (of_property_read_u32(np, "qcom,base-offset", &pll->offset)) {
		dt_err(np, "missing qcom,base-offset\n");
		return ERR_PTR(-EINVAL);
	}

	/* Optional property */
	of_property_read_u32(np, "qcom,post-div-config",
					&pll->post_div_config);

	pll->masks = devm_kzalloc(dev, sizeof(*pll->masks), GFP_KERNEL);
	if (!pll->masks) {
		dt_err(np, "memory alloc failure\n");
		return ERR_PTR(-ENOMEM);
	}

	if (of_device_is_compatible(np, "qcom,fixed-alpha-pll-20p") ||
		of_device_is_compatible(np, "qcom,alpha-pll-20p")) {
		*pll->masks = masks_20nm_p;
		pll->vco_tbl = vco_20nm_p;
		pll->num_vco = ARRAY_SIZE(vco_20nm_p);
	} else if (of_device_is_compatible(np, "qcom,fixed-alpha-pll-20t") ||
		of_device_is_compatible(np, "qcom,alpha-pll-20t")) {
		*pll->masks = masks_20nm_t;
		pll->vco_tbl = vco_20nm_t;
		pll->num_vco = ARRAY_SIZE(vco_20nm_t);
	} else {
		dt_err(np, "unexpected compatible string\n");
		return ERR_PTR(-EINVAL);
	}

	drv = msmclk_parse_phandle(dev, np->parent->phandle);
	if (IS_ERR_OR_NULL(drv))
		return ERR_CAST(drv);
	pll->base = &drv->base;
	return pll;
}

static void *variable_rate_alpha_pll_dt_parser(struct device *dev,
					struct device_node *np)
{
	struct alpha_pll_clk *pll;

	pll = alpha_pll_dt_parser(dev, np);
	if (IS_ERR(pll))
		return pll;

	/* Optional Property */
	of_property_read_u32(np, "qcom,output-enable", &pll->enable_config);

	pll->c.ops = &clk_ops_alpha_pll;
	return msmclk_generic_clk_init(dev, np, &pll->c);
}

static void *fixed_rate_alpha_pll_dt_parser(struct device *dev,
						struct device_node *np)
{
	struct alpha_pll_clk *pll;
	int rc;
	u32 val;

	pll = alpha_pll_dt_parser(dev, np);
	if (IS_ERR(pll))
		return pll;

	rc = of_property_read_u32(np, "qcom,pll-config-rate", &val);
	if (rc) {
		dt_err(np, "missing qcom,pll-config-rate\n");
		return ERR_PTR(-EINVAL);
	}
	pll->c.rate = val;

	rc = of_property_read_u32(np, "qcom,output-enable",
						&pll->enable_config);
	if (rc) {
		dt_err(np, "missing qcom,output-enable\n");
		return ERR_PTR(-EINVAL);
	}

	/* Optional Property */
	rc = of_property_read_u32(np, "qcom,fsm-en-bit", &val);
	if (!rc) {
		rc = of_property_read_u32(np, "qcom,fsm-en-offset",
						&pll->fsm_reg_offset);
		if (rc) {
			dt_err(np, "missing qcom,fsm-en-offset\n");
			return ERR_PTR(-EINVAL);
		}
		pll->fsm_en_mask = BIT(val);
	}

	pll->c.ops = &clk_ops_fixed_alpha_pll;
	return msmclk_generic_clk_init(dev, np, &pll->c);
}

MSMCLK_PARSER(fixed_rate_alpha_pll_dt_parser, "qcom,fixed-alpha-pll-20p", 0);
MSMCLK_PARSER(fixed_rate_alpha_pll_dt_parser, "qcom,fixed-alpha-pll-20t", 1);
MSMCLK_PARSER(variable_rate_alpha_pll_dt_parser, "qcom,alpha-pll-20p", 0);
MSMCLK_PARSER(variable_rate_alpha_pll_dt_parser, "qcom,alpha-pll-20t", 1);
+3 −3
Original line number Diff line number Diff line
@@ -44,11 +44,11 @@ struct alpha_pll_vco_tbl {
struct alpha_pll_clk {
	struct alpha_pll_masks *masks;
	void *const __iomem *base;
	const u32 offset;
	u32 offset;

	/* if fsm_en_mask is set, config PLL to FSM mode */
	const u32 fsm_reg_offset;
	const u32 fsm_en_mask;
	u32 fsm_reg_offset;
	u32 fsm_en_mask;

	u32 enable_config;	/* bitmask of outputs to be enabled */
	u32 post_div_config;	/* masked post divider setting */