blob: 2e2d0d81d6437b49f8b683c11de402d9e33c936e [file] [log] [blame]
Ajay Singh Parmar67f31322016-06-22 17:37:56 -07001/*
Sandeep Panda9d6948c2018-02-02 11:17:04 +05302 * Copyright (c) 2016-2018, The Linux Foundation. All rights reserved.
Ajay Singh Parmar67f31322016-06-22 17:37:56 -07003 *
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
14#define pr_fmt(fmt) "msm-dsi-phy:[%s] " fmt, __func__
15
16#include <linux/of_device.h>
17#include <linux/err.h>
18#include <linux/regulator/consumer.h>
19#include <linux/clk.h>
20#include <linux/msm-bus.h>
21#include <linux/list.h>
22
23#include "msm_drv.h"
24#include "msm_kms.h"
25#include "msm_gpu.h"
26#include "dsi_phy.h"
27#include "dsi_phy_hw.h"
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +053028#include "dsi_clk.h"
29#include "dsi_pwr.h"
Ajay Singh Parmar67f31322016-06-22 17:37:56 -070030#include "dsi_catalog.h"
31
Dhaval Patela2430842017-06-15 14:32:36 -070032#include "sde_dbg.h"
33
Ajay Singh Parmar67f31322016-06-22 17:37:56 -070034#define DSI_PHY_DEFAULT_LABEL "MDSS PHY CTRL"
35
Alan Kwong60cc3552017-11-01 22:08:48 -040036#define BITS_PER_BYTE 8
37
Ajay Singh Parmar67f31322016-06-22 17:37:56 -070038struct dsi_phy_list_item {
39 struct msm_dsi_phy *phy;
40 struct list_head list;
41};
42
43static LIST_HEAD(dsi_phy_list);
44static DEFINE_MUTEX(dsi_phy_list_lock);
45
Padmanabhan Komanduru56611ef2016-12-19 12:21:11 +053046static const struct dsi_ver_spec_info dsi_phy_v0_0_hpm = {
47 .version = DSI_PHY_VERSION_0_0_HPM,
48 .lane_cfg_count = 4,
49 .strength_cfg_count = 2,
50 .regulator_cfg_count = 1,
51 .timing_cfg_count = 8,
52};
53static const struct dsi_ver_spec_info dsi_phy_v0_0_lpm = {
54 .version = DSI_PHY_VERSION_0_0_LPM,
55 .lane_cfg_count = 4,
56 .strength_cfg_count = 2,
57 .regulator_cfg_count = 1,
58 .timing_cfg_count = 8,
59};
Ajay Singh Parmar67f31322016-06-22 17:37:56 -070060static const struct dsi_ver_spec_info dsi_phy_v1_0 = {
61 .version = DSI_PHY_VERSION_1_0,
62 .lane_cfg_count = 4,
63 .strength_cfg_count = 2,
64 .regulator_cfg_count = 1,
65 .timing_cfg_count = 8,
66};
67static const struct dsi_ver_spec_info dsi_phy_v2_0 = {
68 .version = DSI_PHY_VERSION_2_0,
69 .lane_cfg_count = 4,
70 .strength_cfg_count = 2,
71 .regulator_cfg_count = 1,
72 .timing_cfg_count = 8,
73};
74static const struct dsi_ver_spec_info dsi_phy_v3_0 = {
75 .version = DSI_PHY_VERSION_3_0,
76 .lane_cfg_count = 4,
77 .strength_cfg_count = 2,
Padmanabhan Komanduru56611ef2016-12-19 12:21:11 +053078 .regulator_cfg_count = 0,
79 .timing_cfg_count = 12,
Ajay Singh Parmar67f31322016-06-22 17:37:56 -070080};
81
82static const struct of_device_id msm_dsi_phy_of_match[] = {
Padmanabhan Komanduru56611ef2016-12-19 12:21:11 +053083 { .compatible = "qcom,dsi-phy-v0.0-hpm",
84 .data = &dsi_phy_v0_0_hpm,},
85 { .compatible = "qcom,dsi-phy-v0.0-lpm",
86 .data = &dsi_phy_v0_0_lpm,},
Ajay Singh Parmar67f31322016-06-22 17:37:56 -070087 { .compatible = "qcom,dsi-phy-v1.0",
88 .data = &dsi_phy_v1_0,},
89 { .compatible = "qcom,dsi-phy-v2.0",
90 .data = &dsi_phy_v2_0,},
91 { .compatible = "qcom,dsi-phy-v3.0",
92 .data = &dsi_phy_v3_0,},
Ajay Singh Parmar67f31322016-06-22 17:37:56 -070093 {}
94};
95
96static int dsi_phy_regmap_init(struct platform_device *pdev,
97 struct msm_dsi_phy *phy)
98{
99 int rc = 0;
100 void __iomem *ptr;
101
102 ptr = msm_ioremap(pdev, "dsi_phy", phy->name);
103 if (IS_ERR(ptr)) {
104 rc = PTR_ERR(ptr);
105 return rc;
106 }
107
108 phy->hw.base = ptr;
109
110 pr_debug("[%s] map dsi_phy registers to %p\n", phy->name, phy->hw.base);
111
112 return rc;
113}
114
115static int dsi_phy_regmap_deinit(struct msm_dsi_phy *phy)
116{
117 pr_debug("[%s] unmap registers\n", phy->name);
118 return 0;
119}
120
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700121static int dsi_phy_supplies_init(struct platform_device *pdev,
122 struct msm_dsi_phy *phy)
123{
124 int rc = 0;
125 int i = 0;
126 struct dsi_regulator_info *regs;
127 struct regulator *vreg = NULL;
128
129 regs = &phy->pwr_info.digital;
130 regs->vregs = devm_kzalloc(&pdev->dev, sizeof(struct dsi_vreg),
131 GFP_KERNEL);
132 if (!regs->vregs)
133 goto error;
134
135 regs->count = 1;
136 snprintf(regs->vregs->vreg_name,
137 ARRAY_SIZE(regs->vregs[i].vreg_name),
138 "%s", "gdsc");
139
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +0530140 rc = dsi_pwr_get_dt_vreg_data(&pdev->dev,
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700141 &phy->pwr_info.phy_pwr,
142 "qcom,phy-supply-entries");
143 if (rc) {
144 pr_err("failed to get host power supplies, rc = %d\n", rc);
145 goto error_digital;
146 }
147
148 regs = &phy->pwr_info.digital;
149 for (i = 0; i < regs->count; i++) {
150 vreg = devm_regulator_get(&pdev->dev, regs->vregs[i].vreg_name);
151 rc = PTR_RET(vreg);
152 if (rc) {
153 pr_err("failed to get %s regulator\n",
154 regs->vregs[i].vreg_name);
155 goto error_host_pwr;
156 }
157 regs->vregs[i].vreg = vreg;
158 }
159
160 regs = &phy->pwr_info.phy_pwr;
161 for (i = 0; i < regs->count; i++) {
162 vreg = devm_regulator_get(&pdev->dev, regs->vregs[i].vreg_name);
163 rc = PTR_RET(vreg);
164 if (rc) {
165 pr_err("failed to get %s regulator\n",
166 regs->vregs[i].vreg_name);
167 for (--i; i >= 0; i--)
168 devm_regulator_put(regs->vregs[i].vreg);
169 goto error_digital_put;
170 }
171 regs->vregs[i].vreg = vreg;
172 }
173
174 return rc;
175
176error_digital_put:
177 regs = &phy->pwr_info.digital;
178 for (i = 0; i < regs->count; i++)
179 devm_regulator_put(regs->vregs[i].vreg);
180error_host_pwr:
181 devm_kfree(&pdev->dev, phy->pwr_info.phy_pwr.vregs);
182 phy->pwr_info.phy_pwr.vregs = NULL;
183 phy->pwr_info.phy_pwr.count = 0;
184error_digital:
185 devm_kfree(&pdev->dev, phy->pwr_info.digital.vregs);
186 phy->pwr_info.digital.vregs = NULL;
187 phy->pwr_info.digital.count = 0;
188error:
189 return rc;
190}
191
192static int dsi_phy_supplies_deinit(struct msm_dsi_phy *phy)
193{
194 int i = 0;
195 int rc = 0;
196 struct dsi_regulator_info *regs;
197
198 regs = &phy->pwr_info.digital;
199 for (i = 0; i < regs->count; i++) {
200 if (!regs->vregs[i].vreg)
201 pr_err("vreg is NULL, should not reach here\n");
202 else
203 devm_regulator_put(regs->vregs[i].vreg);
204 }
205
206 regs = &phy->pwr_info.phy_pwr;
207 for (i = 0; i < regs->count; i++) {
208 if (!regs->vregs[i].vreg)
209 pr_err("vreg is NULL, should not reach here\n");
210 else
211 devm_regulator_put(regs->vregs[i].vreg);
212 }
213
214 if (phy->pwr_info.phy_pwr.vregs) {
215 devm_kfree(&phy->pdev->dev, phy->pwr_info.phy_pwr.vregs);
216 phy->pwr_info.phy_pwr.vregs = NULL;
217 phy->pwr_info.phy_pwr.count = 0;
218 }
219 if (phy->pwr_info.digital.vregs) {
220 devm_kfree(&phy->pdev->dev, phy->pwr_info.digital.vregs);
221 phy->pwr_info.digital.vregs = NULL;
222 phy->pwr_info.digital.count = 0;
223 }
224
225 return rc;
226}
227
228static int dsi_phy_parse_dt_per_lane_cfgs(struct platform_device *pdev,
229 struct dsi_phy_per_lane_cfgs *cfg,
230 char *property)
231{
232 int rc = 0, i = 0, j = 0;
233 const u8 *data;
234 u32 len = 0;
235
236 data = of_get_property(pdev->dev.of_node, property, &len);
237 if (!data) {
238 pr_err("Unable to read Phy %s settings\n", property);
239 return -EINVAL;
240 }
241
242 if (len != DSI_LANE_MAX * cfg->count_per_lane) {
243 pr_err("incorrect phy %s settings, exp=%d, act=%d\n",
244 property, (DSI_LANE_MAX * cfg->count_per_lane), len);
245 return -EINVAL;
246 }
247
248 for (i = DSI_LOGICAL_LANE_0; i < DSI_LANE_MAX; i++) {
249 for (j = 0; j < cfg->count_per_lane; j++) {
250 cfg->lane[i][j] = *data;
251 data++;
252 }
253 }
254
255 return rc;
256}
257
258static int dsi_phy_settings_init(struct platform_device *pdev,
259 struct msm_dsi_phy *phy)
260{
261 int rc = 0;
262 struct dsi_phy_per_lane_cfgs *lane = &phy->cfg.lanecfg;
263 struct dsi_phy_per_lane_cfgs *strength = &phy->cfg.strength;
264 struct dsi_phy_per_lane_cfgs *timing = &phy->cfg.timing;
265 struct dsi_phy_per_lane_cfgs *regs = &phy->cfg.regulators;
266
267 lane->count_per_lane = phy->ver_info->lane_cfg_count;
268 rc = dsi_phy_parse_dt_per_lane_cfgs(pdev, lane,
269 "qcom,platform-lane-config");
270 if (rc) {
271 pr_err("failed to parse lane cfgs, rc=%d\n", rc);
272 goto err;
273 }
274
275 strength->count_per_lane = phy->ver_info->strength_cfg_count;
276 rc = dsi_phy_parse_dt_per_lane_cfgs(pdev, strength,
277 "qcom,platform-strength-ctrl");
278 if (rc) {
279 pr_err("failed to parse lane cfgs, rc=%d\n", rc);
280 goto err;
281 }
282
283 regs->count_per_lane = phy->ver_info->regulator_cfg_count;
Padmanabhan Komanduru56611ef2016-12-19 12:21:11 +0530284 if (regs->count_per_lane > 0) {
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700285 rc = dsi_phy_parse_dt_per_lane_cfgs(pdev, regs,
286 "qcom,platform-regulator-settings");
Padmanabhan Komanduru56611ef2016-12-19 12:21:11 +0530287 if (rc) {
288 pr_err("failed to parse lane cfgs, rc=%d\n", rc);
289 goto err;
290 }
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700291 }
292
293 /* Actual timing values are dependent on panel */
294 timing->count_per_lane = phy->ver_info->timing_cfg_count;
Alan Kwong797e0892017-10-17 09:37:24 -0400295
296 phy->allow_phy_power_off = of_property_read_bool(pdev->dev.of_node,
297 "qcom,panel-allow-phy-poweroff");
298
Alan Kwong60cc3552017-11-01 22:08:48 -0400299 of_property_read_u32(pdev->dev.of_node,
300 "qcom,dsi-phy-regulator-min-datarate-bps",
301 &phy->regulator_min_datarate_bps);
302
Padmanabhan Komanduru56611ef2016-12-19 12:21:11 +0530303 return 0;
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700304err:
305 lane->count_per_lane = 0;
306 strength->count_per_lane = 0;
307 regs->count_per_lane = 0;
308 timing->count_per_lane = 0;
309 return rc;
310}
311
312static int dsi_phy_settings_deinit(struct msm_dsi_phy *phy)
313{
314 memset(&phy->cfg.lanecfg, 0x0, sizeof(phy->cfg.lanecfg));
315 memset(&phy->cfg.strength, 0x0, sizeof(phy->cfg.strength));
316 memset(&phy->cfg.timing, 0x0, sizeof(phy->cfg.timing));
317 memset(&phy->cfg.regulators, 0x0, sizeof(phy->cfg.regulators));
318 return 0;
319}
320
321static int dsi_phy_driver_probe(struct platform_device *pdev)
322{
323 struct msm_dsi_phy *dsi_phy;
324 struct dsi_phy_list_item *item;
325 const struct of_device_id *id;
326 const struct dsi_ver_spec_info *ver_info;
327 int rc = 0;
328 u32 index = 0;
329
330 if (!pdev || !pdev->dev.of_node) {
331 pr_err("pdev not found\n");
332 return -ENODEV;
333 }
334
335 id = of_match_node(msm_dsi_phy_of_match, pdev->dev.of_node);
336 if (!id)
337 return -ENODEV;
338
339 ver_info = id->data;
340
341 item = devm_kzalloc(&pdev->dev, sizeof(*item), GFP_KERNEL);
342 if (!item)
343 return -ENOMEM;
344
345
346 dsi_phy = devm_kzalloc(&pdev->dev, sizeof(*dsi_phy), GFP_KERNEL);
347 if (!dsi_phy) {
348 devm_kfree(&pdev->dev, item);
349 return -ENOMEM;
350 }
351
352 rc = of_property_read_u32(pdev->dev.of_node, "cell-index", &index);
353 if (rc) {
354 pr_debug("cell index not set, default to 0\n");
355 index = 0;
356 }
357
358 dsi_phy->index = index;
359
360 dsi_phy->name = of_get_property(pdev->dev.of_node, "label", NULL);
361 if (!dsi_phy->name)
362 dsi_phy->name = DSI_PHY_DEFAULT_LABEL;
363
364 pr_debug("Probing %s device\n", dsi_phy->name);
365
366 rc = dsi_phy_regmap_init(pdev, dsi_phy);
367 if (rc) {
368 pr_err("Failed to parse register information, rc=%d\n", rc);
369 goto fail;
370 }
371
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700372 rc = dsi_phy_supplies_init(pdev, dsi_phy);
373 if (rc) {
374 pr_err("failed to parse voltage supplies, rc = %d\n", rc);
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +0530375 goto fail_regmap;
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700376 }
377
378 rc = dsi_catalog_phy_setup(&dsi_phy->hw, ver_info->version,
379 dsi_phy->index);
380 if (rc) {
381 pr_err("Catalog does not support version (%d)\n",
382 ver_info->version);
383 goto fail_supplies;
384 }
385
386 dsi_phy->ver_info = ver_info;
387 rc = dsi_phy_settings_init(pdev, dsi_phy);
388 if (rc) {
389 pr_err("Failed to parse phy setting, rc=%d\n", rc);
390 goto fail_supplies;
391 }
392
393 item->phy = dsi_phy;
394
395 mutex_lock(&dsi_phy_list_lock);
396 list_add(&item->list, &dsi_phy_list);
397 mutex_unlock(&dsi_phy_list_lock);
398
399 mutex_init(&dsi_phy->phy_lock);
400 /** TODO: initialize debugfs */
401 dsi_phy->pdev = pdev;
402 platform_set_drvdata(pdev, dsi_phy);
Shashank Babu Chinta Venkata2f24e982017-04-21 14:57:53 -0700403 pr_info("Probe successful for %s\n", dsi_phy->name);
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700404 return 0;
405
406fail_supplies:
407 (void)dsi_phy_supplies_deinit(dsi_phy);
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700408fail_regmap:
409 (void)dsi_phy_regmap_deinit(dsi_phy);
410fail:
411 devm_kfree(&pdev->dev, dsi_phy);
412 devm_kfree(&pdev->dev, item);
413 return rc;
414}
415
416static int dsi_phy_driver_remove(struct platform_device *pdev)
417{
418 int rc = 0;
419 struct msm_dsi_phy *phy = platform_get_drvdata(pdev);
420 struct list_head *pos, *tmp;
421
422 if (!pdev || !phy) {
423 pr_err("Invalid device\n");
424 return -EINVAL;
425 }
426
427 mutex_lock(&dsi_phy_list_lock);
428 list_for_each_safe(pos, tmp, &dsi_phy_list) {
429 struct dsi_phy_list_item *n;
430
431 n = list_entry(pos, struct dsi_phy_list_item, list);
432 if (n->phy == phy) {
433 list_del(&n->list);
434 devm_kfree(&pdev->dev, n);
435 break;
436 }
437 }
438 mutex_unlock(&dsi_phy_list_lock);
439
440 mutex_lock(&phy->phy_lock);
441 rc = dsi_phy_settings_deinit(phy);
442 if (rc)
443 pr_err("failed to deinitialize phy settings, rc=%d\n", rc);
444
445 rc = dsi_phy_supplies_deinit(phy);
446 if (rc)
447 pr_err("failed to deinitialize voltage supplies, rc=%d\n", rc);
448
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700449 rc = dsi_phy_regmap_deinit(phy);
450 if (rc)
451 pr_err("failed to deinitialize regmap, rc=%d\n", rc);
452 mutex_unlock(&phy->phy_lock);
453
454 mutex_destroy(&phy->phy_lock);
455 devm_kfree(&pdev->dev, phy);
456
457 platform_set_drvdata(pdev, NULL);
458
459 return 0;
460}
461
462static struct platform_driver dsi_phy_platform_driver = {
463 .probe = dsi_phy_driver_probe,
464 .remove = dsi_phy_driver_remove,
465 .driver = {
Ajay Singh Parmar64c19192016-06-10 16:44:56 -0700466 .name = "dsi_phy",
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700467 .of_match_table = msm_dsi_phy_of_match,
468 },
469};
470
471static void dsi_phy_enable_hw(struct msm_dsi_phy *phy)
472{
473 if (phy->hw.ops.regulator_enable)
474 phy->hw.ops.regulator_enable(&phy->hw, &phy->cfg.regulators);
475
476 if (phy->hw.ops.enable)
477 phy->hw.ops.enable(&phy->hw, &phy->cfg);
478}
479
480static void dsi_phy_disable_hw(struct msm_dsi_phy *phy)
481{
482 if (phy->hw.ops.disable)
Padmanabhan Komanduru56611ef2016-12-19 12:21:11 +0530483 phy->hw.ops.disable(&phy->hw, &phy->cfg);
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700484
485 if (phy->hw.ops.regulator_disable)
486 phy->hw.ops.regulator_disable(&phy->hw);
487}
488
489/**
490 * dsi_phy_get() - get a dsi phy handle from device node
491 * @of_node: device node for dsi phy controller
492 *
493 * Gets the DSI PHY handle for the corresponding of_node. The ref count is
494 * incremented to one all subsequents get will fail until the original client
495 * calls a put.
496 *
497 * Return: DSI PHY handle or an error code.
498 */
499struct msm_dsi_phy *dsi_phy_get(struct device_node *of_node)
500{
501 struct list_head *pos, *tmp;
502 struct msm_dsi_phy *phy = NULL;
503
504 mutex_lock(&dsi_phy_list_lock);
505 list_for_each_safe(pos, tmp, &dsi_phy_list) {
506 struct dsi_phy_list_item *n;
507
508 n = list_entry(pos, struct dsi_phy_list_item, list);
509 if (n->phy->pdev->dev.of_node == of_node) {
510 phy = n->phy;
511 break;
512 }
513 }
514 mutex_unlock(&dsi_phy_list_lock);
515
516 if (!phy) {
517 pr_err("Device with of node not found\n");
518 phy = ERR_PTR(-EPROBE_DEFER);
519 return phy;
520 }
521
522 mutex_lock(&phy->phy_lock);
523 if (phy->refcount > 0) {
524 pr_err("[PHY_%d] Device under use\n", phy->index);
525 phy = ERR_PTR(-EINVAL);
526 } else {
527 phy->refcount++;
528 }
529 mutex_unlock(&phy->phy_lock);
530 return phy;
531}
532
533/**
534 * dsi_phy_put() - release dsi phy handle
535 * @dsi_phy: DSI PHY handle.
536 *
537 * Release the DSI PHY hardware. Driver will clean up all resources and puts
538 * back the DSI PHY into reset state.
539 */
540void dsi_phy_put(struct msm_dsi_phy *dsi_phy)
541{
542 mutex_lock(&dsi_phy->phy_lock);
543
544 if (dsi_phy->refcount == 0)
545 pr_err("Unbalanced dsi_phy_put call\n");
546 else
547 dsi_phy->refcount--;
548
549 mutex_unlock(&dsi_phy->phy_lock);
550}
551
552/**
553 * dsi_phy_drv_init() - initialize dsi phy driver
554 * @dsi_phy: DSI PHY handle.
555 *
556 * Initializes DSI PHY driver. Should be called after dsi_phy_get().
557 *
558 * Return: error code.
559 */
560int dsi_phy_drv_init(struct msm_dsi_phy *dsi_phy)
561{
Dhaval Patela2430842017-06-15 14:32:36 -0700562 char dbg_name[DSI_DEBUG_NAME_LEN];
563
564 snprintf(dbg_name, DSI_DEBUG_NAME_LEN, "dsi%d_phy", dsi_phy->index);
565 sde_dbg_reg_register_base(dbg_name, dsi_phy->hw.base,
566 msm_iomap_size(dsi_phy->pdev, "dsi_phy"));
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700567 return 0;
568}
569
570/**
571 * dsi_phy_drv_deinit() - de-initialize dsi phy driver
572 * @dsi_phy: DSI PHY handle.
573 *
574 * Release all resources acquired by dsi_phy_drv_init().
575 *
576 * Return: error code.
577 */
578int dsi_phy_drv_deinit(struct msm_dsi_phy *dsi_phy)
579{
580 return 0;
581}
582
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +0530583int dsi_phy_clk_cb_register(struct msm_dsi_phy *dsi_phy,
584 struct clk_ctrl_cb *clk_cb)
585{
586 if (!dsi_phy || !clk_cb) {
587 pr_err("Invalid params\n");
588 return -EINVAL;
589 }
590
591 dsi_phy->clk_cb.priv = clk_cb->priv;
592 dsi_phy->clk_cb.dsi_clk_cb = clk_cb->dsi_clk_cb;
593 return 0;
594}
595
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700596/**
597 * dsi_phy_validate_mode() - validate a display mode
598 * @dsi_phy: DSI PHY handle.
599 * @mode: Mode information.
600 *
601 * Validation will fail if the mode cannot be supported by the PHY driver or
602 * hardware.
603 *
604 * Return: error code.
605 */
606int dsi_phy_validate_mode(struct msm_dsi_phy *dsi_phy,
607 struct dsi_mode_info *mode)
608{
609 int rc = 0;
610
611 if (!dsi_phy || !mode) {
612 pr_err("Invalid params\n");
613 return -EINVAL;
614 }
615
616 mutex_lock(&dsi_phy->phy_lock);
617
618 pr_debug("[PHY_%d] Skipping validation\n", dsi_phy->index);
619
620 mutex_unlock(&dsi_phy->phy_lock);
621 return rc;
622}
623
624/**
625 * dsi_phy_set_power_state() - enable/disable dsi phy power supplies
626 * @dsi_phy: DSI PHY handle.
627 * @enable: Boolean flag to enable/disable.
628 *
629 * Return: error code.
630 */
631int dsi_phy_set_power_state(struct msm_dsi_phy *dsi_phy, bool enable)
632{
633 int rc = 0;
634
635 if (!dsi_phy) {
636 pr_err("Invalid params\n");
637 return -EINVAL;
638 }
639
640 mutex_lock(&dsi_phy->phy_lock);
641
642 if (enable == dsi_phy->power_state) {
643 pr_err("[PHY_%d] No state change\n", dsi_phy->index);
644 goto error;
645 }
646
647 if (enable) {
648 rc = dsi_pwr_enable_regulator(&dsi_phy->pwr_info.digital, true);
649 if (rc) {
650 pr_err("failed to enable digital regulator\n");
651 goto error;
652 }
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +0530653
Alan Kwong60cc3552017-11-01 22:08:48 -0400654 if (dsi_phy->dsi_phy_state == DSI_PHY_ENGINE_OFF &&
655 dsi_phy->regulator_required) {
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +0530656 rc = dsi_pwr_enable_regulator(
657 &dsi_phy->pwr_info.phy_pwr, true);
658 if (rc) {
659 pr_err("failed to enable phy power\n");
660 (void)dsi_pwr_enable_regulator(
661 &dsi_phy->pwr_info.digital, false);
662 goto error;
663 }
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700664 }
665 } else {
Vara Reddyeda08c02017-12-08 17:54:10 -0800666 if (dsi_phy->dsi_phy_state == DSI_PHY_ENGINE_OFF &&
Alan Kwong60cc3552017-11-01 22:08:48 -0400667 dsi_phy->regulator_required) {
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +0530668 rc = dsi_pwr_enable_regulator(
669 &dsi_phy->pwr_info.phy_pwr, false);
670 if (rc) {
671 pr_err("failed to enable digital regulator\n");
672 goto error;
673 }
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700674 }
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +0530675
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700676 rc = dsi_pwr_enable_regulator(&dsi_phy->pwr_info.digital,
677 false);
678 if (rc) {
679 pr_err("failed to enable phy power\n");
680 goto error;
681 }
682 }
683
684 dsi_phy->power_state = enable;
685error:
686 mutex_unlock(&dsi_phy->phy_lock);
687 return rc;
688}
689
Padmanabhan Komanduru56611ef2016-12-19 12:21:11 +0530690static int dsi_phy_enable_ulps(struct msm_dsi_phy *phy,
Veera Sundaram Sankaranbb3680f2017-04-21 13:20:46 -0700691 struct dsi_host_config *config, bool clamp_enabled)
Padmanabhan Komanduru56611ef2016-12-19 12:21:11 +0530692{
693 int rc = 0;
694 u32 lanes = 0;
695 u32 ulps_lanes;
696
Sandeep Panda9d6948c2018-02-02 11:17:04 +0530697 lanes = config->common_config.data_lanes;
Padmanabhan Komanduru56611ef2016-12-19 12:21:11 +0530698 lanes |= DSI_CLOCK_LANE;
699
Veera Sundaram Sankaranbb3680f2017-04-21 13:20:46 -0700700 /*
701 * If DSI clamps are enabled, it means that the DSI lanes are
702 * already in idle state. Checking for lanes to be in idle state
703 * should be skipped during ULPS entry programming while coming
704 * out of idle screen.
705 */
706 if (!clamp_enabled) {
707 rc = phy->hw.ops.ulps_ops.wait_for_lane_idle(&phy->hw, lanes);
708 if (rc) {
709 pr_err("lanes not entering idle, skip ULPS\n");
710 return rc;
711 }
Padmanabhan Komanduru56611ef2016-12-19 12:21:11 +0530712 }
713
714 phy->hw.ops.ulps_ops.ulps_request(&phy->hw, &phy->cfg, lanes);
715
716 ulps_lanes = phy->hw.ops.ulps_ops.get_lanes_in_ulps(&phy->hw);
717
Veera Sundaram Sankaranbb3680f2017-04-21 13:20:46 -0700718 if (!phy->hw.ops.ulps_ops.is_lanes_in_ulps(lanes, ulps_lanes)) {
Padmanabhan Komanduru56611ef2016-12-19 12:21:11 +0530719 pr_err("Failed to enter ULPS, request=0x%x, actual=0x%x\n",
720 lanes, ulps_lanes);
721 rc = -EIO;
722 }
723
724 return rc;
725}
726
727static int dsi_phy_disable_ulps(struct msm_dsi_phy *phy,
728 struct dsi_host_config *config)
729{
Padmanabhan Komanduru56611ef2016-12-19 12:21:11 +0530730 u32 ulps_lanes, lanes = 0;
731
Sandeep Panda9d6948c2018-02-02 11:17:04 +0530732 lanes = config->common_config.data_lanes;
Padmanabhan Komanduru56611ef2016-12-19 12:21:11 +0530733 lanes |= DSI_CLOCK_LANE;
734
735 ulps_lanes = phy->hw.ops.ulps_ops.get_lanes_in_ulps(&phy->hw);
736
Veera Sundaram Sankaranbb3680f2017-04-21 13:20:46 -0700737 if (!phy->hw.ops.ulps_ops.is_lanes_in_ulps(lanes, ulps_lanes)) {
738 pr_err("Mismatch in ULPS: lanes:%d, ulps_lanes:%d\n",
739 lanes, ulps_lanes);
740 return -EIO;
741 }
Padmanabhan Komanduru56611ef2016-12-19 12:21:11 +0530742
743 phy->hw.ops.ulps_ops.ulps_exit(&phy->hw, &phy->cfg, lanes);
744
745 ulps_lanes = phy->hw.ops.ulps_ops.get_lanes_in_ulps(&phy->hw);
Veera Sundaram Sankaranbb3680f2017-04-21 13:20:46 -0700746
747 if (phy->hw.ops.ulps_ops.is_lanes_in_ulps(lanes, ulps_lanes)) {
Padmanabhan Komanduru56611ef2016-12-19 12:21:11 +0530748 pr_err("Lanes (0x%x) stuck in ULPS\n", ulps_lanes);
Veera Sundaram Sankaranbb3680f2017-04-21 13:20:46 -0700749 return -EIO;
Padmanabhan Komanduru56611ef2016-12-19 12:21:11 +0530750 }
751
Veera Sundaram Sankaranbb3680f2017-04-21 13:20:46 -0700752 return 0;
Padmanabhan Komanduru56611ef2016-12-19 12:21:11 +0530753}
754
Aravind Venkateswaranb3fc3a02018-03-05 16:09:05 -0800755void dsi_phy_toggle_resync_fifo(struct msm_dsi_phy *phy)
756{
757 if (!phy)
758 return;
759
760 if (!phy->hw.ops.toggle_resync_fifo)
761 return;
762
763 phy->hw.ops.toggle_resync_fifo(&phy->hw);
764}
Padmanabhan Komanduru56611ef2016-12-19 12:21:11 +0530765
766int dsi_phy_set_ulps(struct msm_dsi_phy *phy, struct dsi_host_config *config,
Veera Sundaram Sankaranbb3680f2017-04-21 13:20:46 -0700767 bool enable, bool clamp_enabled)
Padmanabhan Komanduru56611ef2016-12-19 12:21:11 +0530768{
769 int rc = 0;
770
771 if (!phy) {
772 pr_err("Invalid params\n");
773 return -EINVAL;
774 }
775
776 if (!phy->hw.ops.ulps_ops.ulps_request ||
Veera Sundaram Sankaranbb3680f2017-04-21 13:20:46 -0700777 !phy->hw.ops.ulps_ops.ulps_exit ||
778 !phy->hw.ops.ulps_ops.get_lanes_in_ulps ||
779 !phy->hw.ops.ulps_ops.is_lanes_in_ulps ||
780 !phy->hw.ops.ulps_ops.wait_for_lane_idle) {
Padmanabhan Komanduru56611ef2016-12-19 12:21:11 +0530781 pr_debug("DSI PHY ULPS ops not present\n");
782 return 0;
783 }
784
785 mutex_lock(&phy->phy_lock);
786
787 if (enable)
Veera Sundaram Sankaranbb3680f2017-04-21 13:20:46 -0700788 rc = dsi_phy_enable_ulps(phy, config, clamp_enabled);
Padmanabhan Komanduru56611ef2016-12-19 12:21:11 +0530789 else
790 rc = dsi_phy_disable_ulps(phy, config);
791
792 if (rc) {
793 pr_err("[DSI_PHY%d] Ulps state change(%d) failed, rc=%d\n",
794 phy->index, enable, rc);
795 goto error;
796 }
797 pr_debug("[DSI_PHY%d] ULPS state = %d\n", phy->index, enable);
798
799error:
800 mutex_unlock(&phy->phy_lock);
801 return rc;
802}
803
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700804/**
805 * dsi_phy_enable() - enable DSI PHY hardware
806 * @dsi_phy: DSI PHY handle.
807 * @config: DSI host configuration.
808 * @pll_source: Source PLL for PHY clock.
809 * @skip_validation: Validation will not be performed on parameters.
Shashank Babu Chinta Venkata7d608732017-05-31 14:10:26 -0700810 * @is_cont_splash_enabled: check whether continuous splash enabled.
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700811 *
812 * Validates and enables DSI PHY.
813 *
814 * Return: error code.
815 */
816int dsi_phy_enable(struct msm_dsi_phy *phy,
817 struct dsi_host_config *config,
818 enum dsi_phy_pll_source pll_source,
Shashank Babu Chinta Venkata7d608732017-05-31 14:10:26 -0700819 bool skip_validation,
820 bool is_cont_splash_enabled)
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700821{
822 int rc = 0;
823
824 if (!phy || !config) {
825 pr_err("Invalid params\n");
826 return -EINVAL;
827 }
828
829 mutex_lock(&phy->phy_lock);
830
831 if (!skip_validation)
832 pr_debug("[PHY_%d] TODO: perform validation\n", phy->index);
833
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700834 memcpy(&phy->mode, &config->video_timing, sizeof(phy->mode));
Padmanabhan Komanduru8ee8ee52016-12-19 12:10:51 +0530835 memcpy(&phy->cfg.lane_map, &config->lane_map, sizeof(config->lane_map));
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700836 phy->data_lanes = config->common_config.data_lanes;
837 phy->dst_format = config->common_config.dst_format;
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700838 phy->cfg.pll_source = pll_source;
839
Padmanabhan Komanduruee89d212016-12-19 12:51:31 +0530840 /**
841 * If PHY timing parameters are not present in panel dtsi file,
842 * then calculate them in the driver
843 */
844 if (!phy->cfg.is_phy_timing_present)
845 rc = phy->hw.ops.calculate_timing_params(&phy->hw,
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700846 &phy->mode,
847 &config->common_config,
848 &phy->cfg.timing);
849 if (rc) {
850 pr_err("[%s] failed to set timing, rc=%d\n", phy->name, rc);
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +0530851 goto error;
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700852 }
853
Shashank Babu Chinta Venkata7d608732017-05-31 14:10:26 -0700854 if (!is_cont_splash_enabled) {
855 dsi_phy_enable_hw(phy);
856 pr_debug("cont splash not enabled, phy enable required\n");
857 }
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +0530858 phy->dsi_phy_state = DSI_PHY_ENGINE_ON;
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700859
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700860error:
861 mutex_unlock(&phy->phy_lock);
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +0530862
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700863 return rc;
864}
865
Sandeep Panda11b20d82017-06-19 12:57:27 +0530866int dsi_phy_lane_reset(struct msm_dsi_phy *phy)
867{
868 int ret = 0;
869
870 if (!phy)
871 return ret;
872
873 mutex_lock(&phy->phy_lock);
874 if (phy->hw.ops.phy_lane_reset)
875 ret = phy->hw.ops.phy_lane_reset(&phy->hw);
876 mutex_unlock(&phy->phy_lock);
877
878 return ret;
879}
880
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700881/**
882 * dsi_phy_disable() - disable DSI PHY hardware.
883 * @phy: DSI PHY handle.
884 *
885 * Return: error code.
886 */
887int dsi_phy_disable(struct msm_dsi_phy *phy)
888{
889 int rc = 0;
890
891 if (!phy) {
892 pr_err("Invalid params\n");
893 return -EINVAL;
894 }
895
896 mutex_lock(&phy->phy_lock);
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700897 dsi_phy_disable_hw(phy);
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +0530898 phy->dsi_phy_state = DSI_PHY_ENGINE_OFF;
899 mutex_unlock(&phy->phy_lock);
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700900
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +0530901 return rc;
902}
903
904/**
Aravind Venkateswaran1769bed2018-05-14 17:15:17 -0700905 * dsi_phy_set_clamp_state() - configure clamps for DSI lanes
906 * @phy: DSI PHY handle.
907 * @enable: boolean to specify clamp enable/disable.
908 *
909 * Return: error code.
910 */
911int dsi_phy_set_clamp_state(struct msm_dsi_phy *phy, bool enable)
912{
913 if (!phy)
914 return -EINVAL;
915
916 pr_debug("[%s] enable=%d\n", phy->name, enable);
917
918 if (phy->hw.ops.clamp_ctrl)
919 phy->hw.ops.clamp_ctrl(&phy->hw, enable);
920
921 return 0;
922}
923
924/**
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +0530925 * dsi_phy_idle_ctrl() - enable/disable DSI PHY during idle screen
926 * @phy: DSI PHY handle
927 * @enable: boolean to specify PHY enable/disable.
928 *
929 * Return: error code.
930 */
931
932int dsi_phy_idle_ctrl(struct msm_dsi_phy *phy, bool enable)
933{
934 if (!phy) {
935 pr_err("Invalid params\n");
936 return -EINVAL;
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700937 }
938
Alan Kwong797e0892017-10-17 09:37:24 -0400939 pr_debug("[%s] enable=%d\n", phy->name, enable);
940
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +0530941 mutex_lock(&phy->phy_lock);
942 if (enable) {
943 if (phy->hw.ops.phy_idle_on)
944 phy->hw.ops.phy_idle_on(&phy->hw, &phy->cfg);
945
946 if (phy->hw.ops.regulator_enable)
947 phy->hw.ops.regulator_enable(&phy->hw,
948 &phy->cfg.regulators);
Alan Kwong797e0892017-10-17 09:37:24 -0400949
950 if (phy->hw.ops.enable)
951 phy->hw.ops.enable(&phy->hw, &phy->cfg);
952
953 phy->dsi_phy_state = DSI_PHY_ENGINE_ON;
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +0530954 } else {
Alan Kwong797e0892017-10-17 09:37:24 -0400955 phy->dsi_phy_state = DSI_PHY_ENGINE_OFF;
956
957 if (phy->hw.ops.disable)
958 phy->hw.ops.disable(&phy->hw, &phy->cfg);
959
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +0530960 if (phy->hw.ops.phy_idle_off)
961 phy->hw.ops.phy_idle_off(&phy->hw);
962 }
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700963 mutex_unlock(&phy->phy_lock);
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +0530964
965 return 0;
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700966}
967
968/**
Alan Kwong60cc3552017-11-01 22:08:48 -0400969 * dsi_phy_set_clk_freq() - set DSI PHY clock frequency setting
970 * @phy: DSI PHY handle
971 * @clk_freq: link clock frequency
972 *
973 * Return: error code.
974 */
975int dsi_phy_set_clk_freq(struct msm_dsi_phy *phy,
976 struct link_clk_freq *clk_freq)
977{
978 if (!phy || !clk_freq) {
979 pr_err("Invalid params\n");
980 return -EINVAL;
981 }
982
983 phy->regulator_required = clk_freq->byte_clk_rate >
984 (phy->regulator_min_datarate_bps / BITS_PER_BYTE);
985
Vara Reddy9cc3f932017-11-22 13:26:31 -0800986 /*
987 * DSI PLL needs 0p9 LDO1A for Powering DSI PLL block.
988 * PLL driver can vote for this regulator in PLL driver file, but for
989 * the usecase where we come out of idle(static screen), if PLL and
990 * PHY vote for regulator ,there will be performance delays as both
991 * votes go through RPM to enable regulators.
992 */
993 phy->regulator_required = true;
Alan Kwong60cc3552017-11-01 22:08:48 -0400994 pr_debug("[%s] lane_datarate=%u min_datarate=%u required=%d\n",
995 phy->name,
996 clk_freq->byte_clk_rate * BITS_PER_BYTE,
997 phy->regulator_min_datarate_bps,
998 phy->regulator_required);
999
1000 return 0;
1001}
1002
1003/**
Ajay Singh Parmar67f31322016-06-22 17:37:56 -07001004 * dsi_phy_set_timing_params() - timing parameters for the panel
1005 * @phy: DSI PHY handle
1006 * @timing: array holding timing params.
1007 * @size: size of the array.
1008 *
1009 * When PHY timing calculator is not implemented, this array will be used to
1010 * pass PHY timing information.
1011 *
1012 * Return: error code.
1013 */
1014int dsi_phy_set_timing_params(struct msm_dsi_phy *phy,
Padmanabhan Komanduruee89d212016-12-19 12:51:31 +05301015 u32 *timing, u32 size)
Ajay Singh Parmar67f31322016-06-22 17:37:56 -07001016{
1017 int rc = 0;
Ajay Singh Parmar67f31322016-06-22 17:37:56 -07001018
1019 if (!phy || !timing || !size) {
1020 pr_err("Invalid params\n");
1021 return -EINVAL;
1022 }
1023
1024 mutex_lock(&phy->phy_lock);
1025
Padmanabhan Komanduruee89d212016-12-19 12:51:31 +05301026 if (phy->hw.ops.phy_timing_val)
1027 rc = phy->hw.ops.phy_timing_val(&phy->cfg.timing, timing, size);
1028 if (!rc)
1029 phy->cfg.is_phy_timing_present = true;
Ajay Singh Parmar67f31322016-06-22 17:37:56 -07001030 mutex_unlock(&phy->phy_lock);
1031 return rc;
1032}
1033
Ajay Singh Parmar64c19192016-06-10 16:44:56 -07001034void dsi_phy_drv_register(void)
Ajay Singh Parmar67f31322016-06-22 17:37:56 -07001035{
1036 platform_driver_register(&dsi_phy_platform_driver);
1037}
1038
Ajay Singh Parmar64c19192016-06-10 16:44:56 -07001039void dsi_phy_drv_unregister(void)
Ajay Singh Parmar67f31322016-06-22 17:37:56 -07001040{
1041 platform_driver_unregister(&dsi_phy_platform_driver);
1042}