+
static const struct clk_parent_data cbf_mux_parent_data[] = {
{ .index = DT_XO },
{ .hw = &cbf_pll.clkr.hw },
@@ -100,6 +127,13 @@ static const struct clk_parent_data
cbf_mux_parent_data[] = {
{ .index = DT_APCS_AUX },
};
+static const struct clk_parent_data cbf_pro_mux_parent_data[] = {
+ { .index = DT_XO },
+ { .hw = &cbf_pll.clkr.hw },
+ { .hw = &cbf_pro_pll_postdiv.hw },
+ { .index = DT_APCS_AUX },
+};
+
struct clk_cbf_8996_mux {
u32 reg;
struct notifier_block nb;
@@ -140,12 +174,14 @@ static int
clk_cbf_8996_mux_determine_rate(struct clk_hw *hw,
struct clk_rate_request
*req)
{
struct clk_hw *parent;
+ struct clk_hw *post_div_hw = clk_hw_get_parent_by_index(hw,
CBF_DIV_INDEX);
+ struct clk_fixed_factor *post_div =
to_clk_fixed_factor(post_div_hw);
- if (req->rate < (DIV_THRESHOLD / 2))
+ if (req->rate < (DIV_THRESHOLD / post_div->div))
return -EINVAL;
if (req->rate < DIV_THRESHOLD)
- parent = clk_hw_get_parent_by_index(hw,
CBF_DIV_INDEX);
+ parent = post_div_hw;
else
parent = clk_hw_get_parent_by_index(hw,
CBF_PLL_INDEX);
@@ -177,10 +213,24 @@ static struct clk_cbf_8996_mux cbf_mux = {
},
};
+static struct clk_cbf_8996_mux cbf_pro_mux = {
+ .reg = CBF_MUX_OFFSET,
+ .nb.notifier_call = cbf_clk_notifier_cb,
+ .clkr.hw.init = &(struct clk_init_data) {
+ .name = "cbf_mux",
+ .parent_data = cbf_pro_mux_parent_data,
+ .num_parents = ARRAY_SIZE(cbf_pro_mux_parent_data),
+ .ops = &clk_cbf_8996_mux_ops,
+ /* CPU clock is critical and should never be gated
*/
+ .flags = CLK_SET_RATE_PARENT | CLK_IS_CRITICAL,
+ },
+};
+
static int cbf_clk_notifier_cb(struct notifier_block *nb, unsigned
long event,
void *data)
{
struct clk_notifier_data *cnd = data;
+ struct clk_hw *hw = __clk_get_hw(cnd->clk);
switch (event) {
case PRE_RATE_CHANGE:
@@ -188,19 +238,19 @@ static int cbf_clk_notifier_cb(struct
notifier_block *nb, unsigned long event,
* Avoid overvolting. clk_core_set_rate_nolock()
walks from top
* to bottom, so it will change the rate of the PLL
before
* chaging the parent of PMUX. This can result in
pmux getting
- * clocked twice the expected rate.
+ * clocked twice (or 4 times) the expected rate.
*
- * Manually switch to PLL/2 here.
+ * Manually switch to PLL/DIV here.
*/
if (cnd->old_rate > DIV_THRESHOLD &&
cnd->new_rate < DIV_THRESHOLD)
-
clk_cbf_8996_mux_set_parent(&cbf_mux.clkr.hw, CBF_DIV_INDEX);
+ clk_cbf_8996_mux_set_parent(hw,
CBF_DIV_INDEX);
break;
case ABORT_RATE_CHANGE:
/* Revert manual change */
if (cnd->new_rate < DIV_THRESHOLD &&
cnd->old_rate > DIV_THRESHOLD)
-
clk_cbf_8996_mux_set_parent(&cbf_mux.clkr.hw, CBF_PLL_INDEX);
+ clk_cbf_8996_mux_set_parent(hw,
CBF_PLL_INDEX);
break;
default:
break;
@@ -213,11 +263,50 @@ static struct clk_hw *cbf_msm8996_hw_clks[] =
{
&cbf_pll_postdiv.hw,
};
+static struct clk_hw *cbf_msm8996pro_hw_clks[] = {
+ &cbf_pro_pll_postdiv.hw,
+};
+
static struct clk_regmap *cbf_msm8996_clks[] = {
&cbf_pll.clkr,
&cbf_mux.clkr,
};
+static struct clk_regmap *cbf_msm8996pro_clks[] = {
+ &cbf_pll.clkr,
+ &cbf_pro_mux.clkr,
+};
+
+struct cbf_match_data {
+ const struct alpha_pll_config *config;
+ struct clk_fixed_factor *cbf_pll_postdiv;
+ struct clk_cbf_8996_mux *cbf_mux;
+ struct clk_hw **hw_clks;
+ size_t nr_hw_clks;
+ struct clk_regmap **clks;
+ size_t nr_clks;
+};
+
+static const struct cbf_match_data cbf_msm8996_match_data = {
+ .config = &cbfpll_config,
+ .cbf_pll_postdiv = &cbf_pll_postdiv,
+ .cbf_mux = &cbf_mux,
+ .hw_clks = cbf_msm8996_hw_clks,
+ .nr_hw_clks = ARRAY_SIZE(cbf_msm8996_hw_clks),
+ .clks = cbf_msm8996_clks,
+ .nr_clks = ARRAY_SIZE(cbf_msm8996_clks)
+};
+
+static const struct cbf_match_data cbf_msm8996pro_match_data = {
+ .config = &cbfpll_pro_config,
+ .cbf_pll_postdiv = &cbf_pro_pll_postdiv,
+ .cbf_mux = &cbf_pro_mux,
+ .hw_clks = cbf_msm8996pro_hw_clks,
+ .nr_hw_clks = ARRAY_SIZE(cbf_msm8996pro_hw_clks),
+ .clks = cbf_msm8996pro_clks,
+ .nr_clks = ARRAY_SIZE(cbf_msm8996pro_clks)
+};
+
static const struct regmap_config cbf_msm8996_regmap_config = {
.reg_bits = 32,
.reg_stride = 4,
@@ -274,6 +363,7 @@ static int qcom_msm8996_cbf_probe(struct
platform_device *pdev)
void __iomem *base;
struct regmap *regmap;
struct device *dev = &pdev->dev;
+ const struct cbf_match_data *data =
of_device_get_match_data(dev);
int i, ret;
base = devm_platform_ioremap_resource(pdev, 0);
@@ -295,7 +385,7 @@ static int qcom_msm8996_cbf_probe(struct
platform_device *pdev)
CBF_MUX_AUTO_CLK_SEL_ALWAYS_ON_MASK,
CBF_MUX_AUTO_CLK_SEL_ALWAYS_ON_GPLL0_SEL);
- clk_alpha_pll_configure(&cbf_pll, regmap, &cbfpll_config);
+ clk_alpha_pll_configure(&cbf_pll, regmap, data->config);
/* Wait for PLL(s) to lock */
udelay(50);
@@ -311,27 +401,27 @@ static int qcom_msm8996_cbf_probe(struct
platform_device *pdev)
/* Switch CBF to use the primary PLL */
regmap_update_bits(regmap, CBF_MUX_OFFSET,
CBF_MUX_PARENT_MASK, 0x1);
- for (i = 0; i < ARRAY_SIZE(cbf_msm8996_hw_clks); i++) {
- ret = devm_clk_hw_register(dev,
cbf_msm8996_hw_clks[i]);
+ for (i = 0; i < data->nr_hw_clks; i++) {
+ ret = devm_clk_hw_register(dev, data->hw_clks[i]);
if (ret)
return ret;
}
- for (i = 0; i < ARRAY_SIZE(cbf_msm8996_clks); i++) {
- ret = devm_clk_register_regmap(dev,
cbf_msm8996_clks[i]);
+ for (i = 0; i < data->nr_clks; i++) {
+ ret = devm_clk_register_regmap(dev, data->clks[i]);
if (ret)
return ret;
}
- ret = devm_clk_notifier_register(dev, cbf_mux.clkr.hw.clk,
&cbf_mux.nb);
+ ret = devm_clk_notifier_register(dev,
data->cbf_mux->clkr.hw.clk, &data->cbf_mux->nb);
if (ret)
return ret;
- ret = devm_of_clk_add_hw_provider(dev,
of_clk_hw_simple_get, &cbf_mux.clkr.hw);
+ ret = devm_of_clk_add_hw_provider(dev,
of_clk_hw_simple_get, &data->cbf_mux->clkr.hw);
if (ret)
return ret;
- return qcom_msm8996_cbf_icc_register(pdev,
&cbf_mux.clkr.hw);
+ return qcom_msm8996_cbf_icc_register(pdev,
&data->cbf_mux->clkr.hw);
}
static int qcom_msm8996_cbf_remove(struct platform_device *pdev)
@@ -340,7 +430,8 @@ static int qcom_msm8996_cbf_remove(struct
platform_device *pdev)
}
static const struct of_device_id qcom_msm8996_cbf_match_table[] = {
- { .compatible = "qcom,msm8996-cbf" },
+ { .compatible = "qcom,msm8996-cbf", .data =
&cbf_msm8996_match_data },
+ { .compatible = "qcom,msm8996pro-cbf", .data =
&cbf_msm8996pro_match_data },
{ /* sentinel */ },
};
MODULE_DEVICE_TABLE(of, qcom_msm8996_cbf_match_table);
--
2.40.0