blob: 989dc3d01875afaa17da4a80ce7c94c58b5292bf [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
Lakshmi Narayana Kalavala89b6cbe2018-05-11 11:28:12 -0700110 pr_debug("[%s] map dsi_phy registers to %pK\n",
111 phy->name, phy->hw.base);
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700112
113 return rc;
114}
115
116static int dsi_phy_regmap_deinit(struct msm_dsi_phy *phy)
117{
118 pr_debug("[%s] unmap registers\n", phy->name);
119 return 0;
120}
121
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700122static int dsi_phy_supplies_init(struct platform_device *pdev,
123 struct msm_dsi_phy *phy)
124{
125 int rc = 0;
126 int i = 0;
127 struct dsi_regulator_info *regs;
128 struct regulator *vreg = NULL;
129
130 regs = &phy->pwr_info.digital;
131 regs->vregs = devm_kzalloc(&pdev->dev, sizeof(struct dsi_vreg),
132 GFP_KERNEL);
133 if (!regs->vregs)
134 goto error;
135
136 regs->count = 1;
137 snprintf(regs->vregs->vreg_name,
138 ARRAY_SIZE(regs->vregs[i].vreg_name),
139 "%s", "gdsc");
140
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +0530141 rc = dsi_pwr_get_dt_vreg_data(&pdev->dev,
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700142 &phy->pwr_info.phy_pwr,
143 "qcom,phy-supply-entries");
144 if (rc) {
145 pr_err("failed to get host power supplies, rc = %d\n", rc);
146 goto error_digital;
147 }
148
149 regs = &phy->pwr_info.digital;
150 for (i = 0; i < regs->count; i++) {
151 vreg = devm_regulator_get(&pdev->dev, regs->vregs[i].vreg_name);
152 rc = PTR_RET(vreg);
153 if (rc) {
154 pr_err("failed to get %s regulator\n",
155 regs->vregs[i].vreg_name);
156 goto error_host_pwr;
157 }
158 regs->vregs[i].vreg = vreg;
159 }
160
161 regs = &phy->pwr_info.phy_pwr;
162 for (i = 0; i < regs->count; i++) {
163 vreg = devm_regulator_get(&pdev->dev, regs->vregs[i].vreg_name);
164 rc = PTR_RET(vreg);
165 if (rc) {
166 pr_err("failed to get %s regulator\n",
167 regs->vregs[i].vreg_name);
168 for (--i; i >= 0; i--)
169 devm_regulator_put(regs->vregs[i].vreg);
170 goto error_digital_put;
171 }
172 regs->vregs[i].vreg = vreg;
173 }
174
175 return rc;
176
177error_digital_put:
178 regs = &phy->pwr_info.digital;
179 for (i = 0; i < regs->count; i++)
180 devm_regulator_put(regs->vregs[i].vreg);
181error_host_pwr:
182 devm_kfree(&pdev->dev, phy->pwr_info.phy_pwr.vregs);
183 phy->pwr_info.phy_pwr.vregs = NULL;
184 phy->pwr_info.phy_pwr.count = 0;
185error_digital:
186 devm_kfree(&pdev->dev, phy->pwr_info.digital.vregs);
187 phy->pwr_info.digital.vregs = NULL;
188 phy->pwr_info.digital.count = 0;
189error:
190 return rc;
191}
192
193static int dsi_phy_supplies_deinit(struct msm_dsi_phy *phy)
194{
195 int i = 0;
196 int rc = 0;
197 struct dsi_regulator_info *regs;
198
199 regs = &phy->pwr_info.digital;
200 for (i = 0; i < regs->count; i++) {
201 if (!regs->vregs[i].vreg)
202 pr_err("vreg is NULL, should not reach here\n");
203 else
204 devm_regulator_put(regs->vregs[i].vreg);
205 }
206
207 regs = &phy->pwr_info.phy_pwr;
208 for (i = 0; i < regs->count; i++) {
209 if (!regs->vregs[i].vreg)
210 pr_err("vreg is NULL, should not reach here\n");
211 else
212 devm_regulator_put(regs->vregs[i].vreg);
213 }
214
215 if (phy->pwr_info.phy_pwr.vregs) {
216 devm_kfree(&phy->pdev->dev, phy->pwr_info.phy_pwr.vregs);
217 phy->pwr_info.phy_pwr.vregs = NULL;
218 phy->pwr_info.phy_pwr.count = 0;
219 }
220 if (phy->pwr_info.digital.vregs) {
221 devm_kfree(&phy->pdev->dev, phy->pwr_info.digital.vregs);
222 phy->pwr_info.digital.vregs = NULL;
223 phy->pwr_info.digital.count = 0;
224 }
225
226 return rc;
227}
228
229static int dsi_phy_parse_dt_per_lane_cfgs(struct platform_device *pdev,
230 struct dsi_phy_per_lane_cfgs *cfg,
231 char *property)
232{
233 int rc = 0, i = 0, j = 0;
234 const u8 *data;
235 u32 len = 0;
236
237 data = of_get_property(pdev->dev.of_node, property, &len);
238 if (!data) {
239 pr_err("Unable to read Phy %s settings\n", property);
240 return -EINVAL;
241 }
242
243 if (len != DSI_LANE_MAX * cfg->count_per_lane) {
244 pr_err("incorrect phy %s settings, exp=%d, act=%d\n",
245 property, (DSI_LANE_MAX * cfg->count_per_lane), len);
246 return -EINVAL;
247 }
248
249 for (i = DSI_LOGICAL_LANE_0; i < DSI_LANE_MAX; i++) {
250 for (j = 0; j < cfg->count_per_lane; j++) {
251 cfg->lane[i][j] = *data;
252 data++;
253 }
254 }
255
256 return rc;
257}
258
259static int dsi_phy_settings_init(struct platform_device *pdev,
260 struct msm_dsi_phy *phy)
261{
262 int rc = 0;
263 struct dsi_phy_per_lane_cfgs *lane = &phy->cfg.lanecfg;
264 struct dsi_phy_per_lane_cfgs *strength = &phy->cfg.strength;
265 struct dsi_phy_per_lane_cfgs *timing = &phy->cfg.timing;
266 struct dsi_phy_per_lane_cfgs *regs = &phy->cfg.regulators;
267
268 lane->count_per_lane = phy->ver_info->lane_cfg_count;
269 rc = dsi_phy_parse_dt_per_lane_cfgs(pdev, lane,
270 "qcom,platform-lane-config");
271 if (rc) {
272 pr_err("failed to parse lane cfgs, rc=%d\n", rc);
273 goto err;
274 }
275
276 strength->count_per_lane = phy->ver_info->strength_cfg_count;
277 rc = dsi_phy_parse_dt_per_lane_cfgs(pdev, strength,
278 "qcom,platform-strength-ctrl");
279 if (rc) {
280 pr_err("failed to parse lane cfgs, rc=%d\n", rc);
281 goto err;
282 }
283
284 regs->count_per_lane = phy->ver_info->regulator_cfg_count;
Padmanabhan Komanduru56611ef2016-12-19 12:21:11 +0530285 if (regs->count_per_lane > 0) {
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700286 rc = dsi_phy_parse_dt_per_lane_cfgs(pdev, regs,
287 "qcom,platform-regulator-settings");
Padmanabhan Komanduru56611ef2016-12-19 12:21:11 +0530288 if (rc) {
289 pr_err("failed to parse lane cfgs, rc=%d\n", rc);
290 goto err;
291 }
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700292 }
293
294 /* Actual timing values are dependent on panel */
295 timing->count_per_lane = phy->ver_info->timing_cfg_count;
Alan Kwong797e0892017-10-17 09:37:24 -0400296
297 phy->allow_phy_power_off = of_property_read_bool(pdev->dev.of_node,
298 "qcom,panel-allow-phy-poweroff");
299
Alan Kwong60cc3552017-11-01 22:08:48 -0400300 of_property_read_u32(pdev->dev.of_node,
301 "qcom,dsi-phy-regulator-min-datarate-bps",
302 &phy->regulator_min_datarate_bps);
303
Padmanabhan Komanduru56611ef2016-12-19 12:21:11 +0530304 return 0;
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700305err:
306 lane->count_per_lane = 0;
307 strength->count_per_lane = 0;
308 regs->count_per_lane = 0;
309 timing->count_per_lane = 0;
310 return rc;
311}
312
313static int dsi_phy_settings_deinit(struct msm_dsi_phy *phy)
314{
315 memset(&phy->cfg.lanecfg, 0x0, sizeof(phy->cfg.lanecfg));
316 memset(&phy->cfg.strength, 0x0, sizeof(phy->cfg.strength));
317 memset(&phy->cfg.timing, 0x0, sizeof(phy->cfg.timing));
318 memset(&phy->cfg.regulators, 0x0, sizeof(phy->cfg.regulators));
319 return 0;
320}
321
322static int dsi_phy_driver_probe(struct platform_device *pdev)
323{
324 struct msm_dsi_phy *dsi_phy;
325 struct dsi_phy_list_item *item;
326 const struct of_device_id *id;
327 const struct dsi_ver_spec_info *ver_info;
328 int rc = 0;
329 u32 index = 0;
330
331 if (!pdev || !pdev->dev.of_node) {
332 pr_err("pdev not found\n");
333 return -ENODEV;
334 }
335
336 id = of_match_node(msm_dsi_phy_of_match, pdev->dev.of_node);
337 if (!id)
338 return -ENODEV;
339
340 ver_info = id->data;
341
342 item = devm_kzalloc(&pdev->dev, sizeof(*item), GFP_KERNEL);
343 if (!item)
344 return -ENOMEM;
345
346
347 dsi_phy = devm_kzalloc(&pdev->dev, sizeof(*dsi_phy), GFP_KERNEL);
348 if (!dsi_phy) {
349 devm_kfree(&pdev->dev, item);
350 return -ENOMEM;
351 }
352
353 rc = of_property_read_u32(pdev->dev.of_node, "cell-index", &index);
354 if (rc) {
355 pr_debug("cell index not set, default to 0\n");
356 index = 0;
357 }
358
359 dsi_phy->index = index;
360
361 dsi_phy->name = of_get_property(pdev->dev.of_node, "label", NULL);
362 if (!dsi_phy->name)
363 dsi_phy->name = DSI_PHY_DEFAULT_LABEL;
364
365 pr_debug("Probing %s device\n", dsi_phy->name);
366
367 rc = dsi_phy_regmap_init(pdev, dsi_phy);
368 if (rc) {
369 pr_err("Failed to parse register information, rc=%d\n", rc);
370 goto fail;
371 }
372
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700373 rc = dsi_phy_supplies_init(pdev, dsi_phy);
374 if (rc) {
375 pr_err("failed to parse voltage supplies, rc = %d\n", rc);
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +0530376 goto fail_regmap;
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700377 }
378
379 rc = dsi_catalog_phy_setup(&dsi_phy->hw, ver_info->version,
380 dsi_phy->index);
381 if (rc) {
382 pr_err("Catalog does not support version (%d)\n",
383 ver_info->version);
384 goto fail_supplies;
385 }
386
387 dsi_phy->ver_info = ver_info;
388 rc = dsi_phy_settings_init(pdev, dsi_phy);
389 if (rc) {
390 pr_err("Failed to parse phy setting, rc=%d\n", rc);
391 goto fail_supplies;
392 }
393
394 item->phy = dsi_phy;
395
396 mutex_lock(&dsi_phy_list_lock);
397 list_add(&item->list, &dsi_phy_list);
398 mutex_unlock(&dsi_phy_list_lock);
399
400 mutex_init(&dsi_phy->phy_lock);
401 /** TODO: initialize debugfs */
402 dsi_phy->pdev = pdev;
403 platform_set_drvdata(pdev, dsi_phy);
Shashank Babu Chinta Venkata2f24e982017-04-21 14:57:53 -0700404 pr_info("Probe successful for %s\n", dsi_phy->name);
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700405 return 0;
406
407fail_supplies:
408 (void)dsi_phy_supplies_deinit(dsi_phy);
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700409fail_regmap:
410 (void)dsi_phy_regmap_deinit(dsi_phy);
411fail:
412 devm_kfree(&pdev->dev, dsi_phy);
413 devm_kfree(&pdev->dev, item);
414 return rc;
415}
416
417static int dsi_phy_driver_remove(struct platform_device *pdev)
418{
419 int rc = 0;
420 struct msm_dsi_phy *phy = platform_get_drvdata(pdev);
421 struct list_head *pos, *tmp;
422
423 if (!pdev || !phy) {
424 pr_err("Invalid device\n");
425 return -EINVAL;
426 }
427
428 mutex_lock(&dsi_phy_list_lock);
429 list_for_each_safe(pos, tmp, &dsi_phy_list) {
430 struct dsi_phy_list_item *n;
431
432 n = list_entry(pos, struct dsi_phy_list_item, list);
433 if (n->phy == phy) {
434 list_del(&n->list);
435 devm_kfree(&pdev->dev, n);
436 break;
437 }
438 }
439 mutex_unlock(&dsi_phy_list_lock);
440
441 mutex_lock(&phy->phy_lock);
442 rc = dsi_phy_settings_deinit(phy);
443 if (rc)
444 pr_err("failed to deinitialize phy settings, rc=%d\n", rc);
445
446 rc = dsi_phy_supplies_deinit(phy);
447 if (rc)
448 pr_err("failed to deinitialize voltage supplies, rc=%d\n", rc);
449
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700450 rc = dsi_phy_regmap_deinit(phy);
451 if (rc)
452 pr_err("failed to deinitialize regmap, rc=%d\n", rc);
453 mutex_unlock(&phy->phy_lock);
454
455 mutex_destroy(&phy->phy_lock);
456 devm_kfree(&pdev->dev, phy);
457
458 platform_set_drvdata(pdev, NULL);
459
460 return 0;
461}
462
463static struct platform_driver dsi_phy_platform_driver = {
464 .probe = dsi_phy_driver_probe,
465 .remove = dsi_phy_driver_remove,
466 .driver = {
Ajay Singh Parmar64c19192016-06-10 16:44:56 -0700467 .name = "dsi_phy",
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700468 .of_match_table = msm_dsi_phy_of_match,
469 },
470};
471
472static void dsi_phy_enable_hw(struct msm_dsi_phy *phy)
473{
474 if (phy->hw.ops.regulator_enable)
475 phy->hw.ops.regulator_enable(&phy->hw, &phy->cfg.regulators);
476
477 if (phy->hw.ops.enable)
478 phy->hw.ops.enable(&phy->hw, &phy->cfg);
479}
480
481static void dsi_phy_disable_hw(struct msm_dsi_phy *phy)
482{
483 if (phy->hw.ops.disable)
Padmanabhan Komanduru56611ef2016-12-19 12:21:11 +0530484 phy->hw.ops.disable(&phy->hw, &phy->cfg);
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700485
486 if (phy->hw.ops.regulator_disable)
487 phy->hw.ops.regulator_disable(&phy->hw);
488}
489
490/**
491 * dsi_phy_get() - get a dsi phy handle from device node
492 * @of_node: device node for dsi phy controller
493 *
494 * Gets the DSI PHY handle for the corresponding of_node. The ref count is
495 * incremented to one all subsequents get will fail until the original client
496 * calls a put.
497 *
498 * Return: DSI PHY handle or an error code.
499 */
500struct msm_dsi_phy *dsi_phy_get(struct device_node *of_node)
501{
502 struct list_head *pos, *tmp;
503 struct msm_dsi_phy *phy = NULL;
504
505 mutex_lock(&dsi_phy_list_lock);
506 list_for_each_safe(pos, tmp, &dsi_phy_list) {
507 struct dsi_phy_list_item *n;
508
509 n = list_entry(pos, struct dsi_phy_list_item, list);
510 if (n->phy->pdev->dev.of_node == of_node) {
511 phy = n->phy;
512 break;
513 }
514 }
515 mutex_unlock(&dsi_phy_list_lock);
516
517 if (!phy) {
518 pr_err("Device with of node not found\n");
519 phy = ERR_PTR(-EPROBE_DEFER);
520 return phy;
521 }
522
523 mutex_lock(&phy->phy_lock);
524 if (phy->refcount > 0) {
525 pr_err("[PHY_%d] Device under use\n", phy->index);
526 phy = ERR_PTR(-EINVAL);
527 } else {
528 phy->refcount++;
529 }
530 mutex_unlock(&phy->phy_lock);
531 return phy;
532}
533
534/**
535 * dsi_phy_put() - release dsi phy handle
536 * @dsi_phy: DSI PHY handle.
537 *
538 * Release the DSI PHY hardware. Driver will clean up all resources and puts
539 * back the DSI PHY into reset state.
540 */
541void dsi_phy_put(struct msm_dsi_phy *dsi_phy)
542{
543 mutex_lock(&dsi_phy->phy_lock);
544
545 if (dsi_phy->refcount == 0)
546 pr_err("Unbalanced dsi_phy_put call\n");
547 else
548 dsi_phy->refcount--;
549
550 mutex_unlock(&dsi_phy->phy_lock);
551}
552
553/**
554 * dsi_phy_drv_init() - initialize dsi phy driver
555 * @dsi_phy: DSI PHY handle.
556 *
557 * Initializes DSI PHY driver. Should be called after dsi_phy_get().
558 *
559 * Return: error code.
560 */
561int dsi_phy_drv_init(struct msm_dsi_phy *dsi_phy)
562{
Dhaval Patela2430842017-06-15 14:32:36 -0700563 char dbg_name[DSI_DEBUG_NAME_LEN];
564
565 snprintf(dbg_name, DSI_DEBUG_NAME_LEN, "dsi%d_phy", dsi_phy->index);
566 sde_dbg_reg_register_base(dbg_name, dsi_phy->hw.base,
567 msm_iomap_size(dsi_phy->pdev, "dsi_phy"));
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700568 return 0;
569}
570
571/**
572 * dsi_phy_drv_deinit() - de-initialize dsi phy driver
573 * @dsi_phy: DSI PHY handle.
574 *
575 * Release all resources acquired by dsi_phy_drv_init().
576 *
577 * Return: error code.
578 */
579int dsi_phy_drv_deinit(struct msm_dsi_phy *dsi_phy)
580{
581 return 0;
582}
583
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +0530584int dsi_phy_clk_cb_register(struct msm_dsi_phy *dsi_phy,
585 struct clk_ctrl_cb *clk_cb)
586{
587 if (!dsi_phy || !clk_cb) {
588 pr_err("Invalid params\n");
589 return -EINVAL;
590 }
591
592 dsi_phy->clk_cb.priv = clk_cb->priv;
593 dsi_phy->clk_cb.dsi_clk_cb = clk_cb->dsi_clk_cb;
594 return 0;
595}
596
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700597/**
598 * dsi_phy_validate_mode() - validate a display mode
599 * @dsi_phy: DSI PHY handle.
600 * @mode: Mode information.
601 *
602 * Validation will fail if the mode cannot be supported by the PHY driver or
603 * hardware.
604 *
605 * Return: error code.
606 */
607int dsi_phy_validate_mode(struct msm_dsi_phy *dsi_phy,
608 struct dsi_mode_info *mode)
609{
610 int rc = 0;
611
612 if (!dsi_phy || !mode) {
613 pr_err("Invalid params\n");
614 return -EINVAL;
615 }
616
617 mutex_lock(&dsi_phy->phy_lock);
618
619 pr_debug("[PHY_%d] Skipping validation\n", dsi_phy->index);
620
621 mutex_unlock(&dsi_phy->phy_lock);
622 return rc;
623}
624
625/**
626 * dsi_phy_set_power_state() - enable/disable dsi phy power supplies
627 * @dsi_phy: DSI PHY handle.
628 * @enable: Boolean flag to enable/disable.
629 *
630 * Return: error code.
631 */
632int dsi_phy_set_power_state(struct msm_dsi_phy *dsi_phy, bool enable)
633{
634 int rc = 0;
635
636 if (!dsi_phy) {
637 pr_err("Invalid params\n");
638 return -EINVAL;
639 }
640
641 mutex_lock(&dsi_phy->phy_lock);
642
643 if (enable == dsi_phy->power_state) {
644 pr_err("[PHY_%d] No state change\n", dsi_phy->index);
645 goto error;
646 }
647
648 if (enable) {
649 rc = dsi_pwr_enable_regulator(&dsi_phy->pwr_info.digital, true);
650 if (rc) {
651 pr_err("failed to enable digital regulator\n");
652 goto error;
653 }
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +0530654
Alan Kwong60cc3552017-11-01 22:08:48 -0400655 if (dsi_phy->dsi_phy_state == DSI_PHY_ENGINE_OFF &&
656 dsi_phy->regulator_required) {
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +0530657 rc = dsi_pwr_enable_regulator(
658 &dsi_phy->pwr_info.phy_pwr, true);
659 if (rc) {
660 pr_err("failed to enable phy power\n");
661 (void)dsi_pwr_enable_regulator(
662 &dsi_phy->pwr_info.digital, false);
663 goto error;
664 }
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700665 }
666 } else {
Vara Reddyeda08c02017-12-08 17:54:10 -0800667 if (dsi_phy->dsi_phy_state == DSI_PHY_ENGINE_OFF &&
Alan Kwong60cc3552017-11-01 22:08:48 -0400668 dsi_phy->regulator_required) {
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +0530669 rc = dsi_pwr_enable_regulator(
670 &dsi_phy->pwr_info.phy_pwr, false);
671 if (rc) {
672 pr_err("failed to enable digital regulator\n");
673 goto error;
674 }
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700675 }
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +0530676
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700677 rc = dsi_pwr_enable_regulator(&dsi_phy->pwr_info.digital,
678 false);
679 if (rc) {
680 pr_err("failed to enable phy power\n");
681 goto error;
682 }
683 }
684
685 dsi_phy->power_state = enable;
686error:
687 mutex_unlock(&dsi_phy->phy_lock);
688 return rc;
689}
690
Padmanabhan Komanduru56611ef2016-12-19 12:21:11 +0530691static int dsi_phy_enable_ulps(struct msm_dsi_phy *phy,
Veera Sundaram Sankaranbb3680f2017-04-21 13:20:46 -0700692 struct dsi_host_config *config, bool clamp_enabled)
Padmanabhan Komanduru56611ef2016-12-19 12:21:11 +0530693{
694 int rc = 0;
695 u32 lanes = 0;
696 u32 ulps_lanes;
697
Sandeep Panda9d6948c2018-02-02 11:17:04 +0530698 lanes = config->common_config.data_lanes;
Padmanabhan Komanduru56611ef2016-12-19 12:21:11 +0530699 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
Sandeep Panda9d6948c2018-02-02 11:17:04 +0530733 lanes = config->common_config.data_lanes;
Padmanabhan Komanduru56611ef2016-12-19 12:21:11 +0530734 lanes |= DSI_CLOCK_LANE;
735
736 ulps_lanes = phy->hw.ops.ulps_ops.get_lanes_in_ulps(&phy->hw);
737
Veera Sundaram Sankaranbb3680f2017-04-21 13:20:46 -0700738 if (!phy->hw.ops.ulps_ops.is_lanes_in_ulps(lanes, ulps_lanes)) {
739 pr_err("Mismatch in ULPS: lanes:%d, ulps_lanes:%d\n",
740 lanes, ulps_lanes);
741 return -EIO;
742 }
Padmanabhan Komanduru56611ef2016-12-19 12:21:11 +0530743
744 phy->hw.ops.ulps_ops.ulps_exit(&phy->hw, &phy->cfg, lanes);
745
746 ulps_lanes = phy->hw.ops.ulps_ops.get_lanes_in_ulps(&phy->hw);
Veera Sundaram Sankaranbb3680f2017-04-21 13:20:46 -0700747
748 if (phy->hw.ops.ulps_ops.is_lanes_in_ulps(lanes, ulps_lanes)) {
Padmanabhan Komanduru56611ef2016-12-19 12:21:11 +0530749 pr_err("Lanes (0x%x) stuck in ULPS\n", ulps_lanes);
Veera Sundaram Sankaranbb3680f2017-04-21 13:20:46 -0700750 return -EIO;
Padmanabhan Komanduru56611ef2016-12-19 12:21:11 +0530751 }
752
Veera Sundaram Sankaranbb3680f2017-04-21 13:20:46 -0700753 return 0;
Padmanabhan Komanduru56611ef2016-12-19 12:21:11 +0530754}
755
Aravind Venkateswaranb3fc3a02018-03-05 16:09:05 -0800756void dsi_phy_toggle_resync_fifo(struct msm_dsi_phy *phy)
757{
758 if (!phy)
759 return;
760
761 if (!phy->hw.ops.toggle_resync_fifo)
762 return;
763
764 phy->hw.ops.toggle_resync_fifo(&phy->hw);
765}
Padmanabhan Komanduru56611ef2016-12-19 12:21:11 +0530766
767int dsi_phy_set_ulps(struct msm_dsi_phy *phy, struct dsi_host_config *config,
Veera Sundaram Sankaranbb3680f2017-04-21 13:20:46 -0700768 bool enable, bool clamp_enabled)
Padmanabhan Komanduru56611ef2016-12-19 12:21:11 +0530769{
770 int rc = 0;
771
772 if (!phy) {
773 pr_err("Invalid params\n");
774 return -EINVAL;
775 }
776
777 if (!phy->hw.ops.ulps_ops.ulps_request ||
Veera Sundaram Sankaranbb3680f2017-04-21 13:20:46 -0700778 !phy->hw.ops.ulps_ops.ulps_exit ||
779 !phy->hw.ops.ulps_ops.get_lanes_in_ulps ||
780 !phy->hw.ops.ulps_ops.is_lanes_in_ulps ||
781 !phy->hw.ops.ulps_ops.wait_for_lane_idle) {
Padmanabhan Komanduru56611ef2016-12-19 12:21:11 +0530782 pr_debug("DSI PHY ULPS ops not present\n");
783 return 0;
784 }
785
786 mutex_lock(&phy->phy_lock);
787
788 if (enable)
Veera Sundaram Sankaranbb3680f2017-04-21 13:20:46 -0700789 rc = dsi_phy_enable_ulps(phy, config, clamp_enabled);
Padmanabhan Komanduru56611ef2016-12-19 12:21:11 +0530790 else
791 rc = dsi_phy_disable_ulps(phy, config);
792
793 if (rc) {
794 pr_err("[DSI_PHY%d] Ulps state change(%d) failed, rc=%d\n",
795 phy->index, enable, rc);
796 goto error;
797 }
798 pr_debug("[DSI_PHY%d] ULPS state = %d\n", phy->index, enable);
799
800error:
801 mutex_unlock(&phy->phy_lock);
802 return rc;
803}
804
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700805/**
806 * dsi_phy_enable() - enable DSI PHY hardware
807 * @dsi_phy: DSI PHY handle.
808 * @config: DSI host configuration.
809 * @pll_source: Source PLL for PHY clock.
810 * @skip_validation: Validation will not be performed on parameters.
Shashank Babu Chinta Venkata7d608732017-05-31 14:10:26 -0700811 * @is_cont_splash_enabled: check whether continuous splash enabled.
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700812 *
813 * Validates and enables DSI PHY.
814 *
815 * Return: error code.
816 */
817int dsi_phy_enable(struct msm_dsi_phy *phy,
818 struct dsi_host_config *config,
819 enum dsi_phy_pll_source pll_source,
Shashank Babu Chinta Venkata7d608732017-05-31 14:10:26 -0700820 bool skip_validation,
821 bool is_cont_splash_enabled)
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700822{
823 int rc = 0;
824
825 if (!phy || !config) {
826 pr_err("Invalid params\n");
827 return -EINVAL;
828 }
829
830 mutex_lock(&phy->phy_lock);
831
832 if (!skip_validation)
833 pr_debug("[PHY_%d] TODO: perform validation\n", phy->index);
834
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700835 memcpy(&phy->mode, &config->video_timing, sizeof(phy->mode));
Padmanabhan Komanduru8ee8ee52016-12-19 12:10:51 +0530836 memcpy(&phy->cfg.lane_map, &config->lane_map, sizeof(config->lane_map));
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700837 phy->data_lanes = config->common_config.data_lanes;
838 phy->dst_format = config->common_config.dst_format;
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700839 phy->cfg.pll_source = pll_source;
840
Padmanabhan Komanduruee89d212016-12-19 12:51:31 +0530841 /**
842 * If PHY timing parameters are not present in panel dtsi file,
843 * then calculate them in the driver
844 */
845 if (!phy->cfg.is_phy_timing_present)
846 rc = phy->hw.ops.calculate_timing_params(&phy->hw,
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700847 &phy->mode,
848 &config->common_config,
849 &phy->cfg.timing);
850 if (rc) {
851 pr_err("[%s] failed to set timing, rc=%d\n", phy->name, rc);
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +0530852 goto error;
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700853 }
854
Shashank Babu Chinta Venkata7d608732017-05-31 14:10:26 -0700855 if (!is_cont_splash_enabled) {
856 dsi_phy_enable_hw(phy);
857 pr_debug("cont splash not enabled, phy enable required\n");
858 }
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +0530859 phy->dsi_phy_state = DSI_PHY_ENGINE_ON;
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700860
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700861error:
862 mutex_unlock(&phy->phy_lock);
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +0530863
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700864 return rc;
865}
866
Sandeep Panda11b20d82017-06-19 12:57:27 +0530867int dsi_phy_lane_reset(struct msm_dsi_phy *phy)
868{
869 int ret = 0;
870
871 if (!phy)
872 return ret;
873
874 mutex_lock(&phy->phy_lock);
875 if (phy->hw.ops.phy_lane_reset)
876 ret = phy->hw.ops.phy_lane_reset(&phy->hw);
877 mutex_unlock(&phy->phy_lock);
878
879 return ret;
880}
881
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700882/**
883 * dsi_phy_disable() - disable DSI PHY hardware.
884 * @phy: DSI PHY handle.
885 *
886 * Return: error code.
887 */
888int dsi_phy_disable(struct msm_dsi_phy *phy)
889{
890 int rc = 0;
891
892 if (!phy) {
893 pr_err("Invalid params\n");
894 return -EINVAL;
895 }
896
897 mutex_lock(&phy->phy_lock);
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700898 dsi_phy_disable_hw(phy);
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +0530899 phy->dsi_phy_state = DSI_PHY_ENGINE_OFF;
900 mutex_unlock(&phy->phy_lock);
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700901
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +0530902 return rc;
903}
904
905/**
Aravind Venkateswaran1769bed2018-05-14 17:15:17 -0700906 * dsi_phy_set_clamp_state() - configure clamps for DSI lanes
907 * @phy: DSI PHY handle.
908 * @enable: boolean to specify clamp enable/disable.
909 *
910 * Return: error code.
911 */
912int dsi_phy_set_clamp_state(struct msm_dsi_phy *phy, bool enable)
913{
914 if (!phy)
915 return -EINVAL;
916
917 pr_debug("[%s] enable=%d\n", phy->name, enable);
918
919 if (phy->hw.ops.clamp_ctrl)
920 phy->hw.ops.clamp_ctrl(&phy->hw, enable);
921
922 return 0;
923}
924
925/**
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +0530926 * dsi_phy_idle_ctrl() - enable/disable DSI PHY during idle screen
927 * @phy: DSI PHY handle
928 * @enable: boolean to specify PHY enable/disable.
929 *
930 * Return: error code.
931 */
932
933int dsi_phy_idle_ctrl(struct msm_dsi_phy *phy, bool enable)
934{
935 if (!phy) {
936 pr_err("Invalid params\n");
937 return -EINVAL;
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700938 }
939
Alan Kwong797e0892017-10-17 09:37:24 -0400940 pr_debug("[%s] enable=%d\n", phy->name, enable);
941
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +0530942 mutex_lock(&phy->phy_lock);
943 if (enable) {
944 if (phy->hw.ops.phy_idle_on)
945 phy->hw.ops.phy_idle_on(&phy->hw, &phy->cfg);
946
947 if (phy->hw.ops.regulator_enable)
948 phy->hw.ops.regulator_enable(&phy->hw,
949 &phy->cfg.regulators);
Alan Kwong797e0892017-10-17 09:37:24 -0400950
951 if (phy->hw.ops.enable)
952 phy->hw.ops.enable(&phy->hw, &phy->cfg);
953
954 phy->dsi_phy_state = DSI_PHY_ENGINE_ON;
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +0530955 } else {
Alan Kwong797e0892017-10-17 09:37:24 -0400956 phy->dsi_phy_state = DSI_PHY_ENGINE_OFF;
957
958 if (phy->hw.ops.disable)
959 phy->hw.ops.disable(&phy->hw, &phy->cfg);
960
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +0530961 if (phy->hw.ops.phy_idle_off)
962 phy->hw.ops.phy_idle_off(&phy->hw);
963 }
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700964 mutex_unlock(&phy->phy_lock);
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +0530965
966 return 0;
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700967}
968
969/**
Alan Kwong60cc3552017-11-01 22:08:48 -0400970 * dsi_phy_set_clk_freq() - set DSI PHY clock frequency setting
971 * @phy: DSI PHY handle
972 * @clk_freq: link clock frequency
973 *
974 * Return: error code.
975 */
976int dsi_phy_set_clk_freq(struct msm_dsi_phy *phy,
977 struct link_clk_freq *clk_freq)
978{
979 if (!phy || !clk_freq) {
980 pr_err("Invalid params\n");
981 return -EINVAL;
982 }
983
984 phy->regulator_required = clk_freq->byte_clk_rate >
985 (phy->regulator_min_datarate_bps / BITS_PER_BYTE);
986
Vara Reddy9cc3f932017-11-22 13:26:31 -0800987 /*
988 * DSI PLL needs 0p9 LDO1A for Powering DSI PLL block.
989 * PLL driver can vote for this regulator in PLL driver file, but for
990 * the usecase where we come out of idle(static screen), if PLL and
991 * PHY vote for regulator ,there will be performance delays as both
992 * votes go through RPM to enable regulators.
993 */
994 phy->regulator_required = true;
Alan Kwong60cc3552017-11-01 22:08:48 -0400995 pr_debug("[%s] lane_datarate=%u min_datarate=%u required=%d\n",
996 phy->name,
997 clk_freq->byte_clk_rate * BITS_PER_BYTE,
998 phy->regulator_min_datarate_bps,
999 phy->regulator_required);
1000
1001 return 0;
1002}
1003
1004/**
Ajay Singh Parmar67f31322016-06-22 17:37:56 -07001005 * dsi_phy_set_timing_params() - timing parameters for the panel
1006 * @phy: DSI PHY handle
1007 * @timing: array holding timing params.
1008 * @size: size of the array.
1009 *
1010 * When PHY timing calculator is not implemented, this array will be used to
1011 * pass PHY timing information.
1012 *
1013 * Return: error code.
1014 */
1015int dsi_phy_set_timing_params(struct msm_dsi_phy *phy,
Padmanabhan Komanduruee89d212016-12-19 12:51:31 +05301016 u32 *timing, u32 size)
Ajay Singh Parmar67f31322016-06-22 17:37:56 -07001017{
1018 int rc = 0;
Ajay Singh Parmar67f31322016-06-22 17:37:56 -07001019
1020 if (!phy || !timing || !size) {
1021 pr_err("Invalid params\n");
1022 return -EINVAL;
1023 }
1024
1025 mutex_lock(&phy->phy_lock);
1026
Padmanabhan Komanduruee89d212016-12-19 12:51:31 +05301027 if (phy->hw.ops.phy_timing_val)
1028 rc = phy->hw.ops.phy_timing_val(&phy->cfg.timing, timing, size);
1029 if (!rc)
1030 phy->cfg.is_phy_timing_present = true;
Ajay Singh Parmar67f31322016-06-22 17:37:56 -07001031 mutex_unlock(&phy->phy_lock);
1032 return rc;
1033}
1034
Ajay Singh Parmar64c19192016-06-10 16:44:56 -07001035void dsi_phy_drv_register(void)
Ajay Singh Parmar67f31322016-06-22 17:37:56 -07001036{
1037 platform_driver_register(&dsi_phy_platform_driver);
1038}
1039
Ajay Singh Parmar64c19192016-06-10 16:44:56 -07001040void dsi_phy_drv_unregister(void)
Ajay Singh Parmar67f31322016-06-22 17:37:56 -07001041{
1042 platform_driver_unregister(&dsi_phy_platform_driver);
1043}