blob: 50042f25ebf463842e823a3c3f52f8546a4788e1 [file] [log] [blame]
Amol Jadi29f95032012-06-22 12:52:54 -07001/*
Channagoud Kadabidd7cb382015-03-23 23:30:25 -07002 * Copyright (c) 2012-2015, The Linux Foundation. All rights reserved.
Amol Jadi29f95032012-06-22 12:52:54 -07003 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are met:
6 * * Redistributions of source code must retain the above copyright
7 * notice, this list of conditions and the following disclaimer.
8 * * Redistributions in binary form must reproduce the above copyright
9 * notice, this list of conditions and the following disclaimer in the
10 * documentation and/or other materials provided with the distribution.
Duy Truongf3ac7b32013-02-13 01:07:28 -080011 * * Neither the name of The Linux Foundation nor
Amol Jadi29f95032012-06-22 12:52:54 -070012 * the names of its contributors may be used to endorse or promote
13 * products derived from this software without specific prior written
14 * permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19 * NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
20 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
21 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
22 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
23 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
24 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
25 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
26 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
Channagoud Kadabif32341c2014-04-03 15:34:04 -070028#include <arch/defines.h>
Amol Jadi29f95032012-06-22 12:52:54 -070029#include <assert.h>
30#include <reg.h>
31#include <err.h>
32#include <clock.h>
33#include <clock_pll.h>
34#include <clock_lib2.h>
Channagoud Kadabi0a98d002015-10-07 11:57:53 -070035#include <platform/timer.h>
Amol Jadi29f95032012-06-22 12:52:54 -070036
37/*=============== CXO clock ops =============*/
38int cxo_clk_enable(struct clk *clk)
39{
40 /* Nothing to do. */
41 return 0;
42}
43
44void cxo_clk_disable(struct clk *clk)
45{
46 /* Nothing to do. */
47 return;
48}
49
50
51/*=============== Branch clock ops =============*/
52
53/* Branch clock enable */
54int clock_lib2_branch_clk_enable(struct clk *clk)
55{
56 int rc = 0;
57 uint32_t cbcr_val;
Channagoud Kadabi0a98d002015-10-07 11:57:53 -070058 int retry = 100;
Amol Jadi29f95032012-06-22 12:52:54 -070059 struct branch_clk *bclk = to_branch_clk(clk);
60
61 cbcr_val = readl(bclk->cbcr_reg);
62 cbcr_val |= CBCR_BRANCH_ENABLE_BIT;
63 writel(cbcr_val, bclk->cbcr_reg);
64
Channagoud Kadabi0a98d002015-10-07 11:57:53 -070065 /* Some clocks do not need to check the enable status, return
66 * if the halt_check is not set
67 */
68 if (!bclk->halt_check)
69 return rc;
70
Amol Jadi29f95032012-06-22 12:52:54 -070071 /* wait until status shows it is enabled */
Channagoud Kadabi0a98d002015-10-07 11:57:53 -070072 while(readl(bclk->cbcr_reg) & CBCR_BRANCH_OFF_BIT)
73 {
74 /* Add 100 ms of time out, bail out if the clock is not enable
75 * within 100 ms */
76 if (!retry)
77 {
78 rc = 1;
79 break;
80 }
81 retry--;
82 mdelay(1);
83 }
Amol Jadi29f95032012-06-22 12:52:54 -070084
85 return rc;
86}
87
88/* Branch clock disable */
89void clock_lib2_branch_clk_disable(struct clk *clk)
90{
91 uint32_t cbcr_val;
92 struct branch_clk *bclk = to_branch_clk(clk);
93
94 cbcr_val = readl(bclk->cbcr_reg);
95 cbcr_val &= ~CBCR_BRANCH_ENABLE_BIT;
96 writel(cbcr_val, bclk->cbcr_reg);
97
Channagoud Kadabidd7cb382015-03-23 23:30:25 -070098 if (!bclk->no_halt_check_on_disable)
99 /* wait until status shows it is disabled */
100 while(!(readl(bclk->cbcr_reg) & CBCR_BRANCH_OFF_BIT));
Amol Jadi29f95032012-06-22 12:52:54 -0700101}
102
103/* Branch clock set rate */
104int clock_lib2_branch_set_rate(struct clk *c, unsigned rate)
105{
106 struct branch_clk *branch = to_branch_clk(c);
107
108 if (!branch->has_sibling)
109 return clk_set_rate(branch->parent, rate);
110
111 return -1;
112}
113
114
115/*=============== Root clock ops =============*/
116
117/* Root enable */
118int clock_lib2_rcg_enable(struct clk *c)
119{
120 /* Hardware feedback from branch enable results in root being enabled.
121 * Nothing to do here.
122 */
123
124 return 0;
125}
126
127/* Root set rate:
128 * Find the entry in the frequecy table corresponding to the requested rate.
129 * Enable the source clock required for the new frequency.
130 * Call the set_rate function defined for this particular root clock.
131 */
132int clock_lib2_rcg_set_rate(struct clk *c, unsigned rate)
133{
134 struct rcg_clk *rclk = to_rcg_clk(c);
135 struct clk_freq_tbl *nf; /* new freq */
136 int rc = 0;
137
138 /* ck if new freq is in table */
139 for (nf = rclk->freq_tbl; nf->freq_hz != FREQ_END
140 && nf->freq_hz != rate; nf++)
141 ;
142
143 /* Frequency not found in the table */
144 if (nf->freq_hz == FREQ_END)
145 return ERR_INVALID_ARGS;
146
147 /* Check if frequency is actually changed. */
148 if (nf == rclk->current_freq)
149 return rc;
150
151 /* First enable the source clock for this freq. */
152 clk_enable(nf->src_clk);
153
154 /* Perform clock-specific frequency switch operations. */
155 ASSERT(rclk->set_rate);
156 rclk->set_rate(rclk, nf);
157
158 /* update current freq */
159 rclk->current_freq = nf;
160
161 return rc;
162}
163
164/* root update config: informs h/w to start using the new config values */
165static void clock_lib2_rcg_update_config(struct rcg_clk *rclk)
166{
167 uint32_t cmd;
168
169 cmd = readl(rclk->cmd_reg);
170 cmd |= CMD_UPDATE_BIT;
171 writel(cmd, rclk->cmd_reg);
172
173 /* Wait for frequency to be updated. */
174 while(readl(rclk->cmd_reg) & CMD_UPDATE_MASK);
175}
176
177/* root set rate for clocks with half integer and MND divider */
178void clock_lib2_rcg_set_rate_mnd(struct rcg_clk *rclk, struct clk_freq_tbl *freq)
179{
180 uint32_t cfg;
181
182 /* Program MND values */
183 writel(freq->m_val, rclk->m_reg);
184 writel(freq->n_val, rclk->n_reg);
185 writel(freq->d_val, rclk->d_reg);
186
187 /* setup src select and divider */
188 cfg = readl(rclk->cfg_reg);
189 cfg &= ~(CFG_SRC_SEL_MASK | CFG_SRC_DIV_MASK | CFG_MODE_MASK);
190 cfg |= freq->div_src_val;
191 if(freq->n_val !=0)
192 {
193 cfg |= (CFG_MODE_DUAL_EDGE << CFG_MODE_OFFSET);
194 }
195 writel(cfg, rclk->cfg_reg);
196
197 /* Inform h/w to start using the new config. */
198 clock_lib2_rcg_update_config(rclk);
199}
200
201/* root set rate for clocks with half integer divider */
202void clock_lib2_rcg_set_rate_hid(struct rcg_clk *rclk, struct clk_freq_tbl *freq)
203{
204 uint32_t cfg;
205
206 /* setup src select and divider */
207 cfg = readl(rclk->cfg_reg);
208 cfg &= ~(CFG_SRC_SEL_MASK | CFG_SRC_DIV_MASK);
209 cfg |= freq->div_src_val;
210 writel(cfg, rclk->cfg_reg);
211
212 clock_lib2_rcg_update_config(rclk);
213}
Neeti Desaiac011272012-08-29 18:24:54 -0700214
215/*=============== Vote clock ops =============*/
216
217/* Vote clock enable */
218int clock_lib2_vote_clk_enable(struct clk *c)
219{
220 uint32_t vote_regval;
221 uint32_t val;
222 struct vote_clk *vclk = to_local_vote_clk(c);
223
224 vote_regval = readl(vclk->vote_reg);
225 vote_regval |= vclk->en_mask;
226 writel_relaxed(vote_regval, vclk->vote_reg);
227 do {
228 val = readl(vclk->cbcr_reg);
229 val &= BRANCH_CHECK_MASK;
230 }
231 /* wait until status shows it is enabled */
232 while((val != BRANCH_ON_VAL) && (val != BRANCH_NOC_FSM_ON_VAL));
233
234 return 0;
235}
236
237/* Vote clock disable */
238void clock_lib2_vote_clk_disable(struct clk *c)
239{
240 uint32_t vote_regval;
241 struct vote_clk *vclk = to_local_vote_clk(c);
242
243 vote_regval = readl(vclk->vote_reg);
244 vote_regval &= ~vclk->en_mask;
245 writel_relaxed(vote_regval, vclk->vote_reg);
Neeti Desaiac011272012-08-29 18:24:54 -0700246}
Channagoud Kadabif32341c2014-04-03 15:34:04 -0700247
248/* Reset clock */
249static int __clock_lib2_branch_clk_reset(uint32_t bcr_reg, enum clk_reset_action action)
250{
251 uint32_t reg;
252 int ret = 0;
253
254 reg = readl(bcr_reg);
255
256 switch (action) {
257 case CLK_RESET_ASSERT:
258 reg |= BIT(0);
259 break;
260 case CLK_RESET_DEASSERT:
261 reg &= ~BIT(0);
262 break;
263 default:
264 ret = 1;
265 }
266
267 writel(reg, bcr_reg);
268
269 /* Wait for writes to go through */
270 dmb();
271
272 return ret;
273}
274
275int clock_lib2_reset_clk_reset(struct clk *c, enum clk_reset_action action)
276{
277 struct reset_clk *rst = to_reset_clk(c);
278
279 if (!rst)
280 return 0;
281
282 return __clock_lib2_branch_clk_reset(rst->bcr_reg, action);
283}
284
285int clock_lib2_branch_clk_reset(struct clk *c, enum clk_reset_action action)
286{
287 struct branch_clk *bclk = to_branch_clk(c);
288
289 if (!bclk)
290 return 0;
291
vijay kumar4f4405f2014-08-08 11:49:53 +0530292 return __clock_lib2_branch_clk_reset((uint32_t)bclk->bcr_reg, action);
Channagoud Kadabif32341c2014-04-03 15:34:04 -0700293}