blob: 38ba3b4a2a1051a119356ae8a0a5b09203c6c0c4 [file] [log] [blame]
Dhaval Pateld19fcf12014-08-12 13:16:05 -07001/* Copyright (c) 2013-2014, The Linux Foundation. All rights reserved.
Arpita Banerjeeda0c39a2013-05-24 16:12:45 -07002 *
3 * Redistribution and use in source and binary forms, with or without
4 * modification, are permitted provided that the following conditions
5 * 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
10 * the documentation and/or other materials provided with the
11 * distribution.
12 * * Neither the name of The Linux Foundation nor the names of its
13 * contributors may be used to endorse or promote products derived
14 * from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
19 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
20 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
22 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
23 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
24 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
25 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
26 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 */
29
30#include <debug.h>
31#include <err.h>
32#include <smem.h>
33#include <msm_panel.h>
34#include <mipi_dsi.h>
35
36#include "gcdb_autopll.h"
37
38static struct mdss_dsi_pll_config pll_data;
39
Dhaval Pateld19fcf12014-08-12 13:16:05 -070040static void calculate_bitclock(struct msm_panel_info *pinfo)
Arpita Banerjeeda0c39a2013-05-24 16:12:45 -070041{
Arpita Banerjeeda0c39a2013-05-24 16:12:45 -070042 uint32_t h_period = 0, v_period = 0;
Dhaval Patelee8675a2013-10-25 10:07:57 -070043 uint32_t width = pinfo->xres;
Arpita Banerjeeda0c39a2013-05-24 16:12:45 -070044
Dhaval Patelee8675a2013-10-25 10:07:57 -070045 if (pinfo->mipi.dual_dsi)
46 width = pinfo->xres / 2;
47
48 h_period = width + pinfo->lcdc.h_back_porch +
Arpita Banerjeeda0c39a2013-05-24 16:12:45 -070049 pinfo->lcdc.h_front_porch + pinfo->lcdc.h_pulse_width +
50 pinfo->lcdc.xres_pad;
51
52 v_period = pinfo->yres + pinfo->lcdc.v_back_porch +
53 pinfo->lcdc.v_front_porch + pinfo->lcdc.v_pulse_width +
54 pinfo->lcdc.yres_pad;
55
56 /* Pixel clock rate */
57 pll_data.pixel_clock = h_period * v_period * pinfo->mipi.frame_rate;
58
59 /* Store all bit clock form data */
60 if (pinfo->mipi.bitclock == 0)
61 pll_data.bit_clock = (pll_data.pixel_clock * pinfo->bpp) /
62 pinfo->mipi.num_of_lanes;
63 else
64 pll_data.bit_clock = pinfo->mipi.bitclock;
65
66 pll_data.byte_clock = pll_data.bit_clock >> 3;
67
68 pll_data.halfbit_clock = pll_data.bit_clock >> 1;
Arpita Banerjeeda0c39a2013-05-24 16:12:45 -070069}
70
71static uint32_t calculate_div1()
72{
73 uint32_t ret = NO_ERROR;
74
75 /* div1 - there is divide by 2 logic present */
76 if (pll_data.halfbit_clock > HALFBIT_CLOCK1) {
77 pll_data.posdiv1 = 0x0; /*div 1 */
78 pll_data.vco_clock = pll_data.halfbit_clock << 1;
79 } else if (pll_data.halfbit_clock > HALFBIT_CLOCK2) {
80 pll_data.posdiv1 = 0x1; /*div 2 */
81 pll_data.vco_clock = pll_data.halfbit_clock << 2;
82 } else if (pll_data.halfbit_clock > HALFBIT_CLOCK3) {
83 pll_data.posdiv1 = 0x3; /*div 4 */
84 pll_data.vco_clock = pll_data.halfbit_clock << 3;
85 } else if (pll_data.halfbit_clock > HALFBIT_CLOCK4) {
86 pll_data.posdiv1 = 0x4; /*div 5 */
87 pll_data.vco_clock = pll_data.halfbit_clock * 10;
88 } else {
89 dprintf(CRITICAL, "Not able to calculate posdiv1\n");
90 }
91
92 return ret;
93}
94
95static uint32_t calculate_div3(uint8_t bpp, uint8_t num_of_lanes)
96{
97 uint32_t ret = NO_ERROR;
98 pll_data.pclk_m = 0x1; /* M = 1, N= 1 */
99 pll_data.pclk_n = 0xFF; /* ~ (N-M) = 0xff */
100 pll_data.pclk_d = 0xFF; /* ~N = 0xFF */
101
102 /* formula is ( vco_clock / pdiv_digital) / mnd = pixel_clock */
103
104 /* div3 */
105 switch (bpp) {
106 case BITS_18:
107 if (num_of_lanes == 3) {
108 pll_data.posdiv3 = pll_data.vco_clock /
109 pll_data.pixel_clock;
110 } else {
111 pll_data.posdiv3 = (pll_data.pixel_clock * 2 / 9) /
112 pll_data.vco_clock;
113 pll_data.pclk_m = 0x2; /* M = 2,N = 9 */
114 pll_data.pclk_n = 0xF8;
115 pll_data.pclk_d = 0xF6;
116 }
117 break;
118 case BITS_16:
119 if (num_of_lanes == 3) {
120 pll_data.posdiv3 = (pll_data.pixel_clock * 3 / 8) /
121 pll_data.vco_clock;
122 pll_data.pclk_m = 0x3; /* M = 3, N = 9 */
123 pll_data.pclk_n = 0xFA;
124 pll_data.pclk_d = 0xF7;
125 } else {
126 pll_data.posdiv3 = pll_data.vco_clock /
127 pll_data.pixel_clock;
128 }
129 break;
130 case BITS_24:
131 default:
132 pll_data.posdiv3 = pll_data.vco_clock /
133 pll_data.pixel_clock;
134 break;
135 }
136
137 pll_data.posdiv3--; /* Register needs one value less */
138}
139
Dhaval Pateld19fcf12014-08-12 13:16:05 -0700140static uint32_t calculate_dec_frac_start()
Arpita Banerjeeda0c39a2013-05-24 16:12:45 -0700141{
Dhaval Pateld19fcf12014-08-12 13:16:05 -0700142 uint32_t refclk = 19200000;
143 uint32_t vco_rate = pll_data.vco_clock;
144 uint32_t tmp, mod;
145
146 vco_rate /= 2;
147 pll_data.dec_start = vco_rate / refclk;
148 tmp = vco_rate % refclk; /* module, fraction */
149 tmp /= 192;
150 tmp *= 1024;
151 tmp /= 100;
152 tmp *= 1024;
153 tmp /= 1000;
154 pll_data.frac_start = tmp;
155
156 vco_rate *= 2; /* restore */
157 tmp = vco_rate / refclk;/* div 1000 first */
158 mod = vco_rate % refclk;
159 tmp *= 127;
160 mod *= 127;
161 mod /= refclk;
162 tmp += mod;
163 tmp /= 10;
164 pll_data.lock_comp = tmp;
165
166 dprintf(SPEW, "%s: dec_start=%u dec_frac=%u lock_comp=%u\n", __func__,
167 pll_data.dec_start, pll_data.frac_start, pll_data.lock_comp);
168}
169
170static uint32_t calculate_vco_28nm(uint8_t bpp, uint8_t num_of_lanes)
171{
Arpita Banerjeeda0c39a2013-05-24 16:12:45 -0700172 uint8_t counter = 0;
173 uint32_t temprate = 0;
174
175 /* If half bitclock is more than VCO min value */
176 if (pll_data.halfbit_clock > VCO_MIN_CLOCK) {
177
178 /* Direct Mode */
179
180 /* support vco clock to max value only */
181 if (pll_data.halfbit_clock > VCO_MAX_CLOCK)
182 pll_data.vco_clock = VCO_MAX_CLOCK;
183 else
184 pll_data.vco_clock = pll_data.halfbit_clock;
185 pll_data.directpath = 0x0;
186 pll_data.posdiv1 = 0x0; /*DSI spec says 0 - div 1 */
187 /*1 - div 2 */
188 /*F - div 16 */
189 } else {
190 /* Indirect Mode */
191
192 pll_data.directpath = 0x02; /* set bit 1 to enable for
193 indirect path */
194
195 calculate_div1();
196 }
197
198 /* calculate mnd and div3 for direct and indirect path */
199 calculate_div3(bpp, num_of_lanes);
200
Dhaval Pateld19fcf12014-08-12 13:16:05 -0700201 return NO_ERROR;
202}
203
204static uint32_t calculate_vco_20nm(uint8_t bpp, uint8_t lanes)
205{
206 uint32_t vco, dsi_clk;
207 int mod, ndiv, hr_oclk2, hr_oclk3;
208 int m = 1;
209 int n = 1;
210 int bpp_m = 3; /* bpp = 3 */
211 int bpp_n = 1;
212
213 if (bpp == BITS_18) {
214 bpp_m = 9; /* bpp = 2.25 */
215 bpp_n = 4;
216
217 if (lanes == 2) {
218 m = 2;
219 n = 9;
220 } else if (lanes == 4) {
221 m = 4;
222 n = 9;
223 }
224 } else if (bpp == BITS_16) {
225 bpp_m = 2; /* bpp = 2 */
226 bpp_n = 1;
227 if (lanes == 3) {
228 m = 3;
229 n = 8;
230 }
231 }
232
233 hr_oclk2 = 4;
234
235 /* If bitclock is more than VCO min value */
236 if (pll_data.halfbit_clock >= HALF_VCO_MIN_CLOCK_20NM) {
237 /* Direct Mode */
238 vco = pll_data.halfbit_clock << 1;
239 /* support vco clock to max value only */
240 if (vco > VCO_MAX_CLOCK_20NM)
241 vco = VCO_MAX_CLOCK_20NM;
242
243 pll_data.directpath = 0x0;
244 pll_data.byte_clock = vco / 2 / hr_oclk2;
245 pll_data.lp_div_mux = 0x0;
246 ndiv = 1;
247 hr_oclk3 = hr_oclk2 * m / n * bpp_m / bpp_n / lanes;
248 } else {
249 /* Indirect Mode */
250 mod = VCO_MIN_CLOCK_20NM % (4 * pll_data.halfbit_clock );
251 ndiv = VCO_MIN_CLOCK_20NM / (4 * pll_data.halfbit_clock );
252 if (mod)
253 ndiv += 1;
254
255 vco = pll_data.halfbit_clock * 4 * ndiv;
256 pll_data.lp_div_mux = 0x1;
257 pll_data.directpath = 0x02; /* set bit 1 to enable for
258 indirect path */
259
260 pll_data.byte_clock = vco / 4 / hr_oclk2 / ndiv;
261 hr_oclk3 = hr_oclk2 * m / n * ndiv * 2 * bpp_m / bpp_n / lanes;
262 }
263
264 pll_data.vco_clock = vco;
265 dsi_clk = vco / 2 / hr_oclk3;
266 pll_data.ndiv = ndiv;
267 pll_data.hr_oclk2 = hr_oclk2 - 1; /* strat from 0 */
268 pll_data.hr_oclk3 = hr_oclk3 - 1; /* strat from 0 */
269
270 pll_data.pclk_m = m; /* M */
271 pll_data.pclk_n = ~(n - m); /* ~(N-M) */
272 pll_data.pclk_d = ~n; /* ~N */
273
274 dprintf(SPEW, "%s: oclk2=%d oclk3=%d ndiv=%d vco=%u dsi_clk=%u byte_clk=%u\n",
275 __func__, hr_oclk2, hr_oclk3, ndiv, vco, dsi_clk, pll_data.byte_clock);
276
277 calculate_dec_frac_start();
278
279 return NO_ERROR;
Arpita Banerjeeda0c39a2013-05-24 16:12:45 -0700280}
281
282uint32_t calculate_clock_config(struct msm_panel_info *pinfo)
283{
284 uint32_t ret = NO_ERROR;
285
286 calculate_bitclock(pinfo);
287
Dhaval Pateld19fcf12014-08-12 13:16:05 -0700288 if (pinfo->mipi.mdss_dsi_phy_db->is_pll_20nm)
289 ret = calculate_vco_20nm(pinfo->bpp, pinfo->mipi.num_of_lanes);
290 else
291 ret = calculate_vco_28nm(pinfo->bpp, pinfo->mipi.num_of_lanes);
Arpita Banerjeeda0c39a2013-05-24 16:12:45 -0700292
293 pinfo->mipi.dsi_pll_config = &pll_data;
294
295 return ret;
296}