diff options
author | Loc Ho <lho@apm.com> | 2016-01-19 21:27:42 -0500 |
---|---|---|
committer | Stephen Boyd <sboyd@codeaurora.org> | 2016-01-29 15:54:35 -0500 |
commit | 47727beb26569725f6c200cde2c38bd1e9f6f1b0 (patch) | |
tree | 408a5ba5f1835574520da37ab233d374a6c5a0e3 | |
parent | 7b63c567b5b3b3e366e6555d764318a75073f2c7 (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.c | 103 |
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 = { | |||
125 | static struct clk *xgene_register_clk_pll(struct device *dev, | 138 | static 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 | ||
177 | static 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 | |||
163 | static void xgene_pllclk_init(struct device_node *np, enum xgene_pll_type pll_type) | 186 | static 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 | ||
185 | static void xgene_socpllclk_init(struct device_node *np) | 210 | static 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 | ||
519 | CLK_OF_DECLARE(xgene_socpll_clock, "apm,xgene-socpll-clock", xgene_socpllclk_init); | 544 | CLK_OF_DECLARE(xgene_socpll_clock, "apm,xgene-socpll-clock", xgene_socpllclk_init); |
520 | CLK_OF_DECLARE(xgene_pcppll_clock, "apm,xgene-pcppll-clock", xgene_pcppllclk_init); | 545 | CLK_OF_DECLARE(xgene_pcppll_clock, "apm,xgene-pcppll-clock", xgene_pcppllclk_init); |
546 | CLK_OF_DECLARE(xgene_socpll_v2_clock, "apm,xgene-socpll-v2-clock", | ||
547 | xgene_socpllclk_init); | ||
548 | CLK_OF_DECLARE(xgene_pcppll_v2_clock, "apm,xgene-pcppll-v2-clock", | ||
549 | xgene_pcppllclk_init); | ||
521 | CLK_OF_DECLARE(xgene_dev_clock, "apm,xgene-device-clock", xgene_devclk_init); | 550 | CLK_OF_DECLARE(xgene_dev_clock, "apm,xgene-device-clock", xgene_devclk_init); |