blob: 1adb31b6469ec3a74c7b79a9ba100fbab354cf63 [file] [log] [blame]
Padmanabhan Komanduru1fc8bc42015-12-21 18:30:46 +05301/* Copyright (c) 2013-2015, The Linux Foundation. All rights reserved.
Arpita Banerjee2522bc62013-05-24 16:03:53 -07002 *
3 * Redistribution and use in source and binary forms, with or without
4 * modification, are permitted provided that the following conditions are
5 * 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
9 * copyright notice, this list of conditions and the following
10 * disclaimer in the documentation and/or other materials provided
11 * with the 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 "AS IS" AND ANY EXPRESS OR IMPLIED
17 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
20 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
23 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
24 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
25 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
26 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 *
28 */
29#include <debug.h>
30#include <reg.h>
31#include <err.h>
32#include <smem.h>
33#include <mipi_dsi.h>
34#include <platform/iomap.h>
Veera Sundaram Sankarandb0b2bf2014-12-16 18:09:27 -080035#include <platform/timer.h>
Arpita Banerjee2522bc62013-05-24 16:03:53 -070036
37#define LPFR_LUT_SIZE 10
38
39#define VCO_REF_CLOCK_RATE 19200000
40
41#define FRAC_DIVIDER 10000
42
Veera Sundaram Sankarandb0b2bf2014-12-16 18:09:27 -080043struct lpfr_cfg {
Arpita Banerjee2522bc62013-05-24 16:03:53 -070044 uint32_t vco_rate;
45 uint8_t resistance;
46};
47
48static struct lpfr_cfg lpfr_lut[LPFR_LUT_SIZE] = {
49 {479500000, 8},
50 {480000000, 11},
51 {575500000, 8},
52 {576000000, 12},
53 {610500000, 8},
54 {659500000, 9},
55 {671500000, 10},
56 {672000000, 14},
57 {708500000, 10},
58 {750000000, 11},
59 };
60
61uint64_t div_s64(uint64_t dividend, uint32_t divisor, uint32_t *remainder)
62{
63 *remainder = dividend % divisor;
64
65 return dividend / divisor;
66}
67
Padmanabhan Komanduru703bd6d2014-03-25 19:57:01 +053068void mdss_dsi_uniphy_pll_lock_detect_setting(uint32_t pll_base)
69{
70 writel(0x0c, pll_base + 0x0064); /* LKDetect CFG2 */
71 udelay(100);
72 writel(0x0d, pll_base + 0x0064); /* LKDetect CFG2 */
Dhaval Patelf04efc32014-04-10 18:22:07 -070073 mdelay(1);
Padmanabhan Komanduru703bd6d2014-03-25 19:57:01 +053074}
75
76void mdss_dsi_uniphy_pll_sw_reset(uint32_t pll_base)
77{
78 writel(0x01, pll_base + 0x0068); /* PLL TEST CFG */
79 udelay(1);
80 writel(0x00, pll_base + 0x0068); /* PLL TEST CFG */
81 udelay(1);
82}
83
Padmanabhan Komanduru1fc8bc42015-12-21 18:30:46 +053084uint64_t div_round_closest_unsigned(uint64_t dividend, uint64_t divisor)
Arpita Banerjee2522bc62013-05-24 16:03:53 -070085{
Padmanabhan Komanduru1fc8bc42015-12-21 18:30:46 +053086 return ((dividend + (divisor / 2)) / divisor);
87}
88
89static int32_t mdss_dsi_pll_vco_rate_calc(struct mdss_dsi_pll_config *pd,
90 struct mdss_dsi_vco_calc *vco_calc)
91{
92 uint8_t i;
93 int8_t rc = NO_ERROR;
94 uint32_t rem;
95 uint64_t frac_n_mode = 0, ref_doubler_en_b = 0;
96 uint64_t div_fb = 0, frac_n_value = 0, ref_clk_to_pll = 0;
Arpita Banerjee2522bc62013-05-24 16:03:53 -070097
98 /* Configure the Loop filter resistance */
99 for (i = 0; i < LPFR_LUT_SIZE; i++)
100 if (pd->vco_clock <= lpfr_lut[i].vco_rate)
101 break;
102 if (i == LPFR_LUT_SIZE) {
103 dprintf(INFO, "unable to get loop filter resistance. vco=%d\n"
Lijuan Gao49a1a792014-10-22 11:19:37 +0800104 , lpfr_lut[i-1].vco_rate);
Arpita Banerjee2522bc62013-05-24 16:03:53 -0700105 rc = ERROR;
106 return rc;
107 }
Padmanabhan Komanduru1fc8bc42015-12-21 18:30:46 +0530108 vco_calc->lpfr_lut_res = lpfr_lut[i].resistance;
Arpita Banerjee2522bc62013-05-24 16:03:53 -0700109
Padmanabhan Komanduru1fc8bc42015-12-21 18:30:46 +0530110 rem = pd->vco_clock % VCO_REF_CLOCK_RATE;
111 if (rem) {
112 vco_calc->refclk_cfg = 0x1;
113 frac_n_mode = 1;
114 ref_doubler_en_b = 0;
115 } else {
116 vco_calc->refclk_cfg = 0x0;
117 frac_n_mode = 0;
118 ref_doubler_en_b = 1;
119 }
Arpita Banerjee2522bc62013-05-24 16:03:53 -0700120
Padmanabhan Komanduru1fc8bc42015-12-21 18:30:46 +0530121 ref_clk_to_pll = (VCO_REF_CLOCK_RATE * 2 * vco_calc->refclk_cfg)
122 + (ref_doubler_en_b * VCO_REF_CLOCK_RATE);
123 div_fb = div_s64(pd->vco_clock, ref_clk_to_pll, &rem);
124 frac_n_value = ((uint64_t) rem * (1 << 16)) / ref_clk_to_pll;
125 vco_calc->gen_vco_clk = pd->vco_clock;
126
127 if (frac_n_mode) {
128 vco_calc->sdm_cfg0 = 0x0;
129 vco_calc->sdm_cfg1 = (div_fb & 0x3f) - 1;
130 vco_calc->sdm_cfg3 = frac_n_value / 256;
131 vco_calc->sdm_cfg2 = frac_n_value % 256;
132 } else {
133 vco_calc->sdm_cfg0 = (0x1 << 5);
134 vco_calc->sdm_cfg0 |= (div_fb & 0x3f) - 1;
135 vco_calc->sdm_cfg1 = 0x0;
136 vco_calc->sdm_cfg2 = 0;
137 vco_calc->sdm_cfg3 = 0;
138 }
139
140 vco_calc->cal_cfg11 = vco_calc->gen_vco_clk / 256000000;
141 vco_calc->cal_cfg10 = (vco_calc->gen_vco_clk % 256000000) / 1000000;
142
143 return NO_ERROR;
144
145}
146
147static void mdss_dsi_ssc_param_calc(struct mdss_dsi_pll_config *pd,
148 struct mdss_dsi_vco_calc *vco_calc)
149{
150 uint64_t ppm_freq, incr, spread_freq, div_rf, frac_n_value;
151 uint32_t rem;
152
153 vco_calc->ssc.kdiv = div_round_closest_unsigned(VCO_REF_CLOCK_RATE,
154 1000000) - 1;
155 vco_calc->ssc.triang_steps = div_round_closest_unsigned(
156 VCO_REF_CLOCK_RATE, pd->ssc_freq * (vco_calc->ssc.kdiv + 1));
157 ppm_freq = (vco_calc->gen_vco_clk * pd->ssc_ppm) / 1000000;
158 incr = (ppm_freq * 65536) / (VCO_REF_CLOCK_RATE * 2 *
159 vco_calc->ssc.triang_steps);
160
161 vco_calc->ssc.triang_inc_7_0 = incr & 0xff;
162 vco_calc->ssc.triang_inc_9_8 = (incr >> 8) & 0x3;
163
164 if (!pd->is_center_spread)
165 spread_freq = vco_calc->gen_vco_clk - ppm_freq;
166 else
167 spread_freq = vco_calc->gen_vco_clk - (ppm_freq / 2);
168
169 div_rf = spread_freq / (2 * VCO_REF_CLOCK_RATE);
170 vco_calc->ssc.dc_offset = (div_rf - 1);
171
172 div_s64(spread_freq, 2 * VCO_REF_CLOCK_RATE, &rem);
173 frac_n_value = ((uint64_t) rem * 65536) / (2 * VCO_REF_CLOCK_RATE);
174
175 vco_calc->ssc.freq_seed_7_0 = frac_n_value & 0xff;
176 vco_calc->ssc.freq_seed_15_8 = (frac_n_value >> 8) & 0xff;
177
178}
179
180static void mdss_dsi_pll_vco_config(uint32_t pll_base, struct mdss_dsi_pll_config *pd,
181 struct mdss_dsi_vco_calc *vco_calc)
182{
Arpita Banerjee2522bc62013-05-24 16:03:53 -0700183 /* Loop filter resistance value */
Padmanabhan Komanduru1fc8bc42015-12-21 18:30:46 +0530184 writel(vco_calc->lpfr_lut_res, pll_base + 0x002c);
Arpita Banerjee2522bc62013-05-24 16:03:53 -0700185 /* Loop filter capacitance values : c1 and c2 */
Padmanabhan Komanduru703bd6d2014-03-25 19:57:01 +0530186 writel(0x70, pll_base + 0x0030);
187 writel(0x15, pll_base + 0x0034);
Arpita Banerjee2522bc62013-05-24 16:03:53 -0700188
Padmanabhan Komanduru703bd6d2014-03-25 19:57:01 +0530189 writel(0x02, pll_base + 0x0008); /* ChgPump */
Arpita Banerjee2522bc62013-05-24 16:03:53 -0700190 /* postDiv1 - calculated in pll config*/
Padmanabhan Komanduru703bd6d2014-03-25 19:57:01 +0530191 writel(pd->posdiv1, pll_base + 0x0004);
Arpita Banerjee2522bc62013-05-24 16:03:53 -0700192 /* postDiv2 - fixed devision 4 */
Padmanabhan Komanduru703bd6d2014-03-25 19:57:01 +0530193 writel(0x03, pll_base + 0x0024);
Arpita Banerjee2522bc62013-05-24 16:03:53 -0700194 /* postDiv3 - calculated in pll config */
Padmanabhan Komanduru703bd6d2014-03-25 19:57:01 +0530195 writel(pd->posdiv3, pll_base + 0x0028); /* postDiv3 */
Arpita Banerjee2522bc62013-05-24 16:03:53 -0700196
Padmanabhan Komanduru703bd6d2014-03-25 19:57:01 +0530197 writel(0x2b, pll_base + 0x0078); /* Cal CFG3 */
198 writel(0x66, pll_base + 0x007c); /* Cal CFG4 */
199 writel(0x05, pll_base + 0x0064); /* LKDetect CFG2 */
Arpita Banerjee2522bc62013-05-24 16:03:53 -0700200
Padmanabhan Komanduru1fc8bc42015-12-21 18:30:46 +0530201 if (!pd->ssc_en) {
202 writel(vco_calc->sdm_cfg1 , pll_base + 0x003c); /* SDM CFG1 */
203 writel(vco_calc->sdm_cfg2 , pll_base + 0x0040); /* SDM CFG2 */
204 writel(vco_calc->sdm_cfg3 , pll_base + 0x0044); /* SDM CFG3 */
Arpita Banerjee2522bc62013-05-24 16:03:53 -0700205 } else {
Padmanabhan Komanduru1fc8bc42015-12-21 18:30:46 +0530206 writel(vco_calc->ssc.dc_offset , pll_base + 0x003c); /* SDM CFG1 */
207 writel(vco_calc->ssc.freq_seed_7_0, pll_base + 0x0040); /* SDM CFG2 */
208 writel(vco_calc->ssc.freq_seed_15_8 , pll_base + 0x0044); /* SDM CFG3 */
209 writel(vco_calc->ssc.kdiv, pll_base + 0x4c); /* SSC CFG0 */
210 writel(vco_calc->ssc.triang_inc_7_0, pll_base + 0x50); /* SSC CFG1 */
211 writel(vco_calc->ssc.triang_inc_9_8, pll_base + 0x54); /* SSC CFG2 */
212 writel(vco_calc->ssc.triang_steps, pll_base + 0x58); /* SSC CFG3 */
Arpita Banerjee2522bc62013-05-24 16:03:53 -0700213 }
214
Padmanabhan Komanduru703bd6d2014-03-25 19:57:01 +0530215 writel(0x00, pll_base + 0x0048); /* SDM CFG4 */
Arpita Banerjee2522bc62013-05-24 16:03:53 -0700216
Padmanabhan Komanduru05975022014-04-17 16:47:34 +0530217 if (pd->vco_delay)
218 udelay(pd->vco_delay);
219 else
220 udelay(10);
Arpita Banerjee2522bc62013-05-24 16:03:53 -0700221
Padmanabhan Komanduru1fc8bc42015-12-21 18:30:46 +0530222 writel(vco_calc->refclk_cfg, pll_base + 0x0000); /* REFCLK CFG */
Padmanabhan Komanduru703bd6d2014-03-25 19:57:01 +0530223 writel(0x00, pll_base + 0x0014); /* PWRGEN CFG */
224 writel(0x71, pll_base + 0x000c); /* VCOLPF CFG */
225 writel(pd->directpath, pll_base + 0x0010); /* VREG CFG */
Padmanabhan Komanduru1fc8bc42015-12-21 18:30:46 +0530226 writel(vco_calc->sdm_cfg0, pll_base + 0x0038); /* SDM CFG0 */
Arpita Banerjee2522bc62013-05-24 16:03:53 -0700227
Padmanabhan Komanduru703bd6d2014-03-25 19:57:01 +0530228 writel(0x0a, pll_base + 0x006c); /* CAL CFG0 */
229 writel(0x30, pll_base + 0x0084); /* CAL CFG6 */
230 writel(0x00, pll_base + 0x0088); /* CAL CFG7 */
231 writel(0x60, pll_base + 0x008c); /* CAL CFG8 */
232 writel(0x00, pll_base + 0x0090); /* CAL CFG9 */
Padmanabhan Komanduru1fc8bc42015-12-21 18:30:46 +0530233 writel(vco_calc->cal_cfg10, pll_base + 0x0094); /* CAL CFG10 */
234 writel(vco_calc->cal_cfg11, pll_base + 0x0098); /* CAL CFG11 */
Padmanabhan Komanduru703bd6d2014-03-25 19:57:01 +0530235 writel(0x20, pll_base + 0x009c); /* EFUSE CFG */
Padmanabhan Komanduru1fc8bc42015-12-21 18:30:46 +0530236}
237
238int32_t mdss_dsi_auto_pll_config(uint32_t pll_base, uint32_t ctl_base,
239 struct mdss_dsi_pll_config *pd)
240{
241 int rc = NO_ERROR;
242 struct mdss_dsi_vco_calc vco_calc;
243
244
245 rc = mdss_dsi_pll_vco_rate_calc(pd, &vco_calc);
246 if (rc)
247 return rc;
248
249 mdss_dsi_ssc_param_calc(pd, &vco_calc);
250
251 mdss_dsi_phy_sw_reset(ctl_base);
252
253 mdss_dsi_pll_vco_config(pll_base, pd, &vco_calc);
254
Veera Sundaram Sankarandb0b2bf2014-12-16 18:09:27 -0800255 return rc;
Arpita Banerjee2522bc62013-05-24 16:03:53 -0700256}