blob: 2567f04f173912951249bdbbc21354a25e3c4ab0 [file] [log] [blame]
Ajay Singh Parmar67f31322016-06-22 17:37:56 -07001/*
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +05302 * Copyright (c) 2016-2017, 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 Reddy9cc3f932017-11-22 13:26:31 -0800666 if (dsi_phy->dsi_phy_state == DSI_PHY_ENGINE_ON &&
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
697 if (config->panel_mode == DSI_OP_CMD_MODE)
698 lanes = config->common_config.data_lanes;
699 lanes |= DSI_CLOCK_LANE;
700
Veera Sundaram Sankaranbb3680f2017-04-21 13:20:46 -0700701 /*
702 * If DSI clamps are enabled, it means that the DSI lanes are
703 * already in idle state. Checking for lanes to be in idle state
704 * should be skipped during ULPS entry programming while coming
705 * out of idle screen.
706 */
707 if (!clamp_enabled) {
708 rc = phy->hw.ops.ulps_ops.wait_for_lane_idle(&phy->hw, lanes);
709 if (rc) {
710 pr_err("lanes not entering idle, skip ULPS\n");
711 return rc;
712 }
Padmanabhan Komanduru56611ef2016-12-19 12:21:11 +0530713 }
714
715 phy->hw.ops.ulps_ops.ulps_request(&phy->hw, &phy->cfg, lanes);
716
717 ulps_lanes = phy->hw.ops.ulps_ops.get_lanes_in_ulps(&phy->hw);
718
Veera Sundaram Sankaranbb3680f2017-04-21 13:20:46 -0700719 if (!phy->hw.ops.ulps_ops.is_lanes_in_ulps(lanes, ulps_lanes)) {
Padmanabhan Komanduru56611ef2016-12-19 12:21:11 +0530720 pr_err("Failed to enter ULPS, request=0x%x, actual=0x%x\n",
721 lanes, ulps_lanes);
722 rc = -EIO;
723 }
724
725 return rc;
726}
727
728static int dsi_phy_disable_ulps(struct msm_dsi_phy *phy,
729 struct dsi_host_config *config)
730{
Padmanabhan Komanduru56611ef2016-12-19 12:21:11 +0530731 u32 ulps_lanes, lanes = 0;
732
733 if (config->panel_mode == DSI_OP_CMD_MODE)
734 lanes = config->common_config.data_lanes;
735 lanes |= DSI_CLOCK_LANE;
736
737 ulps_lanes = phy->hw.ops.ulps_ops.get_lanes_in_ulps(&phy->hw);
738
Veera Sundaram Sankaranbb3680f2017-04-21 13:20:46 -0700739 if (!phy->hw.ops.ulps_ops.is_lanes_in_ulps(lanes, ulps_lanes)) {
740 pr_err("Mismatch in ULPS: lanes:%d, ulps_lanes:%d\n",
741 lanes, ulps_lanes);
742 return -EIO;
743 }
Padmanabhan Komanduru56611ef2016-12-19 12:21:11 +0530744
745 phy->hw.ops.ulps_ops.ulps_exit(&phy->hw, &phy->cfg, lanes);
746
747 ulps_lanes = phy->hw.ops.ulps_ops.get_lanes_in_ulps(&phy->hw);
Veera Sundaram Sankaranbb3680f2017-04-21 13:20:46 -0700748
749 if (phy->hw.ops.ulps_ops.is_lanes_in_ulps(lanes, ulps_lanes)) {
Padmanabhan Komanduru56611ef2016-12-19 12:21:11 +0530750 pr_err("Lanes (0x%x) stuck in ULPS\n", ulps_lanes);
Veera Sundaram Sankaranbb3680f2017-04-21 13:20:46 -0700751 return -EIO;
Padmanabhan Komanduru56611ef2016-12-19 12:21:11 +0530752 }
753
Veera Sundaram Sankaranbb3680f2017-04-21 13:20:46 -0700754 return 0;
Padmanabhan Komanduru56611ef2016-12-19 12:21:11 +0530755}
756
757
758int dsi_phy_set_ulps(struct msm_dsi_phy *phy, struct dsi_host_config *config,
Veera Sundaram Sankaranbb3680f2017-04-21 13:20:46 -0700759 bool enable, bool clamp_enabled)
Padmanabhan Komanduru56611ef2016-12-19 12:21:11 +0530760{
761 int rc = 0;
762
763 if (!phy) {
764 pr_err("Invalid params\n");
765 return -EINVAL;
766 }
767
768 if (!phy->hw.ops.ulps_ops.ulps_request ||
Veera Sundaram Sankaranbb3680f2017-04-21 13:20:46 -0700769 !phy->hw.ops.ulps_ops.ulps_exit ||
770 !phy->hw.ops.ulps_ops.get_lanes_in_ulps ||
771 !phy->hw.ops.ulps_ops.is_lanes_in_ulps ||
772 !phy->hw.ops.ulps_ops.wait_for_lane_idle) {
Padmanabhan Komanduru56611ef2016-12-19 12:21:11 +0530773 pr_debug("DSI PHY ULPS ops not present\n");
774 return 0;
775 }
776
777 mutex_lock(&phy->phy_lock);
778
779 if (enable)
Veera Sundaram Sankaranbb3680f2017-04-21 13:20:46 -0700780 rc = dsi_phy_enable_ulps(phy, config, clamp_enabled);
Padmanabhan Komanduru56611ef2016-12-19 12:21:11 +0530781 else
782 rc = dsi_phy_disable_ulps(phy, config);
783
784 if (rc) {
785 pr_err("[DSI_PHY%d] Ulps state change(%d) failed, rc=%d\n",
786 phy->index, enable, rc);
787 goto error;
788 }
789 pr_debug("[DSI_PHY%d] ULPS state = %d\n", phy->index, enable);
790
791error:
792 mutex_unlock(&phy->phy_lock);
793 return rc;
794}
795
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700796/**
797 * dsi_phy_enable() - enable DSI PHY hardware
798 * @dsi_phy: DSI PHY handle.
799 * @config: DSI host configuration.
800 * @pll_source: Source PLL for PHY clock.
801 * @skip_validation: Validation will not be performed on parameters.
Shashank Babu Chinta Venkata7d608732017-05-31 14:10:26 -0700802 * @is_cont_splash_enabled: check whether continuous splash enabled.
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700803 *
804 * Validates and enables DSI PHY.
805 *
806 * Return: error code.
807 */
808int dsi_phy_enable(struct msm_dsi_phy *phy,
809 struct dsi_host_config *config,
810 enum dsi_phy_pll_source pll_source,
Shashank Babu Chinta Venkata7d608732017-05-31 14:10:26 -0700811 bool skip_validation,
812 bool is_cont_splash_enabled)
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700813{
814 int rc = 0;
815
816 if (!phy || !config) {
817 pr_err("Invalid params\n");
818 return -EINVAL;
819 }
820
821 mutex_lock(&phy->phy_lock);
822
823 if (!skip_validation)
824 pr_debug("[PHY_%d] TODO: perform validation\n", phy->index);
825
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700826 memcpy(&phy->mode, &config->video_timing, sizeof(phy->mode));
Padmanabhan Komanduru8ee8ee52016-12-19 12:10:51 +0530827 memcpy(&phy->cfg.lane_map, &config->lane_map, sizeof(config->lane_map));
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700828 phy->data_lanes = config->common_config.data_lanes;
829 phy->dst_format = config->common_config.dst_format;
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700830 phy->cfg.pll_source = pll_source;
831
Padmanabhan Komanduruee89d212016-12-19 12:51:31 +0530832 /**
833 * If PHY timing parameters are not present in panel dtsi file,
834 * then calculate them in the driver
835 */
836 if (!phy->cfg.is_phy_timing_present)
837 rc = phy->hw.ops.calculate_timing_params(&phy->hw,
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700838 &phy->mode,
839 &config->common_config,
840 &phy->cfg.timing);
841 if (rc) {
842 pr_err("[%s] failed to set timing, rc=%d\n", phy->name, rc);
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +0530843 goto error;
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700844 }
845
Shashank Babu Chinta Venkata7d608732017-05-31 14:10:26 -0700846 if (!is_cont_splash_enabled) {
847 dsi_phy_enable_hw(phy);
848 pr_debug("cont splash not enabled, phy enable required\n");
849 }
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +0530850 phy->dsi_phy_state = DSI_PHY_ENGINE_ON;
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700851
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700852error:
853 mutex_unlock(&phy->phy_lock);
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +0530854
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700855 return rc;
856}
857
Sandeep Panda11b20d82017-06-19 12:57:27 +0530858int dsi_phy_lane_reset(struct msm_dsi_phy *phy)
859{
860 int ret = 0;
861
862 if (!phy)
863 return ret;
864
865 mutex_lock(&phy->phy_lock);
866 if (phy->hw.ops.phy_lane_reset)
867 ret = phy->hw.ops.phy_lane_reset(&phy->hw);
868 mutex_unlock(&phy->phy_lock);
869
870 return ret;
871}
872
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700873/**
874 * dsi_phy_disable() - disable DSI PHY hardware.
875 * @phy: DSI PHY handle.
876 *
877 * Return: error code.
878 */
879int dsi_phy_disable(struct msm_dsi_phy *phy)
880{
881 int rc = 0;
882
883 if (!phy) {
884 pr_err("Invalid params\n");
885 return -EINVAL;
886 }
887
888 mutex_lock(&phy->phy_lock);
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700889 dsi_phy_disable_hw(phy);
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +0530890 phy->dsi_phy_state = DSI_PHY_ENGINE_OFF;
891 mutex_unlock(&phy->phy_lock);
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700892
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +0530893 return rc;
894}
895
896/**
897 * dsi_phy_idle_ctrl() - enable/disable DSI PHY during idle screen
898 * @phy: DSI PHY handle
899 * @enable: boolean to specify PHY enable/disable.
900 *
901 * Return: error code.
902 */
903
904int dsi_phy_idle_ctrl(struct msm_dsi_phy *phy, bool enable)
905{
906 if (!phy) {
907 pr_err("Invalid params\n");
908 return -EINVAL;
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700909 }
910
Alan Kwong797e0892017-10-17 09:37:24 -0400911 pr_debug("[%s] enable=%d\n", phy->name, enable);
912
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +0530913 mutex_lock(&phy->phy_lock);
914 if (enable) {
915 if (phy->hw.ops.phy_idle_on)
916 phy->hw.ops.phy_idle_on(&phy->hw, &phy->cfg);
917
918 if (phy->hw.ops.regulator_enable)
919 phy->hw.ops.regulator_enable(&phy->hw,
920 &phy->cfg.regulators);
Alan Kwong797e0892017-10-17 09:37:24 -0400921
922 if (phy->hw.ops.enable)
923 phy->hw.ops.enable(&phy->hw, &phy->cfg);
924
925 phy->dsi_phy_state = DSI_PHY_ENGINE_ON;
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +0530926 } else {
Alan Kwong797e0892017-10-17 09:37:24 -0400927 phy->dsi_phy_state = DSI_PHY_ENGINE_OFF;
928
929 if (phy->hw.ops.disable)
930 phy->hw.ops.disable(&phy->hw, &phy->cfg);
931
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +0530932 if (phy->hw.ops.phy_idle_off)
933 phy->hw.ops.phy_idle_off(&phy->hw);
934 }
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700935 mutex_unlock(&phy->phy_lock);
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +0530936
937 return 0;
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700938}
939
940/**
Alan Kwong60cc3552017-11-01 22:08:48 -0400941 * dsi_phy_set_clk_freq() - set DSI PHY clock frequency setting
942 * @phy: DSI PHY handle
943 * @clk_freq: link clock frequency
944 *
945 * Return: error code.
946 */
947int dsi_phy_set_clk_freq(struct msm_dsi_phy *phy,
948 struct link_clk_freq *clk_freq)
949{
950 if (!phy || !clk_freq) {
951 pr_err("Invalid params\n");
952 return -EINVAL;
953 }
954
955 phy->regulator_required = clk_freq->byte_clk_rate >
956 (phy->regulator_min_datarate_bps / BITS_PER_BYTE);
957
Vara Reddy9cc3f932017-11-22 13:26:31 -0800958 /*
959 * DSI PLL needs 0p9 LDO1A for Powering DSI PLL block.
960 * PLL driver can vote for this regulator in PLL driver file, but for
961 * the usecase where we come out of idle(static screen), if PLL and
962 * PHY vote for regulator ,there will be performance delays as both
963 * votes go through RPM to enable regulators.
964 */
965 phy->regulator_required = true;
Alan Kwong60cc3552017-11-01 22:08:48 -0400966 pr_debug("[%s] lane_datarate=%u min_datarate=%u required=%d\n",
967 phy->name,
968 clk_freq->byte_clk_rate * BITS_PER_BYTE,
969 phy->regulator_min_datarate_bps,
970 phy->regulator_required);
971
972 return 0;
973}
974
975/**
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700976 * dsi_phy_set_timing_params() - timing parameters for the panel
977 * @phy: DSI PHY handle
978 * @timing: array holding timing params.
979 * @size: size of the array.
980 *
981 * When PHY timing calculator is not implemented, this array will be used to
982 * pass PHY timing information.
983 *
984 * Return: error code.
985 */
986int dsi_phy_set_timing_params(struct msm_dsi_phy *phy,
Padmanabhan Komanduruee89d212016-12-19 12:51:31 +0530987 u32 *timing, u32 size)
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700988{
989 int rc = 0;
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700990
991 if (!phy || !timing || !size) {
992 pr_err("Invalid params\n");
993 return -EINVAL;
994 }
995
996 mutex_lock(&phy->phy_lock);
997
Padmanabhan Komanduruee89d212016-12-19 12:51:31 +0530998 if (phy->hw.ops.phy_timing_val)
999 rc = phy->hw.ops.phy_timing_val(&phy->cfg.timing, timing, size);
1000 if (!rc)
1001 phy->cfg.is_phy_timing_present = true;
Ajay Singh Parmar67f31322016-06-22 17:37:56 -07001002 mutex_unlock(&phy->phy_lock);
1003 return rc;
1004}
1005
Ajay Singh Parmar64c19192016-06-10 16:44:56 -07001006void dsi_phy_drv_register(void)
Ajay Singh Parmar67f31322016-06-22 17:37:56 -07001007{
1008 platform_driver_register(&dsi_phy_platform_driver);
1009}
1010
Ajay Singh Parmar64c19192016-06-10 16:44:56 -07001011void dsi_phy_drv_unregister(void)
Ajay Singh Parmar67f31322016-06-22 17:37:56 -07001012{
1013 platform_driver_unregister(&dsi_phy_platform_driver);
1014}