aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLoc Ho <lho@apm.com>2016-01-19 21:27:42 -0500
committerStephen Boyd <sboyd@codeaurora.org>2016-01-29 15:54:35 -0500
commit47727beb26569725f6c200cde2c38bd1e9f6f1b0 (patch)
tree408a5ba5f1835574520da37ab233d374a6c5a0e3
parent7b63c567b5b3b3e366e6555d764318a75073f2c7 (diff)
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: Loc Ho <lho@apm.com> Signed-off-by: Stephen Boyd <sboyd@codeaurora.org>
-rw-r--r--drivers/clk/clk-xgene.c103
1 files changed, 66 insertions, 37 deletions
diff --git a/drivers/clk/clk-xgene.c b/drivers/clk/clk-xgene.c
index 10224b01b97c..266d573b9134 100644
--- a/drivers/clk/clk-xgene.c
+++ b/drivers/clk/clk-xgene.c
@@ -29,7 +29,9 @@
29#include <linux/of_address.h> 29#include <linux/of_address.h>
30 30
31/* Register SCU_PCPPLL bit fields */ 31/* Register SCU_PCPPLL bit fields */
32#define N_DIV_RD(src) (((src) & 0x000001ff)) 32#define N_DIV_RD(src) ((src) & 0x000001ff)
33#define SC_N_DIV_RD(src) ((src) & 0x0000007f)
34#define SC_OUTDIV2(src) (((src) & 0x00000100) >> 8)
33 35
34/* Register SCU_SOCPLL bit fields */ 36/* Register SCU_SOCPLL bit fields */
35#define CLKR_RD(src) (((src) & 0x07000000)>>24) 37#define CLKR_RD(src) (((src) & 0x07000000)>>24)
@@ -63,6 +65,7 @@ struct xgene_clk_pll {
63 spinlock_t *lock; 65 spinlock_t *lock;
64 u32 pll_offset; 66 u32 pll_offset;
65 enum xgene_pll_type type; 67 enum xgene_pll_type type;
68 int version;
66}; 69};
67 70
68#define to_xgene_clk_pll(_hw) container_of(_hw, struct xgene_clk_pll, hw) 71#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 95
93 pll = xgene_clk_read(pllclk->reg + pllclk->pll_offset); 96 pll = xgene_clk_read(pllclk->reg + pllclk->pll_offset);
94 97
95 if (pllclk->type == PLL_TYPE_PCP) { 98 if (pllclk->version <= 1) {
96 /* 99 if (pllclk->type == PLL_TYPE_PCP) {
97 * PLL VCO = Reference clock * NF 100 /*
98 * PCP PLL = PLL_VCO / 2 101 * PLL VCO = Reference clock * NF
99 */ 102 * PCP PLL = PLL_VCO / 2
100 nout = 2; 103 */
101 fvco = parent_rate * (N_DIV_RD(pll) + 4); 104 nout = 2;
105 fvco = parent_rate * (N_DIV_RD(pll) + 4);
106 } else {
107 /*
108 * Fref = Reference Clock / NREF;
109 * Fvco = Fref * NFB;
110 * Fout = Fvco / NOUT;
111 */
112 nref = CLKR_RD(pll) + 1;
113 nout = CLKOD_RD(pll) + 1;
114 nfb = CLKF_RD(pll);
115 fref = parent_rate / nref;
116 fvco = fref * nfb;
117 }
102 } else { 118 } else {
103 /* 119 /*
104 * Fref = Reference Clock / NREF; 120 * fvco = Reference clock * FBDIVC
105 * Fvco = Fref * NFB; 121 * PLL freq = fvco / NOUT
106 * Fout = Fvco / NOUT;
107 */ 122 */
108 nref = CLKR_RD(pll) + 1; 123 nout = SC_OUTDIV2(pll) ? 2 : 3;
109 nout = CLKOD_RD(pll) + 1; 124 fvco = parent_rate * SC_N_DIV_RD(pll);
110 nfb = CLKF_RD(pll);
111 fref = parent_rate / nref;
112 fvco = fref * nfb;
113 } 125 }
114 pr_debug("%s pll recalc rate %ld parent %ld\n", clk_hw_get_name(hw), 126 pr_debug("%s pll recalc rate %ld parent %ld version %d\n",
115 fvco / nout, parent_rate); 127 clk_hw_get_name(hw), fvco / nout, parent_rate,
128 pllclk->version);
116 129
117 return fvco / nout; 130 return fvco / nout;
118} 131}
@@ -125,7 +138,7 @@ static const struct clk_ops xgene_clk_pll_ops = {
125static struct clk *xgene_register_clk_pll(struct device *dev, 138static struct clk *xgene_register_clk_pll(struct device *dev,
126 const char *name, const char *parent_name, 139 const char *name, const char *parent_name,
127 unsigned long flags, void __iomem *reg, u32 pll_offset, 140 unsigned long flags, void __iomem *reg, u32 pll_offset,
128 u32 type, spinlock_t *lock) 141 u32 type, spinlock_t *lock, int version)
129{ 142{
130 struct xgene_clk_pll *apmclk; 143 struct xgene_clk_pll *apmclk;
131 struct clk *clk; 144 struct clk *clk;
@@ -144,6 +157,7 @@ static struct clk *xgene_register_clk_pll(struct device *dev,
144 init.parent_names = parent_name ? &parent_name : NULL; 157 init.parent_names = parent_name ? &parent_name : NULL;
145 init.num_parents = parent_name ? 1 : 0; 158 init.num_parents = parent_name ? 1 : 0;
146 159
160 apmclk->version = version;
147 apmclk->reg = reg; 161 apmclk->reg = reg;
148 apmclk->lock = lock; 162 apmclk->lock = lock;
149 apmclk->pll_offset = pll_offset; 163 apmclk->pll_offset = pll_offset;
@@ -160,26 +174,37 @@ static struct clk *xgene_register_clk_pll(struct device *dev,
160 return clk; 174 return clk;
161} 175}
162 176
177static int xgene_pllclk_version(struct device_node *np)
178{
179 if (of_device_is_compatible(np, "apm,xgene-socpll-clock"))
180 return 1;
181 if (of_device_is_compatible(np, "apm,xgene-pcppll-clock"))
182 return 1;
183 return 2;
184}
185
163static void xgene_pllclk_init(struct device_node *np, enum xgene_pll_type pll_type) 186static void xgene_pllclk_init(struct device_node *np, enum xgene_pll_type pll_type)
164{ 187{
165 const char *clk_name = np->full_name; 188 const char *clk_name = np->full_name;
166 struct clk *clk; 189 struct clk *clk;
167 void __iomem *reg; 190 void __iomem *reg;
191 int version = xgene_pllclk_version(np);
168 192
169 reg = of_iomap(np, 0); 193 reg = of_iomap(np, 0);
170 if (reg == NULL) { 194 if (reg == NULL) {
171 pr_err("Unable to map CSR register for %s\n", np->full_name); 195 pr_err("Unable to map CSR register for %s\n", np->full_name);
172 return; 196 return;
173 } 197 }
174 of_property_read_string(np, "clock-output-names", &clk_name); 198 of_property_read_string(np, "clock-output-names", &clk_name);
175 clk = xgene_register_clk_pll(NULL, 199 clk = xgene_register_clk_pll(NULL,
176 clk_name, of_clk_get_parent_name(np, 0), 200 clk_name, of_clk_get_parent_name(np, 0),
177 CLK_IS_ROOT, reg, 0, pll_type, &clk_lock); 201 CLK_IS_ROOT, reg, 0, pll_type, &clk_lock,
178 if (!IS_ERR(clk)) { 202 version);
179 of_clk_add_provider(np, of_clk_src_simple_get, clk); 203 if (!IS_ERR(clk)) {
180 clk_register_clkdev(clk, clk_name, NULL); 204 of_clk_add_provider(np, of_clk_src_simple_get, clk);
181 pr_debug("Add %s clock PLL\n", clk_name); 205 clk_register_clkdev(clk, clk_name, NULL);
182 } 206 pr_debug("Add %s clock PLL\n", clk_name);
207 }
183} 208}
184 209
185static void xgene_socpllclk_init(struct device_node *np) 210static void xgene_socpllclk_init(struct device_node *np)
@@ -460,7 +485,7 @@ static void __init xgene_devclk_init(struct device_node *np)
460 rc = of_address_to_resource(np, i, &res); 485 rc = of_address_to_resource(np, i, &res);
461 if (rc != 0) { 486 if (rc != 0) {
462 if (i == 0) { 487 if (i == 0) {
463 pr_err("no DTS register for %s\n", 488 pr_err("no DTS register for %s\n",
464 np->full_name); 489 np->full_name);
465 return; 490 return;
466 } 491 }
@@ -518,4 +543,8 @@ err:
518 543
519CLK_OF_DECLARE(xgene_socpll_clock, "apm,xgene-socpll-clock", xgene_socpllclk_init); 544CLK_OF_DECLARE(xgene_socpll_clock, "apm,xgene-socpll-clock", xgene_socpllclk_init);
520CLK_OF_DECLARE(xgene_pcppll_clock, "apm,xgene-pcppll-clock", xgene_pcppllclk_init); 545CLK_OF_DECLARE(xgene_pcppll_clock, "apm,xgene-pcppll-clock", xgene_pcppllclk_init);
546CLK_OF_DECLARE(xgene_socpll_v2_clock, "apm,xgene-socpll-v2-clock",
547 xgene_socpllclk_init);
548CLK_OF_DECLARE(xgene_pcppll_v2_clock, "apm,xgene-pcppll-v2-clock",
549 xgene_pcppllclk_init);
521CLK_OF_DECLARE(xgene_dev_clock, "apm,xgene-device-clock", xgene_devclk_init); 550CLK_OF_DECLARE(xgene_dev_clock, "apm,xgene-device-clock", xgene_devclk_init);