aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/clk/mvebu/clk-corediv.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/clk/mvebu/clk-corediv.c')
-rw-r--r--drivers/clk/mvebu/clk-corediv.c154
1 files changed, 123 insertions, 31 deletions
diff --git a/drivers/clk/mvebu/clk-corediv.c b/drivers/clk/mvebu/clk-corediv.c
index 7162615bcdcd..d1e5863d3375 100644
--- a/drivers/clk/mvebu/clk-corediv.c
+++ b/drivers/clk/mvebu/clk-corediv.c
@@ -18,26 +18,56 @@
18#include "common.h" 18#include "common.h"
19 19
20#define CORE_CLK_DIV_RATIO_MASK 0xff 20#define CORE_CLK_DIV_RATIO_MASK 0xff
21#define CORE_CLK_DIV_RATIO_RELOAD BIT(8)
22#define CORE_CLK_DIV_ENABLE_OFFSET 24
23#define CORE_CLK_DIV_RATIO_OFFSET 0x8
24 21
22/*
23 * This structure describes the hardware details (bit offset and mask)
24 * to configure one particular core divider clock. Those hardware
25 * details may differ from one SoC to another. This structure is
26 * therefore typically instantiated statically to describe the
27 * hardware details.
28 */
25struct clk_corediv_desc { 29struct clk_corediv_desc {
26 unsigned int mask; 30 unsigned int mask;
27 unsigned int offset; 31 unsigned int offset;
28 unsigned int fieldbit; 32 unsigned int fieldbit;
29}; 33};
30 34
35/*
36 * This structure describes the hardware details to configure the core
37 * divider clocks on a given SoC. Amongst others, it points to the
38 * array of core divider clock descriptors for this SoC, as well as
39 * the corresponding operations to manipulate them.
40 */
41struct clk_corediv_soc_desc {
42 const struct clk_corediv_desc *descs;
43 unsigned int ndescs;
44 const struct clk_ops ops;
45 u32 ratio_reload;
46 u32 enable_bit_offset;
47 u32 ratio_offset;
48};
49
50/*
51 * This structure represents one core divider clock for the clock
52 * framework, and is dynamically allocated for each core divider clock
53 * existing in the current SoC.
54 */
31struct clk_corediv { 55struct clk_corediv {
32 struct clk_hw hw; 56 struct clk_hw hw;
33 void __iomem *reg; 57 void __iomem *reg;
34 struct clk_corediv_desc desc; 58 const struct clk_corediv_desc *desc;
59 const struct clk_corediv_soc_desc *soc_desc;
35 spinlock_t lock; 60 spinlock_t lock;
36}; 61};
37 62
38static struct clk_onecell_data clk_data; 63static struct clk_onecell_data clk_data;
39 64
40static const struct clk_corediv_desc mvebu_corediv_desc[] __initconst = { 65/*
66 * Description of the core divider clocks available. For now, we
67 * support only NAND, and it is available at the same register
68 * locations regardless of the SoC.
69 */
70static const struct clk_corediv_desc mvebu_corediv_desc[] = {
41 { .mask = 0x3f, .offset = 8, .fieldbit = 1 }, /* NAND clock */ 71 { .mask = 0x3f, .offset = 8, .fieldbit = 1 }, /* NAND clock */
42}; 72};
43 73
@@ -46,8 +76,9 @@ static const struct clk_corediv_desc mvebu_corediv_desc[] __initconst = {
46static int clk_corediv_is_enabled(struct clk_hw *hwclk) 76static int clk_corediv_is_enabled(struct clk_hw *hwclk)
47{ 77{
48 struct clk_corediv *corediv = to_corediv_clk(hwclk); 78 struct clk_corediv *corediv = to_corediv_clk(hwclk);
49 struct clk_corediv_desc *desc = &corediv->desc; 79 const struct clk_corediv_soc_desc *soc_desc = corediv->soc_desc;
50 u32 enable_mask = BIT(desc->fieldbit) << CORE_CLK_DIV_ENABLE_OFFSET; 80 const struct clk_corediv_desc *desc = corediv->desc;
81 u32 enable_mask = BIT(desc->fieldbit) << soc_desc->enable_bit_offset;
51 82
52 return !!(readl(corediv->reg) & enable_mask); 83 return !!(readl(corediv->reg) & enable_mask);
53} 84}
@@ -55,14 +86,15 @@ static int clk_corediv_is_enabled(struct clk_hw *hwclk)
55static int clk_corediv_enable(struct clk_hw *hwclk) 86static int clk_corediv_enable(struct clk_hw *hwclk)
56{ 87{
57 struct clk_corediv *corediv = to_corediv_clk(hwclk); 88 struct clk_corediv *corediv = to_corediv_clk(hwclk);
58 struct clk_corediv_desc *desc = &corediv->desc; 89 const struct clk_corediv_soc_desc *soc_desc = corediv->soc_desc;
90 const struct clk_corediv_desc *desc = corediv->desc;
59 unsigned long flags = 0; 91 unsigned long flags = 0;
60 u32 reg; 92 u32 reg;
61 93
62 spin_lock_irqsave(&corediv->lock, flags); 94 spin_lock_irqsave(&corediv->lock, flags);
63 95
64 reg = readl(corediv->reg); 96 reg = readl(corediv->reg);
65 reg |= (BIT(desc->fieldbit) << CORE_CLK_DIV_ENABLE_OFFSET); 97 reg |= (BIT(desc->fieldbit) << soc_desc->enable_bit_offset);
66 writel(reg, corediv->reg); 98 writel(reg, corediv->reg);
67 99
68 spin_unlock_irqrestore(&corediv->lock, flags); 100 spin_unlock_irqrestore(&corediv->lock, flags);
@@ -73,14 +105,15 @@ static int clk_corediv_enable(struct clk_hw *hwclk)
73static void clk_corediv_disable(struct clk_hw *hwclk) 105static void clk_corediv_disable(struct clk_hw *hwclk)
74{ 106{
75 struct clk_corediv *corediv = to_corediv_clk(hwclk); 107 struct clk_corediv *corediv = to_corediv_clk(hwclk);
76 struct clk_corediv_desc *desc = &corediv->desc; 108 const struct clk_corediv_soc_desc *soc_desc = corediv->soc_desc;
109 const struct clk_corediv_desc *desc = corediv->desc;
77 unsigned long flags = 0; 110 unsigned long flags = 0;
78 u32 reg; 111 u32 reg;
79 112
80 spin_lock_irqsave(&corediv->lock, flags); 113 spin_lock_irqsave(&corediv->lock, flags);
81 114
82 reg = readl(corediv->reg); 115 reg = readl(corediv->reg);
83 reg &= ~(BIT(desc->fieldbit) << CORE_CLK_DIV_ENABLE_OFFSET); 116 reg &= ~(BIT(desc->fieldbit) << soc_desc->enable_bit_offset);
84 writel(reg, corediv->reg); 117 writel(reg, corediv->reg);
85 118
86 spin_unlock_irqrestore(&corediv->lock, flags); 119 spin_unlock_irqrestore(&corediv->lock, flags);
@@ -90,10 +123,11 @@ static unsigned long clk_corediv_recalc_rate(struct clk_hw *hwclk,
90 unsigned long parent_rate) 123 unsigned long parent_rate)
91{ 124{
92 struct clk_corediv *corediv = to_corediv_clk(hwclk); 125 struct clk_corediv *corediv = to_corediv_clk(hwclk);
93 struct clk_corediv_desc *desc = &corediv->desc; 126 const struct clk_corediv_soc_desc *soc_desc = corediv->soc_desc;
127 const struct clk_corediv_desc *desc = corediv->desc;
94 u32 reg, div; 128 u32 reg, div;
95 129
96 reg = readl(corediv->reg + CORE_CLK_DIV_RATIO_OFFSET); 130 reg = readl(corediv->reg + soc_desc->ratio_offset);
97 div = (reg >> desc->offset) & desc->mask; 131 div = (reg >> desc->offset) & desc->mask;
98 return parent_rate / div; 132 return parent_rate / div;
99} 133}
@@ -117,7 +151,8 @@ static int clk_corediv_set_rate(struct clk_hw *hwclk, unsigned long rate,
117 unsigned long parent_rate) 151 unsigned long parent_rate)
118{ 152{
119 struct clk_corediv *corediv = to_corediv_clk(hwclk); 153 struct clk_corediv *corediv = to_corediv_clk(hwclk);
120 struct clk_corediv_desc *desc = &corediv->desc; 154 const struct clk_corediv_soc_desc *soc_desc = corediv->soc_desc;
155 const struct clk_corediv_desc *desc = corediv->desc;
121 unsigned long flags = 0; 156 unsigned long flags = 0;
122 u32 reg, div; 157 u32 reg, div;
123 158
@@ -126,17 +161,17 @@ static int clk_corediv_set_rate(struct clk_hw *hwclk, unsigned long rate,
126 spin_lock_irqsave(&corediv->lock, flags); 161 spin_lock_irqsave(&corediv->lock, flags);
127 162
128 /* Write new divider to the divider ratio register */ 163 /* Write new divider to the divider ratio register */
129 reg = readl(corediv->reg + CORE_CLK_DIV_RATIO_OFFSET); 164 reg = readl(corediv->reg + soc_desc->ratio_offset);
130 reg &= ~(desc->mask << desc->offset); 165 reg &= ~(desc->mask << desc->offset);
131 reg |= (div & desc->mask) << desc->offset; 166 reg |= (div & desc->mask) << desc->offset;
132 writel(reg, corediv->reg + CORE_CLK_DIV_RATIO_OFFSET); 167 writel(reg, corediv->reg + soc_desc->ratio_offset);
133 168
134 /* Set reload-force for this clock */ 169 /* Set reload-force for this clock */
135 reg = readl(corediv->reg) | BIT(desc->fieldbit); 170 reg = readl(corediv->reg) | BIT(desc->fieldbit);
136 writel(reg, corediv->reg); 171 writel(reg, corediv->reg);
137 172
138 /* Now trigger the clock update */ 173 /* Now trigger the clock update */
139 reg = readl(corediv->reg) | CORE_CLK_DIV_RATIO_RELOAD; 174 reg = readl(corediv->reg) | soc_desc->ratio_reload;
140 writel(reg, corediv->reg); 175 writel(reg, corediv->reg);
141 176
142 /* 177 /*
@@ -144,7 +179,7 @@ static int clk_corediv_set_rate(struct clk_hw *hwclk, unsigned long rate,
144 * ratios request and the reload request. 179 * ratios request and the reload request.
145 */ 180 */
146 udelay(1000); 181 udelay(1000);
147 reg &= ~(CORE_CLK_DIV_RATIO_MASK | CORE_CLK_DIV_RATIO_RELOAD); 182 reg &= ~(CORE_CLK_DIV_RATIO_MASK | soc_desc->ratio_reload);
148 writel(reg, corediv->reg); 183 writel(reg, corediv->reg);
149 udelay(1000); 184 udelay(1000);
150 185
@@ -153,16 +188,53 @@ static int clk_corediv_set_rate(struct clk_hw *hwclk, unsigned long rate,
153 return 0; 188 return 0;
154} 189}
155 190
156static const struct clk_ops corediv_ops = { 191static const struct clk_corediv_soc_desc armada370_corediv_soc = {
157 .enable = clk_corediv_enable, 192 .descs = mvebu_corediv_desc,
158 .disable = clk_corediv_disable, 193 .ndescs = ARRAY_SIZE(mvebu_corediv_desc),
159 .is_enabled = clk_corediv_is_enabled, 194 .ops = {
160 .recalc_rate = clk_corediv_recalc_rate, 195 .enable = clk_corediv_enable,
161 .round_rate = clk_corediv_round_rate, 196 .disable = clk_corediv_disable,
162 .set_rate = clk_corediv_set_rate, 197 .is_enabled = clk_corediv_is_enabled,
198 .recalc_rate = clk_corediv_recalc_rate,
199 .round_rate = clk_corediv_round_rate,
200 .set_rate = clk_corediv_set_rate,
201 },
202 .ratio_reload = BIT(8),
203 .enable_bit_offset = 24,
204 .ratio_offset = 0x8,
205};
206
207static const struct clk_corediv_soc_desc armada380_corediv_soc = {
208 .descs = mvebu_corediv_desc,
209 .ndescs = ARRAY_SIZE(mvebu_corediv_desc),
210 .ops = {
211 .enable = clk_corediv_enable,
212 .disable = clk_corediv_disable,
213 .is_enabled = clk_corediv_is_enabled,
214 .recalc_rate = clk_corediv_recalc_rate,
215 .round_rate = clk_corediv_round_rate,
216 .set_rate = clk_corediv_set_rate,
217 },
218 .ratio_reload = BIT(8),
219 .enable_bit_offset = 16,
220 .ratio_offset = 0x4,
163}; 221};
164 222
165static void __init mvebu_corediv_clk_init(struct device_node *node) 223static const struct clk_corediv_soc_desc armada375_corediv_soc = {
224 .descs = mvebu_corediv_desc,
225 .ndescs = ARRAY_SIZE(mvebu_corediv_desc),
226 .ops = {
227 .recalc_rate = clk_corediv_recalc_rate,
228 .round_rate = clk_corediv_round_rate,
229 .set_rate = clk_corediv_set_rate,
230 },
231 .ratio_reload = BIT(8),
232 .ratio_offset = 0x4,
233};
234
235static void __init
236mvebu_corediv_clk_init(struct device_node *node,
237 const struct clk_corediv_soc_desc *soc_desc)
166{ 238{
167 struct clk_init_data init; 239 struct clk_init_data init;
168 struct clk_corediv *corediv; 240 struct clk_corediv *corediv;
@@ -178,7 +250,7 @@ static void __init mvebu_corediv_clk_init(struct device_node *node)
178 250
179 parent_name = of_clk_get_parent_name(node, 0); 251 parent_name = of_clk_get_parent_name(node, 0);
180 252
181 clk_data.clk_num = ARRAY_SIZE(mvebu_corediv_desc); 253 clk_data.clk_num = soc_desc->ndescs;
182 254
183 /* clks holds the clock array */ 255 /* clks holds the clock array */
184 clks = kcalloc(clk_data.clk_num, sizeof(struct clk *), 256 clks = kcalloc(clk_data.clk_num, sizeof(struct clk *),
@@ -199,10 +271,11 @@ static void __init mvebu_corediv_clk_init(struct device_node *node)
199 init.num_parents = 1; 271 init.num_parents = 1;
200 init.parent_names = &parent_name; 272 init.parent_names = &parent_name;
201 init.name = clk_name; 273 init.name = clk_name;
202 init.ops = &corediv_ops; 274 init.ops = &soc_desc->ops;
203 init.flags = 0; 275 init.flags = 0;
204 276
205 corediv[i].desc = mvebu_corediv_desc[i]; 277 corediv[i].soc_desc = soc_desc;
278 corediv[i].desc = soc_desc->descs + i;
206 corediv[i].reg = base; 279 corediv[i].reg = base;
207 corediv[i].hw.init = &init; 280 corediv[i].hw.init = &init;
208 281
@@ -219,5 +292,24 @@ err_free_clks:
219err_unmap: 292err_unmap:
220 iounmap(base); 293 iounmap(base);
221} 294}
222CLK_OF_DECLARE(mvebu_corediv_clk, "marvell,armada-370-corediv-clock", 295
223 mvebu_corediv_clk_init); 296static void __init armada370_corediv_clk_init(struct device_node *node)
297{
298 return mvebu_corediv_clk_init(node, &armada370_corediv_soc);
299}
300CLK_OF_DECLARE(armada370_corediv_clk, "marvell,armada-370-corediv-clock",
301 armada370_corediv_clk_init);
302
303static void __init armada375_corediv_clk_init(struct device_node *node)
304{
305 return mvebu_corediv_clk_init(node, &armada375_corediv_soc);
306}
307CLK_OF_DECLARE(armada375_corediv_clk, "marvell,armada-375-corediv-clock",
308 armada375_corediv_clk_init);
309
310static void __init armada380_corediv_clk_init(struct device_node *node)
311{
312 return mvebu_corediv_clk_init(node, &armada380_corediv_soc);
313}
314CLK_OF_DECLARE(armada380_corediv_clk, "marvell,armada-380-corediv-clock",
315 armada380_corediv_clk_init);