Commit 47727beb authored by Loc Ho's avatar Loc Ho Committed by Stephen Boyd

clk: xgene: Add SoC and PMD PLL clocks with v2 hardware

Add X-Gene SoC and PMD PLL clocks support for v2 hardware.
X-Gene SoC v2 and above use an slightly different SoC
and PMD PLL hardware logic.
Signed-off-by: default avatarLoc Ho <lho@apm.com>
Signed-off-by: default avatarStephen Boyd <sboyd@codeaurora.org>
parent 7b63c567
...@@ -29,7 +29,9 @@ ...@@ -29,7 +29,9 @@
#include <linux/of_address.h> #include <linux/of_address.h>
/* Register SCU_PCPPLL bit fields */ /* 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 */ /* Register SCU_SOCPLL bit fields */
#define CLKR_RD(src) (((src) & 0x07000000)>>24) #define CLKR_RD(src) (((src) & 0x07000000)>>24)
...@@ -63,6 +65,7 @@ struct xgene_clk_pll { ...@@ -63,6 +65,7 @@ struct xgene_clk_pll {
spinlock_t *lock; spinlock_t *lock;
u32 pll_offset; u32 pll_offset;
enum xgene_pll_type type; enum xgene_pll_type type;
int version;
}; };
#define to_xgene_clk_pll(_hw) container_of(_hw, struct xgene_clk_pll, hw) #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, ...@@ -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); pll = xgene_clk_read(pllclk->reg + pllclk->pll_offset);
if (pllclk->type == PLL_TYPE_PCP) { if (pllclk->version <= 1) {
/* if (pllclk->type == PLL_TYPE_PCP) {
* PLL VCO = Reference clock * NF /*
* PCP PLL = PLL_VCO / 2 * PLL VCO = Reference clock * NF
*/ * PCP PLL = PLL_VCO / 2
nout = 2; */
fvco = parent_rate * (N_DIV_RD(pll) + 4); 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 { } else {
/* /*
* Fref = Reference Clock / NREF; * fvco = Reference clock * FBDIVC
* Fvco = Fref * NFB; * PLL freq = fvco / NOUT
* Fout = Fvco / NOUT;
*/ */
nref = CLKR_RD(pll) + 1; nout = SC_OUTDIV2(pll) ? 2 : 3;
nout = CLKOD_RD(pll) + 1; fvco = parent_rate * SC_N_DIV_RD(pll);
nfb = CLKF_RD(pll);
fref = parent_rate / nref;
fvco = fref * nfb;
} }
pr_debug("%s pll recalc rate %ld parent %ld\n", clk_hw_get_name(hw), pr_debug("%s pll recalc rate %ld parent %ld version %d\n",
fvco / nout, parent_rate); clk_hw_get_name(hw), fvco / nout, parent_rate,
pllclk->version);
return fvco / nout; return fvco / nout;
} }
...@@ -125,7 +138,7 @@ static const struct clk_ops xgene_clk_pll_ops = { ...@@ -125,7 +138,7 @@ static const struct clk_ops xgene_clk_pll_ops = {
static struct clk *xgene_register_clk_pll(struct device *dev, static struct clk *xgene_register_clk_pll(struct device *dev,
const char *name, const char *parent_name, const char *name, const char *parent_name,
unsigned long flags, void __iomem *reg, u32 pll_offset, 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 xgene_clk_pll *apmclk;
struct clk *clk; struct clk *clk;
...@@ -144,6 +157,7 @@ static struct clk *xgene_register_clk_pll(struct device *dev, ...@@ -144,6 +157,7 @@ static struct clk *xgene_register_clk_pll(struct device *dev,
init.parent_names = parent_name ? &parent_name : NULL; init.parent_names = parent_name ? &parent_name : NULL;
init.num_parents = parent_name ? 1 : 0; init.num_parents = parent_name ? 1 : 0;
apmclk->version = version;
apmclk->reg = reg; apmclk->reg = reg;
apmclk->lock = lock; apmclk->lock = lock;
apmclk->pll_offset = pll_offset; apmclk->pll_offset = pll_offset;
...@@ -160,26 +174,37 @@ static struct clk *xgene_register_clk_pll(struct device *dev, ...@@ -160,26 +174,37 @@ static struct clk *xgene_register_clk_pll(struct device *dev,
return clk; 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) static void xgene_pllclk_init(struct device_node *np, enum xgene_pll_type pll_type)
{ {
const char *clk_name = np->full_name; const char *clk_name = np->full_name;
struct clk *clk; struct clk *clk;
void __iomem *reg; void __iomem *reg;
int version = xgene_pllclk_version(np);
reg = of_iomap(np, 0); reg = of_iomap(np, 0);
if (reg == NULL) { if (reg == NULL) {
pr_err("Unable to map CSR register for %s\n", np->full_name); pr_err("Unable to map CSR register for %s\n", np->full_name);
return; return;
} }
of_property_read_string(np, "clock-output-names", &clk_name); of_property_read_string(np, "clock-output-names", &clk_name);
clk = xgene_register_clk_pll(NULL, clk = xgene_register_clk_pll(NULL,
clk_name, of_clk_get_parent_name(np, 0), clk_name, of_clk_get_parent_name(np, 0),
CLK_IS_ROOT, reg, 0, pll_type, &clk_lock); CLK_IS_ROOT, reg, 0, pll_type, &clk_lock,
if (!IS_ERR(clk)) { version);
of_clk_add_provider(np, of_clk_src_simple_get, clk); if (!IS_ERR(clk)) {
clk_register_clkdev(clk, clk_name, NULL); of_clk_add_provider(np, of_clk_src_simple_get, clk);
pr_debug("Add %s clock PLL\n", clk_name); 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) static void xgene_socpllclk_init(struct device_node *np)
...@@ -460,7 +485,7 @@ static void __init xgene_devclk_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); rc = of_address_to_resource(np, i, &res);
if (rc != 0) { if (rc != 0) {
if (i == 0) { if (i == 0) {
pr_err("no DTS register for %s\n", pr_err("no DTS register for %s\n",
np->full_name); np->full_name);
return; return;
} }
...@@ -518,4 +543,8 @@ static void __init xgene_devclk_init(struct device_node *np) ...@@ -518,4 +543,8 @@ static void __init xgene_devclk_init(struct device_node *np)
CLK_OF_DECLARE(xgene_socpll_clock, "apm,xgene-socpll-clock", xgene_socpllclk_init); 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_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); CLK_OF_DECLARE(xgene_dev_clock, "apm,xgene-device-clock", xgene_devclk_init);
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment