diff options
Diffstat (limited to 'drivers/clk/mvebu/clk-corediv.c')
-rw-r--r-- | drivers/clk/mvebu/clk-corediv.c | 154 |
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 | */ | ||
25 | struct clk_corediv_desc { | 29 | struct 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 | */ | ||
41 | struct 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 | */ | ||
31 | struct clk_corediv { | 55 | struct 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 | ||
38 | static struct clk_onecell_data clk_data; | 63 | static struct clk_onecell_data clk_data; |
39 | 64 | ||
40 | static 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 | */ | ||
70 | static 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 = { | |||
46 | static int clk_corediv_is_enabled(struct clk_hw *hwclk) | 76 | static 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) | |||
55 | static int clk_corediv_enable(struct clk_hw *hwclk) | 86 | static 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) | |||
73 | static void clk_corediv_disable(struct clk_hw *hwclk) | 105 | static 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 | ||
156 | static const struct clk_ops corediv_ops = { | 191 | static 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 | |||
207 | static 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 | ||
165 | static void __init mvebu_corediv_clk_init(struct device_node *node) | 223 | static 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 | |||
235 | static void __init | ||
236 | mvebu_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: | |||
219 | err_unmap: | 292 | err_unmap: |
220 | iounmap(base); | 293 | iounmap(base); |
221 | } | 294 | } |
222 | CLK_OF_DECLARE(mvebu_corediv_clk, "marvell,armada-370-corediv-clock", | 295 | |
223 | mvebu_corediv_clk_init); | 296 | static void __init armada370_corediv_clk_init(struct device_node *node) |
297 | { | ||
298 | return mvebu_corediv_clk_init(node, &armada370_corediv_soc); | ||
299 | } | ||
300 | CLK_OF_DECLARE(armada370_corediv_clk, "marvell,armada-370-corediv-clock", | ||
301 | armada370_corediv_clk_init); | ||
302 | |||
303 | static void __init armada375_corediv_clk_init(struct device_node *node) | ||
304 | { | ||
305 | return mvebu_corediv_clk_init(node, &armada375_corediv_soc); | ||
306 | } | ||
307 | CLK_OF_DECLARE(armada375_corediv_clk, "marvell,armada-375-corediv-clock", | ||
308 | armada375_corediv_clk_init); | ||
309 | |||
310 | static void __init armada380_corediv_clk_init(struct device_node *node) | ||
311 | { | ||
312 | return mvebu_corediv_clk_init(node, &armada380_corediv_soc); | ||
313 | } | ||
314 | CLK_OF_DECLARE(armada380_corediv_clk, "marvell,armada-380-corediv-clock", | ||
315 | armada380_corediv_clk_init); | ||