blob: 218b585e27ee2e1cce58037a76d68766c7ef8af4 [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. */
132 clk_enable(nf->src_clk);
133
134 /* Perform clock-specific frequency switch operations. */
135 ASSERT(rclk->set_rate);
136 rclk->set_rate(rclk, nf);
137
138 /* update current freq */
139 rclk->current_freq = nf;
140
141 return rc;
142}
143
144/* root update config: informs h/w to start using the new config values */
145static void clock_lib2_rcg_update_config(struct rcg_clk *rclk)
146{
147 uint32_t cmd;
148
149 cmd = readl(rclk->cmd_reg);
150 cmd |= CMD_UPDATE_BIT;
151 writel(cmd, rclk->cmd_reg);
152
153 /* Wait for frequency to be updated. */
154 while(readl(rclk->cmd_reg) & CMD_UPDATE_MASK);
155}
156
157/* root set rate for clocks with half integer and MND divider */
158void clock_lib2_rcg_set_rate_mnd(struct rcg_clk *rclk, struct clk_freq_tbl *freq)
159{
160 uint32_t cfg;
161
162 /* Program MND values */
163 writel(freq->m_val, rclk->m_reg);
164 writel(freq->n_val, rclk->n_reg);
165 writel(freq->d_val, rclk->d_reg);
166
167 /* setup src select and divider */
168 cfg = readl(rclk->cfg_reg);
169 cfg &= ~(CFG_SRC_SEL_MASK | CFG_SRC_DIV_MASK | CFG_MODE_MASK);
170 cfg |= freq->div_src_val;
171 if(freq->n_val !=0)
172 {
173 cfg |= (CFG_MODE_DUAL_EDGE << CFG_MODE_OFFSET);
174 }
175 writel(cfg, rclk->cfg_reg);
176
177 /* Inform h/w to start using the new config. */
178 clock_lib2_rcg_update_config(rclk);
179}
180
181/* root set rate for clocks with half integer divider */
182void clock_lib2_rcg_set_rate_hid(struct rcg_clk *rclk, struct clk_freq_tbl *freq)
183{
184 uint32_t cfg;
185
186 /* setup src select and divider */
187 cfg = readl(rclk->cfg_reg);
188 cfg &= ~(CFG_SRC_SEL_MASK | CFG_SRC_DIV_MASK);
189 cfg |= freq->div_src_val;
190 writel(cfg, rclk->cfg_reg);
191
192 clock_lib2_rcg_update_config(rclk);
193}
Neeti Desaiac011272012-08-29 18:24:54 -0700194
195/*=============== Vote clock ops =============*/
196
197/* Vote clock enable */
198int clock_lib2_vote_clk_enable(struct clk *c)
199{
200 uint32_t vote_regval;
201 uint32_t val;
202 struct vote_clk *vclk = to_local_vote_clk(c);
203
204 vote_regval = readl(vclk->vote_reg);
205 vote_regval |= vclk->en_mask;
206 writel_relaxed(vote_regval, vclk->vote_reg);
207 do {
208 val = readl(vclk->cbcr_reg);
209 val &= BRANCH_CHECK_MASK;
210 }
211 /* wait until status shows it is enabled */
212 while((val != BRANCH_ON_VAL) && (val != BRANCH_NOC_FSM_ON_VAL));
213
214 return 0;
215}
216
217/* Vote clock disable */
218void clock_lib2_vote_clk_disable(struct clk *c)
219{
220 uint32_t vote_regval;
221 struct vote_clk *vclk = to_local_vote_clk(c);
222
223 vote_regval = readl(vclk->vote_reg);
224 vote_regval &= ~vclk->en_mask;
225 writel_relaxed(vote_regval, vclk->vote_reg);
226
227 /* wait until status shows it is disabled */
228 while(!(readl(vclk->cbcr_reg) & CBCR_BRANCH_OFF_BIT));
229}