blob: 73196fe35215208b567e3b0c15bacc0373fa5bc5 [file] [log] [blame]
Xiaoming Zhoufd2f2852013-03-20 20:54:38 -04001/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
2 *
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License version 2 and
5 * only version 2 as published by the Free Software Foundation.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 */
12
13#include <linux/kernel.h>
14#include <linux/io.h>
15#include <linux/err.h>
16#include <linux/delay.h>
17#include <linux/string.h>
18#include <linux/iopoll.h>
19#include <linux/clk.h>
20
21#include <asm/processor.h>
22#include <mach/msm_iomap.h>
23#include <mach/clk-provider.h>
24
25#include "clock-dsi-8610.h"
26
27#define DSI_PHY_PHYS 0xFDD00000
28#define DSI_PHY_SIZE 0x00100000
29
30#define DSI_CTRL 0x0000
31#define DSI_DSIPHY_PLL_CTRL_0 0x0200
32#define DSI_DSIPHY_PLL_CTRL_1 0x0204
33#define DSI_DSIPHY_PLL_CTRL_2 0x0208
34#define DSI_DSIPHY_PLL_CTRL_3 0x020C
35#define DSI_DSIPHY_PLL_RDY 0x0280
36#define DSI_DSIPHY_PLL_CTRL_8 0x0220
37#define DSI_DSIPHY_PLL_CTRL_9 0x0224
38#define DSI_DSIPHY_PLL_CTRL_10 0x0228
39
40#define DSI_BPP 3
41#define DSI_PLL_RDY_BIT 0x01
42#define DSI_PLL_RDY_LOOP_COUNT 80000
43#define DSI_MAX_DIVIDER 256
44
45static unsigned char *dsi_base;
46static struct clk *dsi_ahb_clk;
47
48int __init dsi_clk_ctrl_init(struct clk *ahb_clk)
49{
50 dsi_base = ioremap(DSI_PHY_PHYS, DSI_PHY_SIZE);
51 if (!dsi_base) {
52 pr_err("unable to remap dsi base\n");
53 return -ENODEV;
54 }
55
56 dsi_ahb_clk = ahb_clk;
57 return 0;
58}
59
60static int dsi_pll_vco_enable(struct clk *c)
61{
62 u32 status;
63 int i = 0, ret = 0;
64
65 ret = clk_enable(dsi_ahb_clk);
66 if (ret) {
67 pr_err("fail to enable dsi ahb clk\n");
68 return ret;
69 }
70
71 writel_relaxed(0x01, dsi_base + DSI_DSIPHY_PLL_CTRL_0);
72
73 do {
74 status = readl_relaxed(dsi_base + DSI_DSIPHY_PLL_RDY);
75 } while (!(status & DSI_PLL_RDY_BIT) && (i++ < DSI_PLL_RDY_LOOP_COUNT));
76
77 if (!(status & DSI_PLL_RDY_BIT)) {
78 pr_err("DSI PLL not ready, polling time out!\n");
79 ret = -ETIMEDOUT;
80 }
81
82 clk_disable(dsi_ahb_clk);
83
84 return ret;
85}
86
87static void dsi_pll_vco_disable(struct clk *c)
88{
89 int ret;
90
91 ret = clk_enable(dsi_ahb_clk);
92 if (ret) {
93 pr_err("fail to enable dsi ahb clk\n");
94 return;
95 }
96
97 writel_relaxed(0x00, dsi_base + DSI_DSIPHY_PLL_CTRL_0);
98 clk_disable(dsi_ahb_clk);
99}
100
101static int dsi_pll_vco_set_rate(struct clk *c, unsigned long rate)
102{
103 int ret;
104 u32 temp, val;
105 unsigned long fb_divider;
106 struct clk *parent = c->parent;
107 struct dsi_pll_vco_clk *vco_clk =
108 container_of(c, struct dsi_pll_vco_clk, c);
109
110 if (!rate)
111 return 0;
112
113 ret = clk_prepare_enable(dsi_ahb_clk);
114 if (ret) {
115 pr_err("fail to enable dsi ahb clk\n");
116 return ret;
117 }
118
119 temp = rate / 10;
120 val = parent->rate / 10;
121 fb_divider = (temp * vco_clk->pref_div_ratio) / val;
122 fb_divider = fb_divider / 2 - 1;
123
124 temp = readl_relaxed(dsi_base + DSI_DSIPHY_PLL_CTRL_1);
125 val = (temp & 0xFFFFFF00) | (fb_divider & 0xFF);
126 writel_relaxed(val, dsi_base + DSI_DSIPHY_PLL_CTRL_1);
127
128 temp = readl_relaxed(dsi_base + DSI_DSIPHY_PLL_CTRL_2);
129 val = (temp & 0xFFFFFFF8) | ((fb_divider >> 8) & 0x07);
130 writel_relaxed(val, dsi_base + DSI_DSIPHY_PLL_CTRL_2);
131
132 temp = readl_relaxed(dsi_base + DSI_DSIPHY_PLL_CTRL_3);
133 val = (temp & 0xFFFFFFC0) | (vco_clk->pref_div_ratio - 1);
134 writel_relaxed(val, dsi_base + DSI_DSIPHY_PLL_CTRL_3);
135
136 clk_disable_unprepare(dsi_ahb_clk);
137
138 return 0;
139}
140
141/* rate is the bit clk rate */
142static long dsi_pll_vco_round_rate(struct clk *c, unsigned long rate)
143{
144 long vco_rate;
145 struct dsi_pll_vco_clk *vco_clk =
146 container_of(c, struct dsi_pll_vco_clk, c);
147
148
149 vco_rate = rate;
150 if (rate < vco_clk->vco_clk_min)
151 vco_rate = vco_clk->vco_clk_min;
152 else if (rate > vco_clk->vco_clk_max)
153 vco_rate = vco_clk->vco_clk_max;
154
155 return vco_rate;
156}
157
158static unsigned long dsi_pll_vco_get_rate(struct clk *c)
159{
160 u32 fb_divider, ref_divider, vco_rate;
161 u32 temp, status;
162 struct clk *parent = c->parent;
163
164 status = readl_relaxed(dsi_base + DSI_DSIPHY_PLL_RDY);
165 if (status & DSI_PLL_RDY_BIT) {
166 fb_divider = readl_relaxed(dsi_base + DSI_DSIPHY_PLL_CTRL_1);
167 fb_divider &= 0xFF;
168 temp = readl_relaxed(dsi_base + DSI_DSIPHY_PLL_CTRL_2) & 0x07;
169 fb_divider = (temp << 8) | fb_divider;
170 fb_divider += 1;
171
172 ref_divider = readl_relaxed(dsi_base + DSI_DSIPHY_PLL_CTRL_3);
173 ref_divider &= 0x3F;
174 ref_divider += 1;
175
176 vco_rate = (parent->rate / ref_divider) * fb_divider;
177 } else {
178 vco_rate = 0;
179 }
180 return vco_rate;
181}
182
183static enum handoff dsi_pll_vco_handoff(struct clk *c)
184{
185 u32 status;
186
187 if (clk_prepare_enable(dsi_ahb_clk)) {
188 pr_err("fail to enable dsi ahb clk\n");
189 return HANDOFF_DISABLED_CLK;
190 }
191
192 status = readl_relaxed(dsi_base + DSI_DSIPHY_PLL_CTRL_0);
193 if (!status & DSI_PLL_RDY_BIT) {
194 pr_err("DSI PLL not ready\n");
Xiaoming Zhou6169d3a2013-07-09 16:01:19 -0400195 clk_disable_unprepare(dsi_ahb_clk);
Xiaoming Zhoufd2f2852013-03-20 20:54:38 -0400196 return HANDOFF_DISABLED_CLK;
197 }
198
199 c->rate = dsi_pll_vco_get_rate(c);
200
201 clk_disable_unprepare(dsi_ahb_clk);
202
203 return HANDOFF_ENABLED_CLK;
204}
205
206static int dsi_byteclk_set_rate(struct clk *c, unsigned long rate)
207{
208 int div, ret;
209 long vco_rate;
210 unsigned long bitclk_rate;
211 u32 temp, val;
212 struct clk *parent = clk_get_parent(c);
213
214 if (rate == 0) {
215 ret = clk_set_rate(parent, 0);
216 return ret;
217 }
218
219 bitclk_rate = rate * 8;
220 for (div = 1; div < DSI_MAX_DIVIDER; div++) {
221 vco_rate = clk_round_rate(parent, bitclk_rate * div);
222
223 if (vco_rate == bitclk_rate * div)
224 break;
225
226 if (vco_rate < bitclk_rate * div)
227 return -EINVAL;
228 }
229
230 if (vco_rate != bitclk_rate * div)
231 return -EINVAL;
232
233 ret = clk_set_rate(parent, vco_rate);
234 if (ret) {
235 pr_err("fail to set vco rate\n");
236 return ret;
237 }
238
239 ret = clk_prepare_enable(dsi_ahb_clk);
240 if (ret) {
241 pr_err("fail to enable dsi ahb clk\n");
242 return ret;
243 }
244
245 /* set the bit clk divider */
246 temp = readl_relaxed(dsi_base + DSI_DSIPHY_PLL_CTRL_8);
247 val = (temp & 0xFFFFFFF0) | (div - 1);
248 writel_relaxed(val, dsi_base + DSI_DSIPHY_PLL_CTRL_8);
249
250 /* set the byte clk divider */
251 temp = readl_relaxed(dsi_base + DSI_DSIPHY_PLL_CTRL_9);
252 val = (temp & 0xFFFFFF00) | (vco_rate / rate - 1);
253 writel_relaxed(val, dsi_base + DSI_DSIPHY_PLL_CTRL_9);
254 clk_disable_unprepare(dsi_ahb_clk);
255
256 return 0;
257}
258
259static long dsi_byteclk_round_rate(struct clk *c, unsigned long rate)
260{
261 int div;
262 long vco_rate;
263 unsigned long bitclk_rate;
264 struct clk *parent = clk_get_parent(c);
265
266 if (rate == 0)
267 return -EINVAL;
268
269 bitclk_rate = rate * 8;
270 for (div = 1; div < DSI_MAX_DIVIDER; div++) {
271 vco_rate = clk_round_rate(parent, bitclk_rate * div);
272 if (vco_rate == bitclk_rate * div)
273 break;
274 if (vco_rate < bitclk_rate * div)
275 return -EINVAL;
276 }
277
278 if (vco_rate != bitclk_rate * div)
279 return -EINVAL;
280
281 return rate;
282}
283
284static enum handoff dsi_byteclk_handoff(struct clk *c)
285{
286 struct clk *parent = clk_get_parent(c);
287 unsigned long vco_rate = clk_get_rate(parent);
288 u32 out_div2;
289
290 if (vco_rate == 0)
291 return HANDOFF_DISABLED_CLK;
292
293 if (clk_prepare_enable(dsi_ahb_clk)) {
294 pr_err("fail to enable dsi ahb clk\n");
295 return HANDOFF_DISABLED_CLK;
296 }
297
298 out_div2 = readl_relaxed(dsi_base + DSI_DSIPHY_PLL_CTRL_9);
299 out_div2 &= 0xFF;
300 c->rate = vco_rate / (out_div2 + 1);
301 clk_disable_unprepare(dsi_ahb_clk);
302
303 return HANDOFF_ENABLED_CLK;
304}
305
306static int dsi_dsiclk_set_rate(struct clk *c, unsigned long rate)
307{
308 u32 temp, val;
309 int ret;
310 struct clk *parent = clk_get_parent(c);
311 unsigned long vco_rate = clk_get_rate(parent);
312
313 if (rate == 0)
314 return 0;
315
316 if (vco_rate % rate != 0) {
317 pr_err("dsiclk_set_rate invalid rate\n");
318 return -EINVAL;
319 }
320
321 ret = clk_prepare_enable(dsi_ahb_clk);
322 if (ret) {
323 pr_err("fail to enable dsi ahb clk\n");
324 return ret;
325 }
326 temp = readl_relaxed(dsi_base + DSI_DSIPHY_PLL_CTRL_10);
327 val = (temp & 0xFFFFFF00) | (vco_rate / rate - 1);
328 writel_relaxed(val, dsi_base + DSI_DSIPHY_PLL_CTRL_10);
329 clk_disable_unprepare(dsi_ahb_clk);
330
331 return 0;
332}
333
334static long dsi_dsiclk_round_rate(struct clk *c, unsigned long rate)
335{
336 /* rate is the pixel clk rate, translate into dsi clk rate*/
337 struct clk *parent = clk_get_parent(c);
338 unsigned long vco_rate = clk_get_rate(parent);
339
340 rate *= DSI_BPP;
341
342 if (vco_rate < rate)
343 return -EINVAL;
344
345 if (vco_rate % rate != 0)
346 return -EINVAL;
347
348 return rate;
349}
350
351static enum handoff dsi_dsiclk_handoff(struct clk *c)
352{
353 struct clk *parent = clk_get_parent(c);
354 unsigned long vco_rate = clk_get_rate(parent);
355 u32 out_div3;
356
357 if (vco_rate == 0)
358 return HANDOFF_DISABLED_CLK;
359
360 if (clk_prepare_enable(dsi_ahb_clk)) {
361 pr_err("fail to enable dsi ahb clk\n");
362 return HANDOFF_DISABLED_CLK;
363 }
364
365 out_div3 = readl_relaxed(dsi_base + DSI_DSIPHY_PLL_CTRL_10);
366 out_div3 &= 0xFF;
367 c->rate = vco_rate / (out_div3 + 1);
368 clk_disable_unprepare(dsi_ahb_clk);
369
370 return HANDOFF_ENABLED_CLK;
371}
372
Xiaoming Zhoufd2f2852013-03-20 20:54:38 -0400373struct clk_ops clk_ops_dsi_dsiclk = {
Xiaoming Zhoufd2f2852013-03-20 20:54:38 -0400374 .set_rate = dsi_dsiclk_set_rate,
375 .round_rate = dsi_dsiclk_round_rate,
376 .handoff = dsi_dsiclk_handoff,
377};
378
379struct clk_ops clk_ops_dsi_byteclk = {
Xiaoming Zhoufd2f2852013-03-20 20:54:38 -0400380 .set_rate = dsi_byteclk_set_rate,
381 .round_rate = dsi_byteclk_round_rate,
382 .handoff = dsi_byteclk_handoff,
383};
384
385struct clk_ops clk_ops_dsi_vco = {
Xiaoming Zhoufd2f2852013-03-20 20:54:38 -0400386 .enable = dsi_pll_vco_enable,
387 .disable = dsi_pll_vco_disable,
388 .set_rate = dsi_pll_vco_set_rate,
389 .round_rate = dsi_pll_vco_round_rate,
390 .handoff = dsi_pll_vco_handoff,
391};
392