blob: cc87c92ab9c654bb2ca122eea6e70f5a0c96342c [file] [log] [blame]
Amol Jadi29f95032012-06-22 12:52:54 -07001/*
Sundarajan Srinivasana7731502013-12-19 16:15:58 -08002 * Copyright (c) 2012-2014, 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>
35
36
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;
58 struct branch_clk *bclk = to_branch_clk(clk);
59
60 cbcr_val = readl(bclk->cbcr_reg);
61 cbcr_val |= CBCR_BRANCH_ENABLE_BIT;
62 writel(cbcr_val, bclk->cbcr_reg);
63
64 /* wait until status shows it is enabled */
65 while(readl(bclk->cbcr_reg) & CBCR_BRANCH_OFF_BIT);
66
67 return rc;
68}
69
70/* Branch clock disable */
71void clock_lib2_branch_clk_disable(struct clk *clk)
72{
73 uint32_t cbcr_val;
74 struct branch_clk *bclk = to_branch_clk(clk);
75
76 cbcr_val = readl(bclk->cbcr_reg);
77 cbcr_val &= ~CBCR_BRANCH_ENABLE_BIT;
78 writel(cbcr_val, bclk->cbcr_reg);
79
80 /* wait until status shows it is disabled */
81 while(!(readl(bclk->cbcr_reg) & CBCR_BRANCH_OFF_BIT));
82}
83
84/* Branch clock set rate */
85int clock_lib2_branch_set_rate(struct clk *c, unsigned rate)
86{
87 struct branch_clk *branch = to_branch_clk(c);
88
89 if (!branch->has_sibling)
90 return clk_set_rate(branch->parent, rate);
91
92 return -1;
93}
94
95
96/*=============== Root clock ops =============*/
97
98/* Root enable */
99int clock_lib2_rcg_enable(struct clk *c)
100{
101 /* Hardware feedback from branch enable results in root being enabled.
102 * Nothing to do here.
103 */
104
105 return 0;
106}
107
108/* Root set rate:
109 * Find the entry in the frequecy table corresponding to the requested rate.
110 * Enable the source clock required for the new frequency.
111 * Call the set_rate function defined for this particular root clock.
112 */
113int clock_lib2_rcg_set_rate(struct clk *c, unsigned rate)
114{
115 struct rcg_clk *rclk = to_rcg_clk(c);
116 struct clk_freq_tbl *nf; /* new freq */
117 int rc = 0;
118
119 /* ck if new freq is in table */
120 for (nf = rclk->freq_tbl; nf->freq_hz != FREQ_END
121 && nf->freq_hz != rate; nf++)
122 ;
123
124 /* Frequency not found in the table */
125 if (nf->freq_hz == FREQ_END)
126 return ERR_INVALID_ARGS;
127
128 /* Check if frequency is actually changed. */
129 if (nf == rclk->current_freq)
130 return rc;
131
132 /* First enable the source clock for this freq. */
133 clk_enable(nf->src_clk);
134
135 /* Perform clock-specific frequency switch operations. */
136 ASSERT(rclk->set_rate);
137 rclk->set_rate(rclk, nf);
138
139 /* update current freq */
140 rclk->current_freq = nf;
141
142 return rc;
143}
144
145/* root update config: informs h/w to start using the new config values */
146static void clock_lib2_rcg_update_config(struct rcg_clk *rclk)
147{
148 uint32_t cmd;
149
150 cmd = readl(rclk->cmd_reg);
151 cmd |= CMD_UPDATE_BIT;
152 writel(cmd, rclk->cmd_reg);
153
154 /* Wait for frequency to be updated. */
155 while(readl(rclk->cmd_reg) & CMD_UPDATE_MASK);
156}
157
158/* root set rate for clocks with half integer and MND divider */
159void clock_lib2_rcg_set_rate_mnd(struct rcg_clk *rclk, struct clk_freq_tbl *freq)
160{
161 uint32_t cfg;
162
163 /* Program MND values */
164 writel(freq->m_val, rclk->m_reg);
165 writel(freq->n_val, rclk->n_reg);
166 writel(freq->d_val, rclk->d_reg);
167
168 /* setup src select and divider */
169 cfg = readl(rclk->cfg_reg);
170 cfg &= ~(CFG_SRC_SEL_MASK | CFG_SRC_DIV_MASK | CFG_MODE_MASK);
171 cfg |= freq->div_src_val;
172 if(freq->n_val !=0)
173 {
174 cfg |= (CFG_MODE_DUAL_EDGE << CFG_MODE_OFFSET);
175 }
176 writel(cfg, rclk->cfg_reg);
177
178 /* Inform h/w to start using the new config. */
179 clock_lib2_rcg_update_config(rclk);
180}
181
182/* root set rate for clocks with half integer divider */
183void clock_lib2_rcg_set_rate_hid(struct rcg_clk *rclk, struct clk_freq_tbl *freq)
184{
185 uint32_t cfg;
186
187 /* setup src select and divider */
188 cfg = readl(rclk->cfg_reg);
189 cfg &= ~(CFG_SRC_SEL_MASK | CFG_SRC_DIV_MASK);
190 cfg |= freq->div_src_val;
191 writel(cfg, rclk->cfg_reg);
192
193 clock_lib2_rcg_update_config(rclk);
194}
Neeti Desaiac011272012-08-29 18:24:54 -0700195
196/*=============== Vote clock ops =============*/
197
198/* Vote clock enable */
199int clock_lib2_vote_clk_enable(struct clk *c)
200{
201 uint32_t vote_regval;
202 uint32_t val;
203 struct vote_clk *vclk = to_local_vote_clk(c);
204
205 vote_regval = readl(vclk->vote_reg);
206 vote_regval |= vclk->en_mask;
207 writel_relaxed(vote_regval, vclk->vote_reg);
208 do {
209 val = readl(vclk->cbcr_reg);
210 val &= BRANCH_CHECK_MASK;
211 }
212 /* wait until status shows it is enabled */
213 while((val != BRANCH_ON_VAL) && (val != BRANCH_NOC_FSM_ON_VAL));
214
215 return 0;
216}
217
218/* Vote clock disable */
219void clock_lib2_vote_clk_disable(struct clk *c)
220{
221 uint32_t vote_regval;
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);
Neeti Desaiac011272012-08-29 18:24:54 -0700227}
Channagoud Kadabif32341c2014-04-03 15:34:04 -0700228
229/* Reset clock */
230static int __clock_lib2_branch_clk_reset(uint32_t bcr_reg, enum clk_reset_action action)
231{
232 uint32_t reg;
233 int ret = 0;
234
235 reg = readl(bcr_reg);
236
237 switch (action) {
238 case CLK_RESET_ASSERT:
239 reg |= BIT(0);
240 break;
241 case CLK_RESET_DEASSERT:
242 reg &= ~BIT(0);
243 break;
244 default:
245 ret = 1;
246 }
247
248 writel(reg, bcr_reg);
249
250 /* Wait for writes to go through */
251 dmb();
252
253 return ret;
254}
255
256int clock_lib2_reset_clk_reset(struct clk *c, enum clk_reset_action action)
257{
258 struct reset_clk *rst = to_reset_clk(c);
259
260 if (!rst)
261 return 0;
262
263 return __clock_lib2_branch_clk_reset(rst->bcr_reg, action);
264}
265
266int clock_lib2_branch_clk_reset(struct clk *c, enum clk_reset_action action)
267{
268 struct branch_clk *bclk = to_branch_clk(c);
269
270 if (!bclk)
271 return 0;
272
vijay kumar4f4405f2014-08-08 11:49:53 +0530273 return __clock_lib2_branch_clk_reset((uint32_t)bclk->bcr_reg, action);
Channagoud Kadabif32341c2014-04-03 15:34:04 -0700274}