diff options
author | Alex Elder <elder@linaro.org> | 2014-04-21 17:11:42 -0400 |
---|---|---|
committer | Mike Turquette <mturquette@linaro.org> | 2014-04-30 14:51:36 -0400 |
commit | a597faccc7eedd406313e880ed05ff75bc522910 (patch) | |
tree | 4e463bcfde259380a3ea5b50534272357f007dc8 /drivers/clk/bcm/clk-kona-setup.c | |
parent | 03548ec06ad3ec75d5b212fa832e4e617334ea09 (diff) |
clk: bcm281xx: add clock policy support
Add support for CCU policy engine control, and also for setting the
mask bits for bus clocks that require a policy change to get
activated. This includes adding validity checking framework for
CCUs, to validate the policy fields if defined.
Signed-off-by: Alex Elder <elder@linaro.org>
Signed-off-by: Mike Turquette <mturquette@linaro.org>
Diffstat (limited to 'drivers/clk/bcm/clk-kona-setup.c')
-rw-r--r-- | drivers/clk/bcm/clk-kona-setup.c | 92 |
1 files changed, 92 insertions, 0 deletions
diff --git a/drivers/clk/bcm/clk-kona-setup.c b/drivers/clk/bcm/clk-kona-setup.c index 825a2f2ab052..773ad7c7dd59 100644 --- a/drivers/clk/bcm/clk-kona-setup.c +++ b/drivers/clk/bcm/clk-kona-setup.c | |||
@@ -25,6 +25,31 @@ LIST_HEAD(ccu_list); /* The list of set up CCUs */ | |||
25 | 25 | ||
26 | /* Validity checking */ | 26 | /* Validity checking */ |
27 | 27 | ||
28 | static bool ccu_data_offsets_valid(struct ccu_data *ccu) | ||
29 | { | ||
30 | struct ccu_policy *ccu_policy = &ccu->policy; | ||
31 | u32 limit; | ||
32 | |||
33 | limit = ccu->range - sizeof(u32); | ||
34 | limit = round_down(limit, sizeof(u32)); | ||
35 | if (ccu_policy_exists(ccu_policy)) { | ||
36 | if (ccu_policy->enable.offset > limit) { | ||
37 | pr_err("%s: bad policy enable offset for %s " | ||
38 | "(%u > %u)\n", __func__, | ||
39 | ccu->name, ccu_policy->enable.offset, limit); | ||
40 | return false; | ||
41 | } | ||
42 | if (ccu_policy->control.offset > limit) { | ||
43 | pr_err("%s: bad policy control offset for %s " | ||
44 | "(%u > %u)\n", __func__, | ||
45 | ccu->name, ccu_policy->control.offset, limit); | ||
46 | return false; | ||
47 | } | ||
48 | } | ||
49 | |||
50 | return true; | ||
51 | } | ||
52 | |||
28 | static bool clk_requires_trigger(struct kona_clk *bcm_clk) | 53 | static bool clk_requires_trigger(struct kona_clk *bcm_clk) |
29 | { | 54 | { |
30 | struct peri_clk_data *peri = bcm_clk->u.peri; | 55 | struct peri_clk_data *peri = bcm_clk->u.peri; |
@@ -54,6 +79,7 @@ static bool clk_requires_trigger(struct kona_clk *bcm_clk) | |||
54 | static bool peri_clk_data_offsets_valid(struct kona_clk *bcm_clk) | 79 | static bool peri_clk_data_offsets_valid(struct kona_clk *bcm_clk) |
55 | { | 80 | { |
56 | struct peri_clk_data *peri; | 81 | struct peri_clk_data *peri; |
82 | struct bcm_clk_policy *policy; | ||
57 | struct bcm_clk_gate *gate; | 83 | struct bcm_clk_gate *gate; |
58 | struct bcm_clk_div *div; | 84 | struct bcm_clk_div *div; |
59 | struct bcm_clk_sel *sel; | 85 | struct bcm_clk_sel *sel; |
@@ -70,6 +96,15 @@ static bool peri_clk_data_offsets_valid(struct kona_clk *bcm_clk) | |||
70 | limit = range - sizeof(u32); | 96 | limit = range - sizeof(u32); |
71 | limit = round_down(limit, sizeof(u32)); | 97 | limit = round_down(limit, sizeof(u32)); |
72 | 98 | ||
99 | policy = &peri->policy; | ||
100 | if (policy_exists(policy)) { | ||
101 | if (policy->offset > limit) { | ||
102 | pr_err("%s: bad policy offset for %s (%u > %u)\n", | ||
103 | __func__, name, policy->offset, limit); | ||
104 | return false; | ||
105 | } | ||
106 | } | ||
107 | |||
73 | gate = &peri->gate; | 108 | gate = &peri->gate; |
74 | if (gate_exists(gate)) { | 109 | if (gate_exists(gate)) { |
75 | if (gate->offset > limit) { | 110 | if (gate->offset > limit) { |
@@ -167,6 +202,36 @@ static bool bitfield_valid(u32 shift, u32 width, const char *field_name, | |||
167 | return true; | 202 | return true; |
168 | } | 203 | } |
169 | 204 | ||
205 | static bool | ||
206 | ccu_policy_valid(struct ccu_policy *ccu_policy, const char *ccu_name) | ||
207 | { | ||
208 | struct bcm_lvm_en *enable = &ccu_policy->enable; | ||
209 | struct bcm_policy_ctl *control; | ||
210 | |||
211 | if (!bit_posn_valid(enable->bit, "policy enable", ccu_name)) | ||
212 | return false; | ||
213 | |||
214 | control = &ccu_policy->control; | ||
215 | if (!bit_posn_valid(control->go_bit, "policy control GO", ccu_name)) | ||
216 | return false; | ||
217 | |||
218 | if (!bit_posn_valid(control->atl_bit, "policy control ATL", ccu_name)) | ||
219 | return false; | ||
220 | |||
221 | if (!bit_posn_valid(control->ac_bit, "policy control AC", ccu_name)) | ||
222 | return false; | ||
223 | |||
224 | return true; | ||
225 | } | ||
226 | |||
227 | static bool policy_valid(struct bcm_clk_policy *policy, const char *clock_name) | ||
228 | { | ||
229 | if (!bit_posn_valid(policy->bit, "policy", clock_name)) | ||
230 | return false; | ||
231 | |||
232 | return true; | ||
233 | } | ||
234 | |||
170 | /* | 235 | /* |
171 | * All gates, if defined, have a status bit, and for hardware-only | 236 | * All gates, if defined, have a status bit, and for hardware-only |
172 | * gates, that's it. Gates that can be software controlled also | 237 | * gates, that's it. Gates that can be software controlled also |
@@ -312,6 +377,7 @@ static bool | |||
312 | peri_clk_data_valid(struct kona_clk *bcm_clk) | 377 | peri_clk_data_valid(struct kona_clk *bcm_clk) |
313 | { | 378 | { |
314 | struct peri_clk_data *peri; | 379 | struct peri_clk_data *peri; |
380 | struct bcm_clk_policy *policy; | ||
315 | struct bcm_clk_gate *gate; | 381 | struct bcm_clk_gate *gate; |
316 | struct bcm_clk_sel *sel; | 382 | struct bcm_clk_sel *sel; |
317 | struct bcm_clk_div *div; | 383 | struct bcm_clk_div *div; |
@@ -331,6 +397,11 @@ peri_clk_data_valid(struct kona_clk *bcm_clk) | |||
331 | 397 | ||
332 | peri = bcm_clk->u.peri; | 398 | peri = bcm_clk->u.peri; |
333 | name = bcm_clk->init_data.name; | 399 | name = bcm_clk->init_data.name; |
400 | |||
401 | policy = &peri->policy; | ||
402 | if (policy_exists(policy) && !policy_valid(policy, name)) | ||
403 | return false; | ||
404 | |||
334 | gate = &peri->gate; | 405 | gate = &peri->gate; |
335 | if (gate_exists(gate) && !gate_valid(gate, "gate", name)) | 406 | if (gate_exists(gate) && !gate_valid(gate, "gate", name)) |
336 | return false; | 407 | return false; |
@@ -679,6 +750,21 @@ static void kona_ccu_teardown(struct ccu_data *ccu) | |||
679 | ccu->base = NULL; | 750 | ccu->base = NULL; |
680 | } | 751 | } |
681 | 752 | ||
753 | static bool ccu_data_valid(struct ccu_data *ccu) | ||
754 | { | ||
755 | struct ccu_policy *ccu_policy; | ||
756 | |||
757 | if (!ccu_data_offsets_valid(ccu)) | ||
758 | return false; | ||
759 | |||
760 | ccu_policy = &ccu->policy; | ||
761 | if (ccu_policy_exists(ccu_policy)) | ||
762 | if (!ccu_policy_valid(ccu_policy, ccu->name)) | ||
763 | return false; | ||
764 | |||
765 | return true; | ||
766 | } | ||
767 | |||
682 | /* | 768 | /* |
683 | * Set up a CCU. Call the provided ccu_clks_setup callback to | 769 | * Set up a CCU. Call the provided ccu_clks_setup callback to |
684 | * initialize the array of clocks provided by the CCU. | 770 | * initialize the array of clocks provided by the CCU. |
@@ -718,6 +804,12 @@ void __init kona_dt_ccu_setup(struct ccu_data *ccu, | |||
718 | } | 804 | } |
719 | 805 | ||
720 | ccu->range = (u32)range; | 806 | ccu->range = (u32)range; |
807 | |||
808 | if (!ccu_data_valid(ccu)) { | ||
809 | pr_err("%s: ccu data not valid for %s\n", __func__, node->name); | ||
810 | goto out_err; | ||
811 | } | ||
812 | |||
721 | ccu->base = ioremap(res.start, ccu->range); | 813 | ccu->base = ioremap(res.start, ccu->range); |
722 | if (!ccu->base) { | 814 | if (!ccu->base) { |
723 | pr_err("%s: unable to map CCU registers for %s\n", __func__, | 815 | pr_err("%s: unable to map CCU registers for %s\n", __func__, |