blob: 6f778b13af57b0f07fac3db52ce26418b7e107f0 [file] [log] [blame]
Amol Jadi29f95032012-06-22 12:52:54 -07001/*
Duy Truongf3ac7b32013-02-13 01:07:28 -08002 * Copyright (c) 2012, 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 */
28#include <assert.h>
29#include <reg.h>
30#include <err.h>
31#include <clock.h>
32#include <clock_pll.h>
33#include <clock_lib2.h>
34
35
36/*=============== CXO clock ops =============*/
37int cxo_clk_enable(struct clk *clk)
38{
39 /* Nothing to do. */
40 return 0;
41}
42
43void cxo_clk_disable(struct clk *clk)
44{
45 /* Nothing to do. */
46 return;
47}
48
49
50/*=============== Branch clock ops =============*/
51
52/* Branch clock enable */
53int clock_lib2_branch_clk_enable(struct clk *clk)
54{
55 int rc = 0;
56 uint32_t cbcr_val;
57 struct branch_clk *bclk = to_branch_clk(clk);
58
59 cbcr_val = readl(bclk->cbcr_reg);
60 cbcr_val |= CBCR_BRANCH_ENABLE_BIT;
61 writel(cbcr_val, bclk->cbcr_reg);
62
63 /* wait until status shows it is enabled */
64 while(readl(bclk->cbcr_reg) & CBCR_BRANCH_OFF_BIT);
65
66 return rc;
67}
68
69/* Branch clock disable */
70void clock_lib2_branch_clk_disable(struct clk *clk)
71{
72 uint32_t cbcr_val;
73 struct branch_clk *bclk = to_branch_clk(clk);
74
75 cbcr_val = readl(bclk->cbcr_reg);
76 cbcr_val &= ~CBCR_BRANCH_ENABLE_BIT;
77 writel(cbcr_val, bclk->cbcr_reg);
78
79 /* wait until status shows it is disabled */
80 while(!(readl(bclk->cbcr_reg) & CBCR_BRANCH_OFF_BIT));
81}
82
83/* Branch clock set rate */
84int clock_lib2_branch_set_rate(struct clk *c, unsigned rate)
85{
86 struct branch_clk *branch = to_branch_clk(c);
87
88 if (!branch->has_sibling)
89 return clk_set_rate(branch->parent, rate);
90
91 return -1;
92}
93
94
95/*=============== Root clock ops =============*/
96
97/* Root enable */
98int clock_lib2_rcg_enable(struct clk *c)
99{
100 /* Hardware feedback from branch enable results in root being enabled.
101 * Nothing to do here.
102 */
103
104 return 0;
105}
106
107/* Root set rate:
108 * Find the entry in the frequecy table corresponding to the requested rate.
109 * Enable the source clock required for the new frequency.
110 * Call the set_rate function defined for this particular root clock.
111 */
112int clock_lib2_rcg_set_rate(struct clk *c, unsigned rate)
113{
114 struct rcg_clk *rclk = to_rcg_clk(c);
115 struct clk_freq_tbl *nf; /* new freq */
116 int rc = 0;
117
118 /* ck if new freq is in table */
119 for (nf = rclk->freq_tbl; nf->freq_hz != FREQ_END
120 && nf->freq_hz != rate; nf++)
121 ;
122
123 /* Frequency not found in the table */
124 if (nf->freq_hz == FREQ_END)
125 return ERR_INVALID_ARGS;
126
127 /* Check if frequency is actually changed. */
128 if (nf == rclk->current_freq)
129 return rc;
130
131 /* First enable the source clock for this freq. */
Sundarajan Srinivasan8b3eb722014-02-04 15:43:44 -0800132 rc = clk_enable(nf->src_clk);
133
134 if(rc)
135 {
136 dprintf(CRITICAL, "clock_lib2_rcg_set_rate: failed to enable clk %s ret %d\n",
137 nf->src_clk->dbg_name, rc);
138 ASSERT(0);
139 }
Amol Jadi29f95032012-06-22 12:52:54 -0700140
141 /* Perform clock-specific frequency switch operations. */
142 ASSERT(rclk->set_rate);
143 rclk->set_rate(rclk, nf);
144
145 /* update current freq */
146 rclk->current_freq = nf;
147
148 return rc;
149}
150
151/* root update config: informs h/w to start using the new config values */
152static void clock_lib2_rcg_update_config(struct rcg_clk *rclk)
153{
154 uint32_t cmd;
155
156 cmd = readl(rclk->cmd_reg);
157 cmd |= CMD_UPDATE_BIT;
158 writel(cmd, rclk->cmd_reg);
159
160 /* Wait for frequency to be updated. */
161 while(readl(rclk->cmd_reg) & CMD_UPDATE_MASK);
162}
163
164/* root set rate for clocks with half integer and MND divider */
165void clock_lib2_rcg_set_rate_mnd(struct rcg_clk *rclk, struct clk_freq_tbl *freq)
166{
167 uint32_t cfg;
168
169 /* Program MND values */
170 writel(freq->m_val, rclk->m_reg);
171 writel(freq->n_val, rclk->n_reg);
172 writel(freq->d_val, rclk->d_reg);
173
174 /* setup src select and divider */
175 cfg = readl(rclk->cfg_reg);
176 cfg &= ~(CFG_SRC_SEL_MASK | CFG_SRC_DIV_MASK | CFG_MODE_MASK);
177 cfg |= freq->div_src_val;
178 if(freq->n_val !=0)
179 {
180 cfg |= (CFG_MODE_DUAL_EDGE << CFG_MODE_OFFSET);
181 }
182 writel(cfg, rclk->cfg_reg);
183
184 /* Inform h/w to start using the new config. */
185 clock_lib2_rcg_update_config(rclk);
186}
187
188/* root set rate for clocks with half integer divider */
189void clock_lib2_rcg_set_rate_hid(struct rcg_clk *rclk, struct clk_freq_tbl *freq)
190{
191 uint32_t cfg;
192
193 /* setup src select and divider */
194 cfg = readl(rclk->cfg_reg);
195 cfg &= ~(CFG_SRC_SEL_MASK | CFG_SRC_DIV_MASK);
196 cfg |= freq->div_src_val;
197 writel(cfg, rclk->cfg_reg);
198
199 clock_lib2_rcg_update_config(rclk);
200}
Neeti Desaiac011272012-08-29 18:24:54 -0700201
202/*=============== Vote clock ops =============*/
203
204/* Vote clock enable */
205int clock_lib2_vote_clk_enable(struct clk *c)
206{
207 uint32_t vote_regval;
208 uint32_t val;
209 struct vote_clk *vclk = to_local_vote_clk(c);
210
211 vote_regval = readl(vclk->vote_reg);
212 vote_regval |= vclk->en_mask;
213 writel_relaxed(vote_regval, vclk->vote_reg);
214 do {
215 val = readl(vclk->cbcr_reg);
216 val &= BRANCH_CHECK_MASK;
217 }
218 /* wait until status shows it is enabled */
219 while((val != BRANCH_ON_VAL) && (val != BRANCH_NOC_FSM_ON_VAL));
220
221 return 0;
222}
223
224/* Vote clock disable */
225void clock_lib2_vote_clk_disable(struct clk *c)
226{
227 uint32_t vote_regval;
228 struct vote_clk *vclk = to_local_vote_clk(c);
229
230 vote_regval = readl(vclk->vote_reg);
231 vote_regval &= ~vclk->en_mask;
232 writel_relaxed(vote_regval, vclk->vote_reg);
233
234 /* wait until status shows it is disabled */
235 while(!(readl(vclk->cbcr_reg) & CBCR_BRANCH_OFF_BIT));
236}