|
@@ -29,7 +29,9 @@
|
|
|
#include <linux/of_address.h>
|
|
|
|
|
|
/* Register SCU_PCPPLL bit fields */
|
|
|
-#define N_DIV_RD(src) (((src) & 0x000001ff))
|
|
|
+#define N_DIV_RD(src) ((src) & 0x000001ff)
|
|
|
+#define SC_N_DIV_RD(src) ((src) & 0x0000007f)
|
|
|
+#define SC_OUTDIV2(src) (((src) & 0x00000100) >> 8)
|
|
|
|
|
|
/* Register SCU_SOCPLL bit fields */
|
|
|
#define CLKR_RD(src) (((src) & 0x07000000)>>24)
|
|
@@ -63,6 +65,7 @@ struct xgene_clk_pll {
|
|
|
spinlock_t *lock;
|
|
|
u32 pll_offset;
|
|
|
enum xgene_pll_type type;
|
|
|
+ int version;
|
|
|
};
|
|
|
|
|
|
#define to_xgene_clk_pll(_hw) container_of(_hw, struct xgene_clk_pll, hw)
|
|
@@ -92,27 +95,37 @@ static unsigned long xgene_clk_pll_recalc_rate(struct clk_hw *hw,
|
|
|
|
|
|
pll = xgene_clk_read(pllclk->reg + pllclk->pll_offset);
|
|
|
|
|
|
- if (pllclk->type == PLL_TYPE_PCP) {
|
|
|
- /*
|
|
|
- * PLL VCO = Reference clock * NF
|
|
|
- * PCP PLL = PLL_VCO / 2
|
|
|
- */
|
|
|
- nout = 2;
|
|
|
- fvco = parent_rate * (N_DIV_RD(pll) + 4);
|
|
|
+ if (pllclk->version <= 1) {
|
|
|
+ if (pllclk->type == PLL_TYPE_PCP) {
|
|
|
+ /*
|
|
|
+ * PLL VCO = Reference clock * NF
|
|
|
+ * PCP PLL = PLL_VCO / 2
|
|
|
+ */
|
|
|
+ nout = 2;
|
|
|
+ fvco = parent_rate * (N_DIV_RD(pll) + 4);
|
|
|
+ } else {
|
|
|
+ /*
|
|
|
+ * Fref = Reference Clock / NREF;
|
|
|
+ * Fvco = Fref * NFB;
|
|
|
+ * Fout = Fvco / NOUT;
|
|
|
+ */
|
|
|
+ nref = CLKR_RD(pll) + 1;
|
|
|
+ nout = CLKOD_RD(pll) + 1;
|
|
|
+ nfb = CLKF_RD(pll);
|
|
|
+ fref = parent_rate / nref;
|
|
|
+ fvco = fref * nfb;
|
|
|
+ }
|
|
|
} else {
|
|
|
/*
|
|
|
- * Fref = Reference Clock / NREF;
|
|
|
- * Fvco = Fref * NFB;
|
|
|
- * Fout = Fvco / NOUT;
|
|
|
+ * fvco = Reference clock * FBDIVC
|
|
|
+ * PLL freq = fvco / NOUT
|
|
|
*/
|
|
|
- nref = CLKR_RD(pll) + 1;
|
|
|
- nout = CLKOD_RD(pll) + 1;
|
|
|
- nfb = CLKF_RD(pll);
|
|
|
- fref = parent_rate / nref;
|
|
|
- fvco = fref * nfb;
|
|
|
+ nout = SC_OUTDIV2(pll) ? 2 : 3;
|
|
|
+ fvco = parent_rate * SC_N_DIV_RD(pll);
|
|
|
}
|
|
|
- pr_debug("%s pll recalc rate %ld parent %ld\n", clk_hw_get_name(hw),
|
|
|
- fvco / nout, parent_rate);
|
|
|
+ pr_debug("%s pll recalc rate %ld parent %ld version %d\n",
|
|
|
+ clk_hw_get_name(hw), fvco / nout, parent_rate,
|
|
|
+ pllclk->version);
|
|
|
|
|
|
return fvco / nout;
|
|
|
}
|
|
@@ -125,7 +138,7 @@ static const struct clk_ops xgene_clk_pll_ops = {
|
|
|
static struct clk *xgene_register_clk_pll(struct device *dev,
|
|
|
const char *name, const char *parent_name,
|
|
|
unsigned long flags, void __iomem *reg, u32 pll_offset,
|
|
|
- u32 type, spinlock_t *lock)
|
|
|
+ u32 type, spinlock_t *lock, int version)
|
|
|
{
|
|
|
struct xgene_clk_pll *apmclk;
|
|
|
struct clk *clk;
|
|
@@ -144,6 +157,7 @@ static struct clk *xgene_register_clk_pll(struct device *dev,
|
|
|
init.parent_names = parent_name ? &parent_name : NULL;
|
|
|
init.num_parents = parent_name ? 1 : 0;
|
|
|
|
|
|
+ apmclk->version = version;
|
|
|
apmclk->reg = reg;
|
|
|
apmclk->lock = lock;
|
|
|
apmclk->pll_offset = pll_offset;
|
|
@@ -160,26 +174,37 @@ static struct clk *xgene_register_clk_pll(struct device *dev,
|
|
|
return clk;
|
|
|
}
|
|
|
|
|
|
+static int xgene_pllclk_version(struct device_node *np)
|
|
|
+{
|
|
|
+ if (of_device_is_compatible(np, "apm,xgene-socpll-clock"))
|
|
|
+ return 1;
|
|
|
+ if (of_device_is_compatible(np, "apm,xgene-pcppll-clock"))
|
|
|
+ return 1;
|
|
|
+ return 2;
|
|
|
+}
|
|
|
+
|
|
|
static void xgene_pllclk_init(struct device_node *np, enum xgene_pll_type pll_type)
|
|
|
{
|
|
|
- const char *clk_name = np->full_name;
|
|
|
- struct clk *clk;
|
|
|
- void __iomem *reg;
|
|
|
+ const char *clk_name = np->full_name;
|
|
|
+ struct clk *clk;
|
|
|
+ void __iomem *reg;
|
|
|
+ int version = xgene_pllclk_version(np);
|
|
|
|
|
|
- reg = of_iomap(np, 0);
|
|
|
- if (reg == NULL) {
|
|
|
- pr_err("Unable to map CSR register for %s\n", np->full_name);
|
|
|
- return;
|
|
|
- }
|
|
|
- of_property_read_string(np, "clock-output-names", &clk_name);
|
|
|
- clk = xgene_register_clk_pll(NULL,
|
|
|
- clk_name, of_clk_get_parent_name(np, 0),
|
|
|
- CLK_IS_ROOT, reg, 0, pll_type, &clk_lock);
|
|
|
- if (!IS_ERR(clk)) {
|
|
|
- of_clk_add_provider(np, of_clk_src_simple_get, clk);
|
|
|
- clk_register_clkdev(clk, clk_name, NULL);
|
|
|
- pr_debug("Add %s clock PLL\n", clk_name);
|
|
|
- }
|
|
|
+ reg = of_iomap(np, 0);
|
|
|
+ if (reg == NULL) {
|
|
|
+ pr_err("Unable to map CSR register for %s\n", np->full_name);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ of_property_read_string(np, "clock-output-names", &clk_name);
|
|
|
+ clk = xgene_register_clk_pll(NULL,
|
|
|
+ clk_name, of_clk_get_parent_name(np, 0),
|
|
|
+ CLK_IS_ROOT, reg, 0, pll_type, &clk_lock,
|
|
|
+ version);
|
|
|
+ if (!IS_ERR(clk)) {
|
|
|
+ of_clk_add_provider(np, of_clk_src_simple_get, clk);
|
|
|
+ clk_register_clkdev(clk, clk_name, NULL);
|
|
|
+ pr_debug("Add %s clock PLL\n", clk_name);
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
static void xgene_socpllclk_init(struct device_node *np)
|
|
@@ -460,7 +485,7 @@ static void __init xgene_devclk_init(struct device_node *np)
|
|
|
rc = of_address_to_resource(np, i, &res);
|
|
|
if (rc != 0) {
|
|
|
if (i == 0) {
|
|
|
- pr_err("no DTS register for %s\n",
|
|
|
+ pr_err("no DTS register for %s\n",
|
|
|
np->full_name);
|
|
|
return;
|
|
|
}
|
|
@@ -518,4 +543,8 @@ err:
|
|
|
|
|
|
CLK_OF_DECLARE(xgene_socpll_clock, "apm,xgene-socpll-clock", xgene_socpllclk_init);
|
|
|
CLK_OF_DECLARE(xgene_pcppll_clock, "apm,xgene-pcppll-clock", xgene_pcppllclk_init);
|
|
|
+CLK_OF_DECLARE(xgene_socpll_v2_clock, "apm,xgene-socpll-v2-clock",
|
|
|
+ xgene_socpllclk_init);
|
|
|
+CLK_OF_DECLARE(xgene_pcppll_v2_clock, "apm,xgene-pcppll-v2-clock",
|
|
|
+ xgene_pcppllclk_init);
|
|
|
CLK_OF_DECLARE(xgene_dev_clock, "apm,xgene-device-clock", xgene_devclk_init);
|