blob: 646d575275616bef55bb8828442ecceb9ae78ee4 [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)
Siddhartha Agrawalfe64dcb2014-10-07 12:41:01 -070046 width /= 2;
47
48 if (pinfo->fbc.enabled && pinfo->fbc.comp_ratio)
49 width /= pinfo->fbc.comp_ratio;
Dhaval Patelee8675a2013-10-25 10:07:57 -070050
51 h_period = width + pinfo->lcdc.h_back_porch +
Arpita Banerjeeda0c39a2013-05-24 16:12:45 -070052 pinfo->lcdc.h_front_porch + pinfo->lcdc.h_pulse_width +
53 pinfo->lcdc.xres_pad;
54
55 v_period = pinfo->yres + pinfo->lcdc.v_back_porch +
56 pinfo->lcdc.v_front_porch + pinfo->lcdc.v_pulse_width +
57 pinfo->lcdc.yres_pad;
58
59 /* Pixel clock rate */
60 pll_data.pixel_clock = h_period * v_period * pinfo->mipi.frame_rate;
61
62 /* Store all bit clock form data */
63 if (pinfo->mipi.bitclock == 0)
64 pll_data.bit_clock = (pll_data.pixel_clock * pinfo->bpp) /
65 pinfo->mipi.num_of_lanes;
66 else
67 pll_data.bit_clock = pinfo->mipi.bitclock;
68
69 pll_data.byte_clock = pll_data.bit_clock >> 3;
70
71 pll_data.halfbit_clock = pll_data.bit_clock >> 1;
Arpita Banerjeeda0c39a2013-05-24 16:12:45 -070072}
73
74static uint32_t calculate_div1()
75{
76 uint32_t ret = NO_ERROR;
77
78 /* div1 - there is divide by 2 logic present */
79 if (pll_data.halfbit_clock > HALFBIT_CLOCK1) {
80 pll_data.posdiv1 = 0x0; /*div 1 */
81 pll_data.vco_clock = pll_data.halfbit_clock << 1;
82 } else if (pll_data.halfbit_clock > HALFBIT_CLOCK2) {
83 pll_data.posdiv1 = 0x1; /*div 2 */
84 pll_data.vco_clock = pll_data.halfbit_clock << 2;
85 } else if (pll_data.halfbit_clock > HALFBIT_CLOCK3) {
86 pll_data.posdiv1 = 0x3; /*div 4 */
87 pll_data.vco_clock = pll_data.halfbit_clock << 3;
88 } else if (pll_data.halfbit_clock > HALFBIT_CLOCK4) {
89 pll_data.posdiv1 = 0x4; /*div 5 */
90 pll_data.vco_clock = pll_data.halfbit_clock * 10;
91 } else {
92 dprintf(CRITICAL, "Not able to calculate posdiv1\n");
93 }
94
95 return ret;
96}
97
98static uint32_t calculate_div3(uint8_t bpp, uint8_t num_of_lanes)
99{
Arpita Banerjeeda0c39a2013-05-24 16:12:45 -0700100 pll_data.pclk_m = 0x1; /* M = 1, N= 1 */
101 pll_data.pclk_n = 0xFF; /* ~ (N-M) = 0xff */
102 pll_data.pclk_d = 0xFF; /* ~N = 0xFF */
103
104 /* formula is ( vco_clock / pdiv_digital) / mnd = pixel_clock */
105
106 /* div3 */
107 switch (bpp) {
108 case BITS_18:
109 if (num_of_lanes == 3) {
110 pll_data.posdiv3 = pll_data.vco_clock /
111 pll_data.pixel_clock;
112 } else {
113 pll_data.posdiv3 = (pll_data.pixel_clock * 2 / 9) /
114 pll_data.vco_clock;
115 pll_data.pclk_m = 0x2; /* M = 2,N = 9 */
116 pll_data.pclk_n = 0xF8;
117 pll_data.pclk_d = 0xF6;
118 }
119 break;
120 case BITS_16:
121 if (num_of_lanes == 3) {
122 pll_data.posdiv3 = (pll_data.pixel_clock * 3 / 8) /
123 pll_data.vco_clock;
124 pll_data.pclk_m = 0x3; /* M = 3, N = 9 */
125 pll_data.pclk_n = 0xFA;
126 pll_data.pclk_d = 0xF7;
127 } else {
128 pll_data.posdiv3 = pll_data.vco_clock /
129 pll_data.pixel_clock;
130 }
131 break;
132 case BITS_24:
133 default:
134 pll_data.posdiv3 = pll_data.vco_clock /
135 pll_data.pixel_clock;
136 break;
137 }
138
139 pll_data.posdiv3--; /* Register needs one value less */
Veera Sundaram Sankaran824e6fa2014-12-09 11:32:58 -0800140 return NO_ERROR;
Arpita Banerjeeda0c39a2013-05-24 16:12:45 -0700141}
142
Dhaval Pateld19fcf12014-08-12 13:16:05 -0700143static uint32_t calculate_dec_frac_start()
Arpita Banerjeeda0c39a2013-05-24 16:12:45 -0700144{
Dhaval Pateld19fcf12014-08-12 13:16:05 -0700145 uint32_t refclk = 19200000;
146 uint32_t vco_rate = pll_data.vco_clock;
Chandan Uddaraju67519562014-11-01 17:00:45 -0700147 uint32_t tmp;
Dhaval Pateld19fcf12014-08-12 13:16:05 -0700148
149 vco_rate /= 2;
150 pll_data.dec_start = vco_rate / refclk;
151 tmp = vco_rate % refclk; /* module, fraction */
152 tmp /= 192;
153 tmp *= 1024;
154 tmp /= 100;
155 tmp *= 1024;
156 tmp /= 1000;
157 pll_data.frac_start = tmp;
158
159 vco_rate *= 2; /* restore */
Chandan Uddaraju67519562014-11-01 17:00:45 -0700160 tmp = vco_rate / (refclk / 1000);/* div 1000 first */
161 tmp *= 1024;
162 tmp /= 1000;
Dhaval Pateld19fcf12014-08-12 13:16:05 -0700163 tmp /= 10;
Chandan Uddaraju67519562014-11-01 17:00:45 -0700164 pll_data.lock_comp = tmp - 1;
Dhaval Pateld19fcf12014-08-12 13:16:05 -0700165
Chandan Uddaraju67519562014-11-01 17:00:45 -0700166 dprintf(SPEW, "%s: dec_start=0x%x dec_frac=0x%x lock_comp=0x%x\n", __func__,
Dhaval Pateld19fcf12014-08-12 13:16:05 -0700167 pll_data.dec_start, pll_data.frac_start, pll_data.lock_comp);
Veera Sundaram Sankaran824e6fa2014-12-09 11:32:58 -0800168 return NO_ERROR;
Dhaval Pateld19fcf12014-08-12 13:16:05 -0700169}
170
171static uint32_t calculate_vco_28nm(uint8_t bpp, uint8_t num_of_lanes)
172{
Arpita Banerjeeda0c39a2013-05-24 16:12:45 -0700173 /* If half bitclock is more than VCO min value */
174 if (pll_data.halfbit_clock > VCO_MIN_CLOCK) {
175
176 /* Direct Mode */
177
178 /* support vco clock to max value only */
179 if (pll_data.halfbit_clock > VCO_MAX_CLOCK)
180 pll_data.vco_clock = VCO_MAX_CLOCK;
181 else
182 pll_data.vco_clock = pll_data.halfbit_clock;
183 pll_data.directpath = 0x0;
184 pll_data.posdiv1 = 0x0; /*DSI spec says 0 - div 1 */
185 /*1 - div 2 */
186 /*F - div 16 */
187 } else {
188 /* Indirect Mode */
189
190 pll_data.directpath = 0x02; /* set bit 1 to enable for
191 indirect path */
192
193 calculate_div1();
194 }
195
196 /* calculate mnd and div3 for direct and indirect path */
197 calculate_div3(bpp, num_of_lanes);
198
Dhaval Pateld19fcf12014-08-12 13:16:05 -0700199 return NO_ERROR;
200}
201
202static uint32_t calculate_vco_20nm(uint8_t bpp, uint8_t lanes)
203{
204 uint32_t vco, dsi_clk;
205 int mod, ndiv, hr_oclk2, hr_oclk3;
206 int m = 1;
207 int n = 1;
208 int bpp_m = 3; /* bpp = 3 */
209 int bpp_n = 1;
210
211 if (bpp == BITS_18) {
212 bpp_m = 9; /* bpp = 2.25 */
213 bpp_n = 4;
214
215 if (lanes == 2) {
216 m = 2;
217 n = 9;
218 } else if (lanes == 4) {
219 m = 4;
220 n = 9;
221 }
222 } else if (bpp == BITS_16) {
223 bpp_m = 2; /* bpp = 2 */
224 bpp_n = 1;
225 if (lanes == 3) {
226 m = 3;
227 n = 8;
228 }
229 }
230
231 hr_oclk2 = 4;
232
233 /* If bitclock is more than VCO min value */
234 if (pll_data.halfbit_clock >= HALF_VCO_MIN_CLOCK_20NM) {
235 /* Direct Mode */
236 vco = pll_data.halfbit_clock << 1;
237 /* support vco clock to max value only */
238 if (vco > VCO_MAX_CLOCK_20NM)
239 vco = VCO_MAX_CLOCK_20NM;
240
241 pll_data.directpath = 0x0;
242 pll_data.byte_clock = vco / 2 / hr_oclk2;
243 pll_data.lp_div_mux = 0x0;
244 ndiv = 1;
245 hr_oclk3 = hr_oclk2 * m / n * bpp_m / bpp_n / lanes;
246 } else {
247 /* Indirect Mode */
248 mod = VCO_MIN_CLOCK_20NM % (4 * pll_data.halfbit_clock );
249 ndiv = VCO_MIN_CLOCK_20NM / (4 * pll_data.halfbit_clock );
250 if (mod)
251 ndiv += 1;
252
253 vco = pll_data.halfbit_clock * 4 * ndiv;
254 pll_data.lp_div_mux = 0x1;
255 pll_data.directpath = 0x02; /* set bit 1 to enable for
256 indirect path */
257
258 pll_data.byte_clock = vco / 4 / hr_oclk2 / ndiv;
259 hr_oclk3 = hr_oclk2 * m / n * ndiv * 2 * bpp_m / bpp_n / lanes;
260 }
261
262 pll_data.vco_clock = vco;
263 dsi_clk = vco / 2 / hr_oclk3;
264 pll_data.ndiv = ndiv;
265 pll_data.hr_oclk2 = hr_oclk2 - 1; /* strat from 0 */
266 pll_data.hr_oclk3 = hr_oclk3 - 1; /* strat from 0 */
267
268 pll_data.pclk_m = m; /* M */
269 pll_data.pclk_n = ~(n - m); /* ~(N-M) */
270 pll_data.pclk_d = ~n; /* ~N */
271
272 dprintf(SPEW, "%s: oclk2=%d oclk3=%d ndiv=%d vco=%u dsi_clk=%u byte_clk=%u\n",
273 __func__, hr_oclk2, hr_oclk3, ndiv, vco, dsi_clk, pll_data.byte_clock);
274
275 calculate_dec_frac_start();
276
277 return NO_ERROR;
Arpita Banerjeeda0c39a2013-05-24 16:12:45 -0700278}
279
280uint32_t calculate_clock_config(struct msm_panel_info *pinfo)
281{
282 uint32_t ret = NO_ERROR;
283
284 calculate_bitclock(pinfo);
285
Dhaval Pateld19fcf12014-08-12 13:16:05 -0700286 if (pinfo->mipi.mdss_dsi_phy_db->is_pll_20nm)
287 ret = calculate_vco_20nm(pinfo->bpp, pinfo->mipi.num_of_lanes);
288 else
289 ret = calculate_vco_28nm(pinfo->bpp, pinfo->mipi.num_of_lanes);
Arpita Banerjeeda0c39a2013-05-24 16:12:45 -0700290
291 pinfo->mipi.dsi_pll_config = &pll_data;
292
293 return ret;
294}