blob: 77f1efe4e013d077349d5e7adac050bd3f34950b [file] [log] [blame]
Hai Lia6895542015-03-31 14:36:33 -04001/*
2 * Copyright (c) 2015, The Linux Foundation. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 and
6 * only version 2 as published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 */
13
Hai Liec31abf2015-05-15 13:04:06 -040014#include <linux/platform_device.h>
15#include <linux/regulator/consumer.h>
16
Hai Lia6895542015-03-31 14:36:33 -040017#include "dsi.h"
18#include "dsi.xml.h"
19
20#define dsi_phy_read(offset) msm_readl((offset))
21#define dsi_phy_write(offset, data) msm_writel((data), (offset))
22
Hai Liec31abf2015-05-15 13:04:06 -040023struct dsi_phy_ops {
Hai Li13351cd2015-06-10 13:18:17 -040024 int (*enable)(struct msm_dsi_phy *phy, int src_pll_id,
Hai Liec31abf2015-05-15 13:04:06 -040025 const unsigned long bit_rate, const unsigned long esc_rate);
Hai Li29e61692015-08-13 17:45:51 -040026 void (*disable)(struct msm_dsi_phy *phy);
Hai Liec31abf2015-05-15 13:04:06 -040027};
28
29struct dsi_phy_cfg {
30 enum msm_dsi_phy_type type;
31 struct dsi_reg_config reg_cfg;
32 struct dsi_phy_ops ops;
Hai Li13351cd2015-06-10 13:18:17 -040033
34 /* Each cell {phy_id, pll_id} of the truth table indicates
35 * if the source PLL is on the right side of the PHY.
36 * Fill default H/W values in illegal cells, eg. cell {0, 1}.
37 */
38 bool src_pll_truthtable[DSI_MAX][DSI_MAX];
Hai Liec31abf2015-05-15 13:04:06 -040039};
40
Hai Lia6895542015-03-31 14:36:33 -040041struct dsi_dphy_timing {
42 u32 clk_pre;
43 u32 clk_post;
44 u32 clk_zero;
45 u32 clk_trail;
46 u32 clk_prepare;
47 u32 hs_exit;
48 u32 hs_zero;
49 u32 hs_prepare;
50 u32 hs_trail;
51 u32 hs_rqst;
52 u32 ta_go;
53 u32 ta_sure;
54 u32 ta_get;
55};
56
57struct msm_dsi_phy {
Hai Li9d32c4982015-05-15 13:04:05 -040058 struct platform_device *pdev;
Hai Lia6895542015-03-31 14:36:33 -040059 void __iomem *base;
60 void __iomem *reg_base;
61 int id;
Hai Li9d32c4982015-05-15 13:04:05 -040062
63 struct clk *ahb_clk;
Hai Liec31abf2015-05-15 13:04:06 -040064 struct regulator_bulk_data supplies[DSI_DEV_REGULATOR_MAX];
Hai Li9d32c4982015-05-15 13:04:05 -040065
Hai Lia6895542015-03-31 14:36:33 -040066 struct dsi_dphy_timing timing;
Hai Liec31abf2015-05-15 13:04:06 -040067 const struct dsi_phy_cfg *cfg;
Hai Li9d32c4982015-05-15 13:04:05 -040068
Hai Lidcefc112015-06-18 10:14:21 -040069 bool regulator_ldo_mode;
70
Hai Li9d32c4982015-05-15 13:04:05 -040071 struct msm_dsi_pll *pll;
Hai Lia6895542015-03-31 14:36:33 -040072};
73
Hai Liec31abf2015-05-15 13:04:06 -040074static int dsi_phy_regulator_init(struct msm_dsi_phy *phy)
75{
76 struct regulator_bulk_data *s = phy->supplies;
77 const struct dsi_reg_entry *regs = phy->cfg->reg_cfg.regs;
78 struct device *dev = &phy->pdev->dev;
79 int num = phy->cfg->reg_cfg.num;
80 int i, ret;
81
82 for (i = 0; i < num; i++)
83 s[i].supply = regs[i].name;
84
85 ret = devm_regulator_bulk_get(&phy->pdev->dev, num, s);
86 if (ret < 0) {
87 dev_err(dev, "%s: failed to init regulator, ret=%d\n",
88 __func__, ret);
89 return ret;
90 }
91
92 for (i = 0; i < num; i++) {
93 if ((regs[i].min_voltage >= 0) && (regs[i].max_voltage >= 0)) {
94 ret = regulator_set_voltage(s[i].consumer,
95 regs[i].min_voltage, regs[i].max_voltage);
96 if (ret < 0) {
97 dev_err(dev,
98 "regulator %d set voltage failed, %d\n",
99 i, ret);
100 return ret;
101 }
102 }
103 }
104
105 return 0;
106}
107
108static void dsi_phy_regulator_disable(struct msm_dsi_phy *phy)
109{
110 struct regulator_bulk_data *s = phy->supplies;
111 const struct dsi_reg_entry *regs = phy->cfg->reg_cfg.regs;
112 int num = phy->cfg->reg_cfg.num;
113 int i;
114
115 DBG("");
116 for (i = num - 1; i >= 0; i--)
117 if (regs[i].disable_load >= 0)
118 regulator_set_load(s[i].consumer,
119 regs[i].disable_load);
120
121 regulator_bulk_disable(num, s);
122}
123
124static int dsi_phy_regulator_enable(struct msm_dsi_phy *phy)
125{
126 struct regulator_bulk_data *s = phy->supplies;
127 const struct dsi_reg_entry *regs = phy->cfg->reg_cfg.regs;
128 struct device *dev = &phy->pdev->dev;
129 int num = phy->cfg->reg_cfg.num;
130 int ret, i;
131
132 DBG("");
133 for (i = 0; i < num; i++) {
134 if (regs[i].enable_load >= 0) {
135 ret = regulator_set_load(s[i].consumer,
136 regs[i].enable_load);
137 if (ret < 0) {
138 dev_err(dev,
139 "regulator %d set op mode failed, %d\n",
140 i, ret);
141 goto fail;
142 }
143 }
144 }
145
146 ret = regulator_bulk_enable(num, s);
147 if (ret < 0) {
148 dev_err(dev, "regulator enable failed, %d\n", ret);
149 goto fail;
150 }
151
152 return 0;
153
154fail:
155 for (i--; i >= 0; i--)
156 regulator_set_load(s[i].consumer, regs[i].disable_load);
157 return ret;
158}
159
Hai Lifae11c12015-08-13 17:45:50 -0400160static void dsi_phy_set_src_pll(struct msm_dsi_phy *phy, int pll_id, u32 reg,
161 u32 bit_mask)
Hai Li13351cd2015-06-10 13:18:17 -0400162{
163 int phy_id = phy->id;
Hai Lifae11c12015-08-13 17:45:50 -0400164 u32 val;
Hai Li13351cd2015-06-10 13:18:17 -0400165
166 if ((phy_id >= DSI_MAX) || (pll_id >= DSI_MAX))
167 return;
168
Hai Lifae11c12015-08-13 17:45:50 -0400169 val = dsi_phy_read(phy->base + reg);
170
Hai Li13351cd2015-06-10 13:18:17 -0400171 if (phy->cfg->src_pll_truthtable[phy_id][pll_id])
Hai Lifae11c12015-08-13 17:45:50 -0400172 dsi_phy_write(phy->base + reg, val | bit_mask);
Hai Li13351cd2015-06-10 13:18:17 -0400173 else
Hai Lifae11c12015-08-13 17:45:50 -0400174 dsi_phy_write(phy->base + reg, val & (~bit_mask));
Hai Li13351cd2015-06-10 13:18:17 -0400175}
176
Hai Lia6895542015-03-31 14:36:33 -0400177#define S_DIV_ROUND_UP(n, d) \
178 (((n) >= 0) ? (((n) + (d) - 1) / (d)) : (((n) - (d) + 1) / (d)))
179
180static inline s32 linear_inter(s32 tmax, s32 tmin, s32 percent,
181 s32 min_result, bool even)
182{
183 s32 v;
184 v = (tmax - tmin) * percent;
185 v = S_DIV_ROUND_UP(v, 100) + tmin;
186 if (even && (v & 0x1))
187 return max_t(s32, min_result, v - 1);
188 else
189 return max_t(s32, min_result, v);
190}
191
192static void dsi_dphy_timing_calc_clk_zero(struct dsi_dphy_timing *timing,
193 s32 ui, s32 coeff, s32 pcnt)
194{
195 s32 tmax, tmin, clk_z;
196 s32 temp;
197
198 /* reset */
199 temp = 300 * coeff - ((timing->clk_prepare >> 1) + 1) * 2 * ui;
200 tmin = S_DIV_ROUND_UP(temp, ui) - 2;
201 if (tmin > 255) {
202 tmax = 511;
203 clk_z = linear_inter(2 * tmin, tmin, pcnt, 0, true);
204 } else {
205 tmax = 255;
206 clk_z = linear_inter(tmax, tmin, pcnt, 0, true);
207 }
208
209 /* adjust */
210 temp = (timing->hs_rqst + timing->clk_prepare + clk_z) & 0x7;
211 timing->clk_zero = clk_z + 8 - temp;
212}
213
214static int dsi_dphy_timing_calc(struct dsi_dphy_timing *timing,
215 const unsigned long bit_rate, const unsigned long esc_rate)
216{
217 s32 ui, lpx;
218 s32 tmax, tmin;
219 s32 pcnt0 = 10;
220 s32 pcnt1 = (bit_rate > 1200000000) ? 15 : 10;
221 s32 pcnt2 = 10;
222 s32 pcnt3 = (bit_rate > 180000000) ? 10 : 40;
223 s32 coeff = 1000; /* Precision, should avoid overflow */
224 s32 temp;
225
226 if (!bit_rate || !esc_rate)
227 return -EINVAL;
228
229 ui = mult_frac(NSEC_PER_MSEC, coeff, bit_rate / 1000);
230 lpx = mult_frac(NSEC_PER_MSEC, coeff, esc_rate / 1000);
231
232 tmax = S_DIV_ROUND_UP(95 * coeff, ui) - 2;
233 tmin = S_DIV_ROUND_UP(38 * coeff, ui) - 2;
234 timing->clk_prepare = linear_inter(tmax, tmin, pcnt0, 0, true);
235
236 temp = lpx / ui;
237 if (temp & 0x1)
238 timing->hs_rqst = temp;
239 else
240 timing->hs_rqst = max_t(s32, 0, temp - 2);
241
242 /* Calculate clk_zero after clk_prepare and hs_rqst */
243 dsi_dphy_timing_calc_clk_zero(timing, ui, coeff, pcnt2);
244
245 temp = 105 * coeff + 12 * ui - 20 * coeff;
246 tmax = S_DIV_ROUND_UP(temp, ui) - 2;
247 tmin = S_DIV_ROUND_UP(60 * coeff, ui) - 2;
248 timing->clk_trail = linear_inter(tmax, tmin, pcnt3, 0, true);
249
250 temp = 85 * coeff + 6 * ui;
251 tmax = S_DIV_ROUND_UP(temp, ui) - 2;
252 temp = 40 * coeff + 4 * ui;
253 tmin = S_DIV_ROUND_UP(temp, ui) - 2;
254 timing->hs_prepare = linear_inter(tmax, tmin, pcnt1, 0, true);
255
256 tmax = 255;
257 temp = ((timing->hs_prepare >> 1) + 1) * 2 * ui + 2 * ui;
258 temp = 145 * coeff + 10 * ui - temp;
259 tmin = S_DIV_ROUND_UP(temp, ui) - 2;
260 timing->hs_zero = linear_inter(tmax, tmin, pcnt2, 24, true);
261
262 temp = 105 * coeff + 12 * ui - 20 * coeff;
263 tmax = S_DIV_ROUND_UP(temp, ui) - 2;
264 temp = 60 * coeff + 4 * ui;
265 tmin = DIV_ROUND_UP(temp, ui) - 2;
266 timing->hs_trail = linear_inter(tmax, tmin, pcnt3, 0, true);
267
268 tmax = 255;
269 tmin = S_DIV_ROUND_UP(100 * coeff, ui) - 2;
270 timing->hs_exit = linear_inter(tmax, tmin, pcnt2, 0, true);
271
272 tmax = 63;
273 temp = ((timing->hs_exit >> 1) + 1) * 2 * ui;
274 temp = 60 * coeff + 52 * ui - 24 * ui - temp;
275 tmin = S_DIV_ROUND_UP(temp, 8 * ui) - 1;
276 timing->clk_post = linear_inter(tmax, tmin, pcnt2, 0, false);
277
278 tmax = 63;
279 temp = ((timing->clk_prepare >> 1) + 1) * 2 * ui;
280 temp += ((timing->clk_zero >> 1) + 1) * 2 * ui;
281 temp += 8 * ui + lpx;
282 tmin = S_DIV_ROUND_UP(temp, 8 * ui) - 1;
283 if (tmin > tmax) {
284 temp = linear_inter(2 * tmax, tmin, pcnt2, 0, false) >> 1;
285 timing->clk_pre = temp >> 1;
286 temp = (2 * tmax - tmin) * pcnt2;
287 } else {
288 timing->clk_pre = linear_inter(tmax, tmin, pcnt2, 0, false);
289 }
290
291 timing->ta_go = 3;
292 timing->ta_sure = 0;
293 timing->ta_get = 4;
294
295 DBG("PHY timings: %d, %d, %d, %d, %d, %d, %d, %d, %d, %d",
296 timing->clk_pre, timing->clk_post, timing->clk_zero,
297 timing->clk_trail, timing->clk_prepare, timing->hs_exit,
298 timing->hs_zero, timing->hs_prepare, timing->hs_trail,
299 timing->hs_rqst);
300
301 return 0;
302}
303
304static void dsi_28nm_phy_regulator_ctrl(struct msm_dsi_phy *phy, bool enable)
305{
306 void __iomem *base = phy->reg_base;
307
308 if (!enable) {
309 dsi_phy_write(base + REG_DSI_28nm_PHY_REGULATOR_CAL_PWR_CFG, 0);
310 return;
311 }
312
313 dsi_phy_write(base + REG_DSI_28nm_PHY_REGULATOR_CTRL_0, 0x0);
314 dsi_phy_write(base + REG_DSI_28nm_PHY_REGULATOR_CAL_PWR_CFG, 1);
315 dsi_phy_write(base + REG_DSI_28nm_PHY_REGULATOR_CTRL_5, 0);
316 dsi_phy_write(base + REG_DSI_28nm_PHY_REGULATOR_CTRL_3, 0);
317 dsi_phy_write(base + REG_DSI_28nm_PHY_REGULATOR_CTRL_2, 0x3);
318 dsi_phy_write(base + REG_DSI_28nm_PHY_REGULATOR_CTRL_1, 0x9);
319 dsi_phy_write(base + REG_DSI_28nm_PHY_REGULATOR_CTRL_0, 0x7);
320 dsi_phy_write(base + REG_DSI_28nm_PHY_REGULATOR_CTRL_4, 0x20);
321}
322
Hai Li13351cd2015-06-10 13:18:17 -0400323static int dsi_28nm_phy_enable(struct msm_dsi_phy *phy, int src_pll_id,
Hai Lia6895542015-03-31 14:36:33 -0400324 const unsigned long bit_rate, const unsigned long esc_rate)
325{
326 struct dsi_dphy_timing *timing = &phy->timing;
327 int i;
328 void __iomem *base = phy->base;
329
330 DBG("");
331
332 if (dsi_dphy_timing_calc(timing, bit_rate, esc_rate)) {
333 pr_err("%s: D-PHY timing calculation failed\n", __func__);
334 return -EINVAL;
335 }
336
337 dsi_phy_write(base + REG_DSI_28nm_PHY_STRENGTH_0, 0xff);
338
339 dsi_28nm_phy_regulator_ctrl(phy, true);
340
341 dsi_phy_write(base + REG_DSI_28nm_PHY_LDO_CNTRL, 0x00);
342
343 dsi_phy_write(base + REG_DSI_28nm_PHY_TIMING_CTRL_0,
344 DSI_28nm_PHY_TIMING_CTRL_0_CLK_ZERO(timing->clk_zero));
345 dsi_phy_write(base + REG_DSI_28nm_PHY_TIMING_CTRL_1,
346 DSI_28nm_PHY_TIMING_CTRL_1_CLK_TRAIL(timing->clk_trail));
347 dsi_phy_write(base + REG_DSI_28nm_PHY_TIMING_CTRL_2,
348 DSI_28nm_PHY_TIMING_CTRL_2_CLK_PREPARE(timing->clk_prepare));
349 if (timing->clk_zero & BIT(8))
350 dsi_phy_write(base + REG_DSI_28nm_PHY_TIMING_CTRL_3,
351 DSI_28nm_PHY_TIMING_CTRL_3_CLK_ZERO_8);
352 dsi_phy_write(base + REG_DSI_28nm_PHY_TIMING_CTRL_4,
353 DSI_28nm_PHY_TIMING_CTRL_4_HS_EXIT(timing->hs_exit));
354 dsi_phy_write(base + REG_DSI_28nm_PHY_TIMING_CTRL_5,
355 DSI_28nm_PHY_TIMING_CTRL_5_HS_ZERO(timing->hs_zero));
356 dsi_phy_write(base + REG_DSI_28nm_PHY_TIMING_CTRL_6,
357 DSI_28nm_PHY_TIMING_CTRL_6_HS_PREPARE(timing->hs_prepare));
358 dsi_phy_write(base + REG_DSI_28nm_PHY_TIMING_CTRL_7,
359 DSI_28nm_PHY_TIMING_CTRL_7_HS_TRAIL(timing->hs_trail));
360 dsi_phy_write(base + REG_DSI_28nm_PHY_TIMING_CTRL_8,
361 DSI_28nm_PHY_TIMING_CTRL_8_HS_RQST(timing->hs_rqst));
362 dsi_phy_write(base + REG_DSI_28nm_PHY_TIMING_CTRL_9,
363 DSI_28nm_PHY_TIMING_CTRL_9_TA_GO(timing->ta_go) |
364 DSI_28nm_PHY_TIMING_CTRL_9_TA_SURE(timing->ta_sure));
365 dsi_phy_write(base + REG_DSI_28nm_PHY_TIMING_CTRL_10,
366 DSI_28nm_PHY_TIMING_CTRL_10_TA_GET(timing->ta_get));
367 dsi_phy_write(base + REG_DSI_28nm_PHY_TIMING_CTRL_11,
368 DSI_28nm_PHY_TIMING_CTRL_11_TRIG3_CMD(0));
369
370 dsi_phy_write(base + REG_DSI_28nm_PHY_CTRL_1, 0x00);
371 dsi_phy_write(base + REG_DSI_28nm_PHY_CTRL_0, 0x5f);
372
373 dsi_phy_write(base + REG_DSI_28nm_PHY_STRENGTH_1, 0x6);
374
375 for (i = 0; i < 4; i++) {
376 dsi_phy_write(base + REG_DSI_28nm_PHY_LN_CFG_0(i), 0);
377 dsi_phy_write(base + REG_DSI_28nm_PHY_LN_CFG_1(i), 0);
378 dsi_phy_write(base + REG_DSI_28nm_PHY_LN_CFG_2(i), 0);
379 dsi_phy_write(base + REG_DSI_28nm_PHY_LN_CFG_3(i), 0);
380 dsi_phy_write(base + REG_DSI_28nm_PHY_LN_TEST_DATAPATH(i), 0);
381 dsi_phy_write(base + REG_DSI_28nm_PHY_LN_DEBUG_SEL(i), 0);
382 dsi_phy_write(base + REG_DSI_28nm_PHY_LN_TEST_STR_0(i), 0x1);
383 dsi_phy_write(base + REG_DSI_28nm_PHY_LN_TEST_STR_1(i), 0x97);
384 }
385 dsi_phy_write(base + REG_DSI_28nm_PHY_LN_CFG_4(0), 0);
386 dsi_phy_write(base + REG_DSI_28nm_PHY_LN_CFG_4(1), 0x5);
387 dsi_phy_write(base + REG_DSI_28nm_PHY_LN_CFG_4(2), 0xa);
388 dsi_phy_write(base + REG_DSI_28nm_PHY_LN_CFG_4(3), 0xf);
389
390 dsi_phy_write(base + REG_DSI_28nm_PHY_LNCK_CFG_1, 0xc0);
391 dsi_phy_write(base + REG_DSI_28nm_PHY_LNCK_TEST_STR0, 0x1);
392 dsi_phy_write(base + REG_DSI_28nm_PHY_LNCK_TEST_STR1, 0xbb);
393
394 dsi_phy_write(base + REG_DSI_28nm_PHY_CTRL_0, 0x5f);
395
Hai Lifae11c12015-08-13 17:45:50 -0400396 dsi_phy_set_src_pll(phy, src_pll_id, REG_DSI_28nm_PHY_GLBL_TEST_CTRL,
397 DSI_28nm_PHY_GLBL_TEST_CTRL_BITCLK_HS_SEL);
Hai Lia6895542015-03-31 14:36:33 -0400398
399 return 0;
400}
401
Hai Li29e61692015-08-13 17:45:51 -0400402static void dsi_28nm_phy_disable(struct msm_dsi_phy *phy)
Hai Lia6895542015-03-31 14:36:33 -0400403{
404 dsi_phy_write(phy->base + REG_DSI_28nm_PHY_CTRL_0, 0);
405 dsi_28nm_phy_regulator_ctrl(phy, false);
406
407 /*
408 * Wait for the registers writes to complete in order to
409 * ensure that the phy is completely disabled
410 */
411 wmb();
Hai Lia6895542015-03-31 14:36:33 -0400412}
413
Hai Lidcefc112015-06-18 10:14:21 -0400414static void dsi_20nm_phy_regulator_ctrl(struct msm_dsi_phy *phy, bool enable)
415{
416 void __iomem *base = phy->reg_base;
417
418 if (!enable) {
419 dsi_phy_write(base + REG_DSI_20nm_PHY_REGULATOR_CAL_PWR_CFG, 0);
420 return;
421 }
422
423 if (phy->regulator_ldo_mode) {
424 dsi_phy_write(phy->base + REG_DSI_20nm_PHY_LDO_CNTRL, 0x1d);
425 return;
426 }
427
428 /* non LDO mode */
429 dsi_phy_write(base + REG_DSI_20nm_PHY_REGULATOR_CTRL_1, 0x03);
430 dsi_phy_write(base + REG_DSI_20nm_PHY_REGULATOR_CTRL_2, 0x03);
431 dsi_phy_write(base + REG_DSI_20nm_PHY_REGULATOR_CTRL_3, 0x00);
432 dsi_phy_write(base + REG_DSI_20nm_PHY_REGULATOR_CTRL_4, 0x20);
433 dsi_phy_write(base + REG_DSI_20nm_PHY_REGULATOR_CAL_PWR_CFG, 0x01);
434 dsi_phy_write(phy->base + REG_DSI_20nm_PHY_LDO_CNTRL, 0x00);
435 dsi_phy_write(base + REG_DSI_20nm_PHY_REGULATOR_CTRL_0, 0x03);
436}
437
438static int dsi_20nm_phy_enable(struct msm_dsi_phy *phy, int src_pll_id,
439 const unsigned long bit_rate, const unsigned long esc_rate)
440{
441 struct dsi_dphy_timing *timing = &phy->timing;
442 int i;
443 void __iomem *base = phy->base;
444 u32 cfg_4[4] = {0x20, 0x40, 0x20, 0x00};
445
446 DBG("");
447
448 if (dsi_dphy_timing_calc(timing, bit_rate, esc_rate)) {
449 pr_err("%s: D-PHY timing calculation failed\n", __func__);
450 return -EINVAL;
451 }
452
453 dsi_20nm_phy_regulator_ctrl(phy, true);
454
455 dsi_phy_write(base + REG_DSI_20nm_PHY_STRENGTH_0, 0xff);
456
Hai Lifae11c12015-08-13 17:45:50 -0400457 dsi_phy_set_src_pll(phy, src_pll_id, REG_DSI_20nm_PHY_GLBL_TEST_CTRL,
458 DSI_20nm_PHY_GLBL_TEST_CTRL_BITCLK_HS_SEL);
Hai Lidcefc112015-06-18 10:14:21 -0400459
460 for (i = 0; i < 4; i++) {
461 dsi_phy_write(base + REG_DSI_20nm_PHY_LN_CFG_3(i),
462 (i >> 1) * 0x40);
463 dsi_phy_write(base + REG_DSI_20nm_PHY_LN_TEST_STR_0(i), 0x01);
464 dsi_phy_write(base + REG_DSI_20nm_PHY_LN_TEST_STR_1(i), 0x46);
465 dsi_phy_write(base + REG_DSI_20nm_PHY_LN_CFG_0(i), 0x02);
466 dsi_phy_write(base + REG_DSI_20nm_PHY_LN_CFG_1(i), 0xa0);
467 dsi_phy_write(base + REG_DSI_20nm_PHY_LN_CFG_4(i), cfg_4[i]);
468 }
469
470 dsi_phy_write(base + REG_DSI_20nm_PHY_LNCK_CFG_3, 0x80);
471 dsi_phy_write(base + REG_DSI_20nm_PHY_LNCK_TEST_STR0, 0x01);
472 dsi_phy_write(base + REG_DSI_20nm_PHY_LNCK_TEST_STR1, 0x46);
473 dsi_phy_write(base + REG_DSI_20nm_PHY_LNCK_CFG_0, 0x00);
474 dsi_phy_write(base + REG_DSI_20nm_PHY_LNCK_CFG_1, 0xa0);
475 dsi_phy_write(base + REG_DSI_20nm_PHY_LNCK_CFG_2, 0x00);
476 dsi_phy_write(base + REG_DSI_20nm_PHY_LNCK_CFG_4, 0x00);
477
478 dsi_phy_write(base + REG_DSI_20nm_PHY_TIMING_CTRL_0,
479 DSI_20nm_PHY_TIMING_CTRL_0_CLK_ZERO(timing->clk_zero));
480 dsi_phy_write(base + REG_DSI_20nm_PHY_TIMING_CTRL_1,
481 DSI_20nm_PHY_TIMING_CTRL_1_CLK_TRAIL(timing->clk_trail));
482 dsi_phy_write(base + REG_DSI_20nm_PHY_TIMING_CTRL_2,
483 DSI_20nm_PHY_TIMING_CTRL_2_CLK_PREPARE(timing->clk_prepare));
484 if (timing->clk_zero & BIT(8))
485 dsi_phy_write(base + REG_DSI_20nm_PHY_TIMING_CTRL_3,
486 DSI_20nm_PHY_TIMING_CTRL_3_CLK_ZERO_8);
487 dsi_phy_write(base + REG_DSI_20nm_PHY_TIMING_CTRL_4,
488 DSI_20nm_PHY_TIMING_CTRL_4_HS_EXIT(timing->hs_exit));
489 dsi_phy_write(base + REG_DSI_20nm_PHY_TIMING_CTRL_5,
490 DSI_20nm_PHY_TIMING_CTRL_5_HS_ZERO(timing->hs_zero));
491 dsi_phy_write(base + REG_DSI_20nm_PHY_TIMING_CTRL_6,
492 DSI_20nm_PHY_TIMING_CTRL_6_HS_PREPARE(timing->hs_prepare));
493 dsi_phy_write(base + REG_DSI_20nm_PHY_TIMING_CTRL_7,
494 DSI_20nm_PHY_TIMING_CTRL_7_HS_TRAIL(timing->hs_trail));
495 dsi_phy_write(base + REG_DSI_20nm_PHY_TIMING_CTRL_8,
496 DSI_20nm_PHY_TIMING_CTRL_8_HS_RQST(timing->hs_rqst));
497 dsi_phy_write(base + REG_DSI_20nm_PHY_TIMING_CTRL_9,
498 DSI_20nm_PHY_TIMING_CTRL_9_TA_GO(timing->ta_go) |
499 DSI_20nm_PHY_TIMING_CTRL_9_TA_SURE(timing->ta_sure));
500 dsi_phy_write(base + REG_DSI_20nm_PHY_TIMING_CTRL_10,
501 DSI_20nm_PHY_TIMING_CTRL_10_TA_GET(timing->ta_get));
502 dsi_phy_write(base + REG_DSI_20nm_PHY_TIMING_CTRL_11,
503 DSI_20nm_PHY_TIMING_CTRL_11_TRIG3_CMD(0));
504
505 dsi_phy_write(base + REG_DSI_20nm_PHY_CTRL_1, 0x00);
506
507 dsi_phy_write(base + REG_DSI_20nm_PHY_STRENGTH_1, 0x06);
508
509 /* make sure everything is written before enable */
510 wmb();
511 dsi_phy_write(base + REG_DSI_20nm_PHY_CTRL_0, 0x7f);
512
513 return 0;
514}
515
Hai Li29e61692015-08-13 17:45:51 -0400516static void dsi_20nm_phy_disable(struct msm_dsi_phy *phy)
Hai Lidcefc112015-06-18 10:14:21 -0400517{
518 dsi_phy_write(phy->base + REG_DSI_20nm_PHY_CTRL_0, 0);
519 dsi_20nm_phy_regulator_ctrl(phy, false);
Hai Lidcefc112015-06-18 10:14:21 -0400520}
521
Hai Li9d32c4982015-05-15 13:04:05 -0400522static int dsi_phy_enable_resource(struct msm_dsi_phy *phy)
523{
524 int ret;
525
526 pm_runtime_get_sync(&phy->pdev->dev);
527
528 ret = clk_prepare_enable(phy->ahb_clk);
529 if (ret) {
530 pr_err("%s: can't enable ahb clk, %d\n", __func__, ret);
531 pm_runtime_put_sync(&phy->pdev->dev);
532 }
533
534 return ret;
535}
536
537static void dsi_phy_disable_resource(struct msm_dsi_phy *phy)
538{
539 clk_disable_unprepare(phy->ahb_clk);
540 pm_runtime_put_sync(&phy->pdev->dev);
541}
542
Hai Liec31abf2015-05-15 13:04:06 -0400543static const struct dsi_phy_cfg dsi_phy_cfgs[MSM_DSI_PHY_MAX] = {
544 [MSM_DSI_PHY_28NM_HPM] = {
545 .type = MSM_DSI_PHY_28NM_HPM,
Hai Li13351cd2015-06-10 13:18:17 -0400546 .src_pll_truthtable = { {true, true}, {false, true} },
Hai Liec31abf2015-05-15 13:04:06 -0400547 .reg_cfg = {
548 .num = 1,
549 .regs = {
550 {"vddio", 1800000, 1800000, 100000, 100},
551 },
552 },
553 .ops = {
554 .enable = dsi_28nm_phy_enable,
555 .disable = dsi_28nm_phy_disable,
556 }
557 },
558 [MSM_DSI_PHY_28NM_LP] = {
559 .type = MSM_DSI_PHY_28NM_LP,
Hai Li13351cd2015-06-10 13:18:17 -0400560 .src_pll_truthtable = { {true, true}, {true, true} },
Hai Liec31abf2015-05-15 13:04:06 -0400561 .reg_cfg = {
562 .num = 1,
563 .regs = {
564 {"vddio", 1800000, 1800000, 100000, 100},
565 },
566 },
567 .ops = {
568 .enable = dsi_28nm_phy_enable,
569 .disable = dsi_28nm_phy_disable,
570 }
571 },
Hai Lidcefc112015-06-18 10:14:21 -0400572 [MSM_DSI_PHY_20NM] = {
573 .type = MSM_DSI_PHY_20NM,
574 .src_pll_truthtable = { {false, true}, {false, true} },
575 .reg_cfg = {
576 .num = 2,
577 .regs = {
578 {"vddio", 1800000, 1800000, 100000, 100},
579 {"vcca", 1000000, 1000000, 10000, 100},
580 },
581 },
582 .ops = {
583 .enable = dsi_20nm_phy_enable,
584 .disable = dsi_20nm_phy_disable,
585 }
586 },
Hai Liec31abf2015-05-15 13:04:06 -0400587};
Hai Lia6895542015-03-31 14:36:33 -0400588
Hai Liec31abf2015-05-15 13:04:06 -0400589static const struct of_device_id dsi_phy_dt_match[] = {
590 { .compatible = "qcom,dsi-phy-28nm-hpm",
591 .data = &dsi_phy_cfgs[MSM_DSI_PHY_28NM_HPM],},
592 { .compatible = "qcom,dsi-phy-28nm-lp",
593 .data = &dsi_phy_cfgs[MSM_DSI_PHY_28NM_LP],},
Hai Lidcefc112015-06-18 10:14:21 -0400594 { .compatible = "qcom,dsi-phy-20nm",
595 .data = &dsi_phy_cfgs[MSM_DSI_PHY_20NM],},
Hai Liec31abf2015-05-15 13:04:06 -0400596 {}
597};
598
599static int dsi_phy_driver_probe(struct platform_device *pdev)
Hai Lia6895542015-03-31 14:36:33 -0400600{
601 struct msm_dsi_phy *phy;
Hai Liec31abf2015-05-15 13:04:06 -0400602 const struct of_device_id *match;
Hai Li9d32c4982015-05-15 13:04:05 -0400603 int ret;
Hai Lia6895542015-03-31 14:36:33 -0400604
605 phy = devm_kzalloc(&pdev->dev, sizeof(*phy), GFP_KERNEL);
606 if (!phy)
Hai Liec31abf2015-05-15 13:04:06 -0400607 return -ENOMEM;
608
609 match = of_match_node(dsi_phy_dt_match, pdev->dev.of_node);
610 if (!match)
611 return -ENODEV;
612
613 phy->cfg = match->data;
614 phy->pdev = pdev;
615
616 ret = of_property_read_u32(pdev->dev.of_node,
617 "qcom,dsi-phy-index", &phy->id);
618 if (ret) {
619 dev_err(&pdev->dev,
620 "%s: PHY index not specified, ret=%d\n",
621 __func__, ret);
622 goto fail;
623 }
Hai Lia6895542015-03-31 14:36:33 -0400624
Hai Lidcefc112015-06-18 10:14:21 -0400625 phy->regulator_ldo_mode = of_property_read_bool(pdev->dev.of_node,
626 "qcom,dsi-phy-regulator-ldo-mode");
627
Hai Lia6895542015-03-31 14:36:33 -0400628 phy->base = msm_ioremap(pdev, "dsi_phy", "DSI_PHY");
Fabian Frederick73dbf692015-05-04 19:03:54 +0200629 if (IS_ERR(phy->base)) {
Hai Liec31abf2015-05-15 13:04:06 -0400630 dev_err(&pdev->dev, "%s: failed to map phy base\n", __func__);
631 ret = -ENOMEM;
632 goto fail;
Hai Lia6895542015-03-31 14:36:33 -0400633 }
634 phy->reg_base = msm_ioremap(pdev, "dsi_phy_regulator", "DSI_PHY_REG");
Fabian Frederick73dbf692015-05-04 19:03:54 +0200635 if (IS_ERR(phy->reg_base)) {
Hai Liec31abf2015-05-15 13:04:06 -0400636 dev_err(&pdev->dev,
637 "%s: failed to map phy regulator base\n", __func__);
638 ret = -ENOMEM;
639 goto fail;
Hai Lia6895542015-03-31 14:36:33 -0400640 }
641
Hai Liec31abf2015-05-15 13:04:06 -0400642 ret = dsi_phy_regulator_init(phy);
643 if (ret) {
644 dev_err(&pdev->dev, "%s: failed to init regulator\n", __func__);
645 goto fail;
Hai Lia6895542015-03-31 14:36:33 -0400646 }
647
Hai Li9d32c4982015-05-15 13:04:05 -0400648 phy->ahb_clk = devm_clk_get(&pdev->dev, "iface_clk");
649 if (IS_ERR(phy->ahb_clk)) {
650 pr_err("%s: Unable to get ahb clk\n", __func__);
Hai Liec31abf2015-05-15 13:04:06 -0400651 ret = PTR_ERR(phy->ahb_clk);
652 goto fail;
Hai Li9d32c4982015-05-15 13:04:05 -0400653 }
654
655 /* PLL init will call into clk_register which requires
656 * register access, so we need to enable power and ahb clock.
657 */
658 ret = dsi_phy_enable_resource(phy);
659 if (ret)
Hai Liec31abf2015-05-15 13:04:06 -0400660 goto fail;
Hai Li9d32c4982015-05-15 13:04:05 -0400661
Hai Liec31abf2015-05-15 13:04:06 -0400662 phy->pll = msm_dsi_pll_init(pdev, phy->cfg->type, phy->id);
Hai Li9d32c4982015-05-15 13:04:05 -0400663 if (!phy->pll)
Hai Liec31abf2015-05-15 13:04:06 -0400664 dev_info(&pdev->dev,
665 "%s: pll init failed, need separate pll clk driver\n",
Hai Li9d32c4982015-05-15 13:04:05 -0400666 __func__);
667
668 dsi_phy_disable_resource(phy);
Hai Lia6895542015-03-31 14:36:33 -0400669
Hai Liec31abf2015-05-15 13:04:06 -0400670 platform_set_drvdata(pdev, phy);
671
672 return 0;
673
674fail:
675 return ret;
Hai Lia6895542015-03-31 14:36:33 -0400676}
677
Hai Liec31abf2015-05-15 13:04:06 -0400678static int dsi_phy_driver_remove(struct platform_device *pdev)
Hai Li9d32c4982015-05-15 13:04:05 -0400679{
Hai Liec31abf2015-05-15 13:04:06 -0400680 struct msm_dsi_phy *phy = platform_get_drvdata(pdev);
681
682 if (phy && phy->pll) {
Hai Li9d32c4982015-05-15 13:04:05 -0400683 msm_dsi_pll_destroy(phy->pll);
684 phy->pll = NULL;
685 }
Hai Liec31abf2015-05-15 13:04:06 -0400686
687 platform_set_drvdata(pdev, NULL);
688
689 return 0;
690}
691
692static struct platform_driver dsi_phy_platform_driver = {
693 .probe = dsi_phy_driver_probe,
694 .remove = dsi_phy_driver_remove,
695 .driver = {
696 .name = "msm_dsi_phy",
697 .of_match_table = dsi_phy_dt_match,
698 },
699};
700
701void __init msm_dsi_phy_driver_register(void)
702{
703 platform_driver_register(&dsi_phy_platform_driver);
704}
705
706void __exit msm_dsi_phy_driver_unregister(void)
707{
708 platform_driver_unregister(&dsi_phy_platform_driver);
Hai Li9d32c4982015-05-15 13:04:05 -0400709}
710
Hai Li13351cd2015-06-10 13:18:17 -0400711int msm_dsi_phy_enable(struct msm_dsi_phy *phy, int src_pll_id,
Hai Lia6895542015-03-31 14:36:33 -0400712 const unsigned long bit_rate, const unsigned long esc_rate)
713{
Hai Liec31abf2015-05-15 13:04:06 -0400714 int ret;
715
716 if (!phy || !phy->cfg->ops.enable)
Hai Lia6895542015-03-31 14:36:33 -0400717 return -EINVAL;
Hai Liec31abf2015-05-15 13:04:06 -0400718
719 ret = dsi_phy_regulator_enable(phy);
720 if (ret) {
721 dev_err(&phy->pdev->dev, "%s: regulator enable failed, %d\n",
722 __func__, ret);
723 return ret;
724 }
725
Hai Li13351cd2015-06-10 13:18:17 -0400726 return phy->cfg->ops.enable(phy, src_pll_id, bit_rate, esc_rate);
Hai Lia6895542015-03-31 14:36:33 -0400727}
728
Hai Li29e61692015-08-13 17:45:51 -0400729void msm_dsi_phy_disable(struct msm_dsi_phy *phy)
Hai Lia6895542015-03-31 14:36:33 -0400730{
Hai Liec31abf2015-05-15 13:04:06 -0400731 if (!phy || !phy->cfg->ops.disable)
Hai Li29e61692015-08-13 17:45:51 -0400732 return;
Hai Liec31abf2015-05-15 13:04:06 -0400733
734 phy->cfg->ops.disable(phy);
735 dsi_phy_regulator_disable(phy);
Hai Lia6895542015-03-31 14:36:33 -0400736}
737
738void msm_dsi_phy_get_clk_pre_post(struct msm_dsi_phy *phy,
739 u32 *clk_pre, u32 *clk_post)
740{
741 if (!phy)
742 return;
743 if (clk_pre)
744 *clk_pre = phy->timing.clk_pre;
745 if (clk_post)
746 *clk_post = phy->timing.clk_post;
747}
748
Hai Li9d32c4982015-05-15 13:04:05 -0400749struct msm_dsi_pll *msm_dsi_phy_get_pll(struct msm_dsi_phy *phy)
750{
751 if (!phy)
752 return NULL;
753
754 return phy->pll;
755}
756