blob: 32497ffe9abd3c77fe47fba10d4dc93dfbd64579 [file] [log] [blame]
Ajay Singh Parmar67f31322016-06-22 17:37:56 -07001/*
Sandeep Pandaaf198a92019-03-07 19:33:15 +05302 * Copyright (c) 2016-2019, 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
Sandeep Panda97c89dd2018-10-25 15:49:16 +0530110 ptr = msm_ioremap(pdev, "dyn_refresh_base", phy->name);
111 phy->hw.dyn_pll_base = ptr;
112
Lakshmi Narayana Kalavala89b6cbe2018-05-11 11:28:12 -0700113 pr_debug("[%s] map dsi_phy registers to %pK\n",
114 phy->name, phy->hw.base);
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700115
116 return rc;
117}
118
119static int dsi_phy_regmap_deinit(struct msm_dsi_phy *phy)
120{
121 pr_debug("[%s] unmap registers\n", phy->name);
122 return 0;
123}
124
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700125static int dsi_phy_supplies_init(struct platform_device *pdev,
126 struct msm_dsi_phy *phy)
127{
128 int rc = 0;
129 int i = 0;
130 struct dsi_regulator_info *regs;
131 struct regulator *vreg = NULL;
132
133 regs = &phy->pwr_info.digital;
134 regs->vregs = devm_kzalloc(&pdev->dev, sizeof(struct dsi_vreg),
135 GFP_KERNEL);
136 if (!regs->vregs)
137 goto error;
138
139 regs->count = 1;
140 snprintf(regs->vregs->vreg_name,
141 ARRAY_SIZE(regs->vregs[i].vreg_name),
142 "%s", "gdsc");
143
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +0530144 rc = dsi_pwr_get_dt_vreg_data(&pdev->dev,
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700145 &phy->pwr_info.phy_pwr,
146 "qcom,phy-supply-entries");
147 if (rc) {
148 pr_err("failed to get host power supplies, rc = %d\n", rc);
149 goto error_digital;
150 }
151
152 regs = &phy->pwr_info.digital;
153 for (i = 0; i < regs->count; i++) {
154 vreg = devm_regulator_get(&pdev->dev, regs->vregs[i].vreg_name);
155 rc = PTR_RET(vreg);
156 if (rc) {
157 pr_err("failed to get %s regulator\n",
158 regs->vregs[i].vreg_name);
159 goto error_host_pwr;
160 }
161 regs->vregs[i].vreg = vreg;
162 }
163
164 regs = &phy->pwr_info.phy_pwr;
165 for (i = 0; i < regs->count; i++) {
166 vreg = devm_regulator_get(&pdev->dev, regs->vregs[i].vreg_name);
167 rc = PTR_RET(vreg);
168 if (rc) {
169 pr_err("failed to get %s regulator\n",
170 regs->vregs[i].vreg_name);
171 for (--i; i >= 0; i--)
172 devm_regulator_put(regs->vregs[i].vreg);
173 goto error_digital_put;
174 }
175 regs->vregs[i].vreg = vreg;
176 }
177
178 return rc;
179
180error_digital_put:
181 regs = &phy->pwr_info.digital;
182 for (i = 0; i < regs->count; i++)
183 devm_regulator_put(regs->vregs[i].vreg);
184error_host_pwr:
185 devm_kfree(&pdev->dev, phy->pwr_info.phy_pwr.vregs);
186 phy->pwr_info.phy_pwr.vregs = NULL;
187 phy->pwr_info.phy_pwr.count = 0;
188error_digital:
189 devm_kfree(&pdev->dev, phy->pwr_info.digital.vregs);
190 phy->pwr_info.digital.vregs = NULL;
191 phy->pwr_info.digital.count = 0;
192error:
193 return rc;
194}
195
196static int dsi_phy_supplies_deinit(struct msm_dsi_phy *phy)
197{
198 int i = 0;
199 int rc = 0;
200 struct dsi_regulator_info *regs;
201
202 regs = &phy->pwr_info.digital;
203 for (i = 0; i < regs->count; i++) {
204 if (!regs->vregs[i].vreg)
205 pr_err("vreg is NULL, should not reach here\n");
206 else
207 devm_regulator_put(regs->vregs[i].vreg);
208 }
209
210 regs = &phy->pwr_info.phy_pwr;
211 for (i = 0; i < regs->count; i++) {
212 if (!regs->vregs[i].vreg)
213 pr_err("vreg is NULL, should not reach here\n");
214 else
215 devm_regulator_put(regs->vregs[i].vreg);
216 }
217
218 if (phy->pwr_info.phy_pwr.vregs) {
219 devm_kfree(&phy->pdev->dev, phy->pwr_info.phy_pwr.vregs);
220 phy->pwr_info.phy_pwr.vregs = NULL;
221 phy->pwr_info.phy_pwr.count = 0;
222 }
223 if (phy->pwr_info.digital.vregs) {
224 devm_kfree(&phy->pdev->dev, phy->pwr_info.digital.vregs);
225 phy->pwr_info.digital.vregs = NULL;
226 phy->pwr_info.digital.count = 0;
227 }
228
229 return rc;
230}
231
232static int dsi_phy_parse_dt_per_lane_cfgs(struct platform_device *pdev,
233 struct dsi_phy_per_lane_cfgs *cfg,
234 char *property)
235{
236 int rc = 0, i = 0, j = 0;
237 const u8 *data;
238 u32 len = 0;
239
240 data = of_get_property(pdev->dev.of_node, property, &len);
241 if (!data) {
242 pr_err("Unable to read Phy %s settings\n", property);
243 return -EINVAL;
244 }
245
246 if (len != DSI_LANE_MAX * cfg->count_per_lane) {
247 pr_err("incorrect phy %s settings, exp=%d, act=%d\n",
248 property, (DSI_LANE_MAX * cfg->count_per_lane), len);
249 return -EINVAL;
250 }
251
252 for (i = DSI_LOGICAL_LANE_0; i < DSI_LANE_MAX; i++) {
253 for (j = 0; j < cfg->count_per_lane; j++) {
254 cfg->lane[i][j] = *data;
255 data++;
256 }
257 }
258
259 return rc;
260}
261
262static int dsi_phy_settings_init(struct platform_device *pdev,
263 struct msm_dsi_phy *phy)
264{
265 int rc = 0;
266 struct dsi_phy_per_lane_cfgs *lane = &phy->cfg.lanecfg;
267 struct dsi_phy_per_lane_cfgs *strength = &phy->cfg.strength;
268 struct dsi_phy_per_lane_cfgs *timing = &phy->cfg.timing;
269 struct dsi_phy_per_lane_cfgs *regs = &phy->cfg.regulators;
270
271 lane->count_per_lane = phy->ver_info->lane_cfg_count;
272 rc = dsi_phy_parse_dt_per_lane_cfgs(pdev, lane,
273 "qcom,platform-lane-config");
274 if (rc) {
275 pr_err("failed to parse lane cfgs, rc=%d\n", rc);
276 goto err;
277 }
278
279 strength->count_per_lane = phy->ver_info->strength_cfg_count;
280 rc = dsi_phy_parse_dt_per_lane_cfgs(pdev, strength,
281 "qcom,platform-strength-ctrl");
282 if (rc) {
283 pr_err("failed to parse lane cfgs, rc=%d\n", rc);
284 goto err;
285 }
286
287 regs->count_per_lane = phy->ver_info->regulator_cfg_count;
Padmanabhan Komanduru56611ef2016-12-19 12:21:11 +0530288 if (regs->count_per_lane > 0) {
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700289 rc = dsi_phy_parse_dt_per_lane_cfgs(pdev, regs,
290 "qcom,platform-regulator-settings");
Padmanabhan Komanduru56611ef2016-12-19 12:21:11 +0530291 if (rc) {
292 pr_err("failed to parse lane cfgs, rc=%d\n", rc);
293 goto err;
294 }
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700295 }
296
297 /* Actual timing values are dependent on panel */
298 timing->count_per_lane = phy->ver_info->timing_cfg_count;
Alan Kwong797e0892017-10-17 09:37:24 -0400299
300 phy->allow_phy_power_off = of_property_read_bool(pdev->dev.of_node,
301 "qcom,panel-allow-phy-poweroff");
302
Alan Kwong60cc3552017-11-01 22:08:48 -0400303 of_property_read_u32(pdev->dev.of_node,
304 "qcom,dsi-phy-regulator-min-datarate-bps",
305 &phy->regulator_min_datarate_bps);
306
Padmanabhan Komanduru56611ef2016-12-19 12:21:11 +0530307 return 0;
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700308err:
309 lane->count_per_lane = 0;
310 strength->count_per_lane = 0;
311 regs->count_per_lane = 0;
312 timing->count_per_lane = 0;
313 return rc;
314}
315
316static int dsi_phy_settings_deinit(struct msm_dsi_phy *phy)
317{
318 memset(&phy->cfg.lanecfg, 0x0, sizeof(phy->cfg.lanecfg));
319 memset(&phy->cfg.strength, 0x0, sizeof(phy->cfg.strength));
320 memset(&phy->cfg.timing, 0x0, sizeof(phy->cfg.timing));
321 memset(&phy->cfg.regulators, 0x0, sizeof(phy->cfg.regulators));
322 return 0;
323}
324
325static int dsi_phy_driver_probe(struct platform_device *pdev)
326{
327 struct msm_dsi_phy *dsi_phy;
328 struct dsi_phy_list_item *item;
329 const struct of_device_id *id;
330 const struct dsi_ver_spec_info *ver_info;
331 int rc = 0;
332 u32 index = 0;
333
334 if (!pdev || !pdev->dev.of_node) {
335 pr_err("pdev not found\n");
336 return -ENODEV;
337 }
338
339 id = of_match_node(msm_dsi_phy_of_match, pdev->dev.of_node);
340 if (!id)
341 return -ENODEV;
342
343 ver_info = id->data;
344
345 item = devm_kzalloc(&pdev->dev, sizeof(*item), GFP_KERNEL);
346 if (!item)
347 return -ENOMEM;
348
349
350 dsi_phy = devm_kzalloc(&pdev->dev, sizeof(*dsi_phy), GFP_KERNEL);
351 if (!dsi_phy) {
352 devm_kfree(&pdev->dev, item);
353 return -ENOMEM;
354 }
355
356 rc = of_property_read_u32(pdev->dev.of_node, "cell-index", &index);
357 if (rc) {
358 pr_debug("cell index not set, default to 0\n");
359 index = 0;
360 }
361
362 dsi_phy->index = index;
363
364 dsi_phy->name = of_get_property(pdev->dev.of_node, "label", NULL);
365 if (!dsi_phy->name)
366 dsi_phy->name = DSI_PHY_DEFAULT_LABEL;
367
368 pr_debug("Probing %s device\n", dsi_phy->name);
369
370 rc = dsi_phy_regmap_init(pdev, dsi_phy);
371 if (rc) {
372 pr_err("Failed to parse register information, rc=%d\n", rc);
373 goto fail;
374 }
375
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700376 rc = dsi_phy_supplies_init(pdev, dsi_phy);
377 if (rc) {
378 pr_err("failed to parse voltage supplies, rc = %d\n", rc);
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +0530379 goto fail_regmap;
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700380 }
381
382 rc = dsi_catalog_phy_setup(&dsi_phy->hw, ver_info->version,
383 dsi_phy->index);
384 if (rc) {
385 pr_err("Catalog does not support version (%d)\n",
386 ver_info->version);
387 goto fail_supplies;
388 }
389
390 dsi_phy->ver_info = ver_info;
391 rc = dsi_phy_settings_init(pdev, dsi_phy);
392 if (rc) {
393 pr_err("Failed to parse phy setting, rc=%d\n", rc);
394 goto fail_supplies;
395 }
396
397 item->phy = dsi_phy;
398
399 mutex_lock(&dsi_phy_list_lock);
400 list_add(&item->list, &dsi_phy_list);
401 mutex_unlock(&dsi_phy_list_lock);
402
403 mutex_init(&dsi_phy->phy_lock);
404 /** TODO: initialize debugfs */
405 dsi_phy->pdev = pdev;
406 platform_set_drvdata(pdev, dsi_phy);
Shashank Babu Chinta Venkata2f24e982017-04-21 14:57:53 -0700407 pr_info("Probe successful for %s\n", dsi_phy->name);
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700408 return 0;
409
410fail_supplies:
411 (void)dsi_phy_supplies_deinit(dsi_phy);
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700412fail_regmap:
413 (void)dsi_phy_regmap_deinit(dsi_phy);
414fail:
415 devm_kfree(&pdev->dev, dsi_phy);
416 devm_kfree(&pdev->dev, item);
417 return rc;
418}
419
420static int dsi_phy_driver_remove(struct platform_device *pdev)
421{
422 int rc = 0;
423 struct msm_dsi_phy *phy = platform_get_drvdata(pdev);
424 struct list_head *pos, *tmp;
425
426 if (!pdev || !phy) {
427 pr_err("Invalid device\n");
428 return -EINVAL;
429 }
430
431 mutex_lock(&dsi_phy_list_lock);
432 list_for_each_safe(pos, tmp, &dsi_phy_list) {
433 struct dsi_phy_list_item *n;
434
435 n = list_entry(pos, struct dsi_phy_list_item, list);
436 if (n->phy == phy) {
437 list_del(&n->list);
438 devm_kfree(&pdev->dev, n);
439 break;
440 }
441 }
442 mutex_unlock(&dsi_phy_list_lock);
443
444 mutex_lock(&phy->phy_lock);
445 rc = dsi_phy_settings_deinit(phy);
446 if (rc)
447 pr_err("failed to deinitialize phy settings, rc=%d\n", rc);
448
449 rc = dsi_phy_supplies_deinit(phy);
450 if (rc)
451 pr_err("failed to deinitialize voltage supplies, rc=%d\n", rc);
452
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700453 rc = dsi_phy_regmap_deinit(phy);
454 if (rc)
455 pr_err("failed to deinitialize regmap, rc=%d\n", rc);
456 mutex_unlock(&phy->phy_lock);
457
458 mutex_destroy(&phy->phy_lock);
459 devm_kfree(&pdev->dev, phy);
460
461 platform_set_drvdata(pdev, NULL);
462
463 return 0;
464}
465
466static struct platform_driver dsi_phy_platform_driver = {
467 .probe = dsi_phy_driver_probe,
468 .remove = dsi_phy_driver_remove,
469 .driver = {
Ajay Singh Parmar64c19192016-06-10 16:44:56 -0700470 .name = "dsi_phy",
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700471 .of_match_table = msm_dsi_phy_of_match,
472 },
473};
474
475static void dsi_phy_enable_hw(struct msm_dsi_phy *phy)
476{
477 if (phy->hw.ops.regulator_enable)
478 phy->hw.ops.regulator_enable(&phy->hw, &phy->cfg.regulators);
479
480 if (phy->hw.ops.enable)
481 phy->hw.ops.enable(&phy->hw, &phy->cfg);
482}
483
484static void dsi_phy_disable_hw(struct msm_dsi_phy *phy)
485{
486 if (phy->hw.ops.disable)
Padmanabhan Komanduru56611ef2016-12-19 12:21:11 +0530487 phy->hw.ops.disable(&phy->hw, &phy->cfg);
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700488
489 if (phy->hw.ops.regulator_disable)
490 phy->hw.ops.regulator_disable(&phy->hw);
491}
492
493/**
494 * dsi_phy_get() - get a dsi phy handle from device node
495 * @of_node: device node for dsi phy controller
496 *
497 * Gets the DSI PHY handle for the corresponding of_node. The ref count is
498 * incremented to one all subsequents get will fail until the original client
499 * calls a put.
500 *
501 * Return: DSI PHY handle or an error code.
502 */
503struct msm_dsi_phy *dsi_phy_get(struct device_node *of_node)
504{
505 struct list_head *pos, *tmp;
506 struct msm_dsi_phy *phy = NULL;
507
508 mutex_lock(&dsi_phy_list_lock);
509 list_for_each_safe(pos, tmp, &dsi_phy_list) {
510 struct dsi_phy_list_item *n;
511
512 n = list_entry(pos, struct dsi_phy_list_item, list);
513 if (n->phy->pdev->dev.of_node == of_node) {
514 phy = n->phy;
515 break;
516 }
517 }
518 mutex_unlock(&dsi_phy_list_lock);
519
520 if (!phy) {
521 pr_err("Device with of node not found\n");
522 phy = ERR_PTR(-EPROBE_DEFER);
523 return phy;
524 }
525
526 mutex_lock(&phy->phy_lock);
527 if (phy->refcount > 0) {
528 pr_err("[PHY_%d] Device under use\n", phy->index);
529 phy = ERR_PTR(-EINVAL);
530 } else {
531 phy->refcount++;
532 }
533 mutex_unlock(&phy->phy_lock);
534 return phy;
535}
536
537/**
538 * dsi_phy_put() - release dsi phy handle
539 * @dsi_phy: DSI PHY handle.
540 *
541 * Release the DSI PHY hardware. Driver will clean up all resources and puts
542 * back the DSI PHY into reset state.
543 */
544void dsi_phy_put(struct msm_dsi_phy *dsi_phy)
545{
546 mutex_lock(&dsi_phy->phy_lock);
547
548 if (dsi_phy->refcount == 0)
549 pr_err("Unbalanced dsi_phy_put call\n");
550 else
551 dsi_phy->refcount--;
552
553 mutex_unlock(&dsi_phy->phy_lock);
554}
555
556/**
557 * dsi_phy_drv_init() - initialize dsi phy driver
558 * @dsi_phy: DSI PHY handle.
559 *
560 * Initializes DSI PHY driver. Should be called after dsi_phy_get().
561 *
562 * Return: error code.
563 */
564int dsi_phy_drv_init(struct msm_dsi_phy *dsi_phy)
565{
Dhaval Patela2430842017-06-15 14:32:36 -0700566 char dbg_name[DSI_DEBUG_NAME_LEN];
567
568 snprintf(dbg_name, DSI_DEBUG_NAME_LEN, "dsi%d_phy", dsi_phy->index);
569 sde_dbg_reg_register_base(dbg_name, dsi_phy->hw.base,
570 msm_iomap_size(dsi_phy->pdev, "dsi_phy"));
Sandeep Panda440b33a2018-05-10 22:25:03 +0530571 sde_dbg_reg_register_dump_range(dbg_name, dbg_name, 0,
572 msm_iomap_size(dsi_phy->pdev, "dsi_phy"), 0);
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700573 return 0;
574}
575
576/**
577 * dsi_phy_drv_deinit() - de-initialize dsi phy driver
578 * @dsi_phy: DSI PHY handle.
579 *
580 * Release all resources acquired by dsi_phy_drv_init().
581 *
582 * Return: error code.
583 */
584int dsi_phy_drv_deinit(struct msm_dsi_phy *dsi_phy)
585{
586 return 0;
587}
588
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +0530589int dsi_phy_clk_cb_register(struct msm_dsi_phy *dsi_phy,
590 struct clk_ctrl_cb *clk_cb)
591{
592 if (!dsi_phy || !clk_cb) {
593 pr_err("Invalid params\n");
594 return -EINVAL;
595 }
596
597 dsi_phy->clk_cb.priv = clk_cb->priv;
598 dsi_phy->clk_cb.dsi_clk_cb = clk_cb->dsi_clk_cb;
599 return 0;
600}
601
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700602/**
603 * dsi_phy_validate_mode() - validate a display mode
604 * @dsi_phy: DSI PHY handle.
605 * @mode: Mode information.
606 *
607 * Validation will fail if the mode cannot be supported by the PHY driver or
608 * hardware.
609 *
610 * Return: error code.
611 */
612int dsi_phy_validate_mode(struct msm_dsi_phy *dsi_phy,
613 struct dsi_mode_info *mode)
614{
615 int rc = 0;
616
617 if (!dsi_phy || !mode) {
618 pr_err("Invalid params\n");
619 return -EINVAL;
620 }
621
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700622 pr_debug("[PHY_%d] Skipping validation\n", dsi_phy->index);
623
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700624 return rc;
625}
626
627/**
628 * dsi_phy_set_power_state() - enable/disable dsi phy power supplies
629 * @dsi_phy: DSI PHY handle.
630 * @enable: Boolean flag to enable/disable.
631 *
632 * Return: error code.
633 */
634int dsi_phy_set_power_state(struct msm_dsi_phy *dsi_phy, bool enable)
635{
636 int rc = 0;
637
638 if (!dsi_phy) {
639 pr_err("Invalid params\n");
640 return -EINVAL;
641 }
642
643 mutex_lock(&dsi_phy->phy_lock);
644
645 if (enable == dsi_phy->power_state) {
646 pr_err("[PHY_%d] No state change\n", dsi_phy->index);
647 goto error;
648 }
649
650 if (enable) {
651 rc = dsi_pwr_enable_regulator(&dsi_phy->pwr_info.digital, true);
652 if (rc) {
653 pr_err("failed to enable digital regulator\n");
654 goto error;
655 }
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +0530656
Alan Kwong60cc3552017-11-01 22:08:48 -0400657 if (dsi_phy->dsi_phy_state == DSI_PHY_ENGINE_OFF &&
658 dsi_phy->regulator_required) {
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +0530659 rc = dsi_pwr_enable_regulator(
660 &dsi_phy->pwr_info.phy_pwr, true);
661 if (rc) {
662 pr_err("failed to enable phy power\n");
663 (void)dsi_pwr_enable_regulator(
664 &dsi_phy->pwr_info.digital, false);
665 goto error;
666 }
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700667 }
668 } else {
Vara Reddyeda08c02017-12-08 17:54:10 -0800669 if (dsi_phy->dsi_phy_state == DSI_PHY_ENGINE_OFF &&
Alan Kwong60cc3552017-11-01 22:08:48 -0400670 dsi_phy->regulator_required) {
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +0530671 rc = dsi_pwr_enable_regulator(
672 &dsi_phy->pwr_info.phy_pwr, false);
673 if (rc) {
674 pr_err("failed to enable digital regulator\n");
675 goto error;
676 }
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700677 }
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +0530678
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700679 rc = dsi_pwr_enable_regulator(&dsi_phy->pwr_info.digital,
680 false);
681 if (rc) {
682 pr_err("failed to enable phy power\n");
683 goto error;
684 }
685 }
686
687 dsi_phy->power_state = enable;
688error:
689 mutex_unlock(&dsi_phy->phy_lock);
690 return rc;
691}
692
Padmanabhan Komanduru56611ef2016-12-19 12:21:11 +0530693static int dsi_phy_enable_ulps(struct msm_dsi_phy *phy,
Veera Sundaram Sankaranbb3680f2017-04-21 13:20:46 -0700694 struct dsi_host_config *config, bool clamp_enabled)
Padmanabhan Komanduru56611ef2016-12-19 12:21:11 +0530695{
696 int rc = 0;
697 u32 lanes = 0;
698 u32 ulps_lanes;
699
Sandeep Panda9d6948c2018-02-02 11:17:04 +0530700 lanes = config->common_config.data_lanes;
Padmanabhan Komanduru56611ef2016-12-19 12:21:11 +0530701 lanes |= DSI_CLOCK_LANE;
702
Veera Sundaram Sankaranbb3680f2017-04-21 13:20:46 -0700703 /*
704 * If DSI clamps are enabled, it means that the DSI lanes are
705 * already in idle state. Checking for lanes to be in idle state
706 * should be skipped during ULPS entry programming while coming
707 * out of idle screen.
708 */
709 if (!clamp_enabled) {
710 rc = phy->hw.ops.ulps_ops.wait_for_lane_idle(&phy->hw, lanes);
711 if (rc) {
712 pr_err("lanes not entering idle, skip ULPS\n");
713 return rc;
714 }
Padmanabhan Komanduru56611ef2016-12-19 12:21:11 +0530715 }
716
717 phy->hw.ops.ulps_ops.ulps_request(&phy->hw, &phy->cfg, lanes);
718
719 ulps_lanes = phy->hw.ops.ulps_ops.get_lanes_in_ulps(&phy->hw);
720
Veera Sundaram Sankaranbb3680f2017-04-21 13:20:46 -0700721 if (!phy->hw.ops.ulps_ops.is_lanes_in_ulps(lanes, ulps_lanes)) {
Padmanabhan Komanduru56611ef2016-12-19 12:21:11 +0530722 pr_err("Failed to enter ULPS, request=0x%x, actual=0x%x\n",
723 lanes, ulps_lanes);
724 rc = -EIO;
725 }
726
727 return rc;
728}
729
730static int dsi_phy_disable_ulps(struct msm_dsi_phy *phy,
731 struct dsi_host_config *config)
732{
Padmanabhan Komanduru56611ef2016-12-19 12:21:11 +0530733 u32 ulps_lanes, lanes = 0;
734
Sandeep Panda9d6948c2018-02-02 11:17:04 +0530735 lanes = config->common_config.data_lanes;
Padmanabhan Komanduru56611ef2016-12-19 12:21:11 +0530736 lanes |= DSI_CLOCK_LANE;
737
738 ulps_lanes = phy->hw.ops.ulps_ops.get_lanes_in_ulps(&phy->hw);
739
Veera Sundaram Sankaranbb3680f2017-04-21 13:20:46 -0700740 if (!phy->hw.ops.ulps_ops.is_lanes_in_ulps(lanes, ulps_lanes)) {
741 pr_err("Mismatch in ULPS: lanes:%d, ulps_lanes:%d\n",
742 lanes, ulps_lanes);
743 return -EIO;
744 }
Padmanabhan Komanduru56611ef2016-12-19 12:21:11 +0530745
746 phy->hw.ops.ulps_ops.ulps_exit(&phy->hw, &phy->cfg, lanes);
747
748 ulps_lanes = phy->hw.ops.ulps_ops.get_lanes_in_ulps(&phy->hw);
Veera Sundaram Sankaranbb3680f2017-04-21 13:20:46 -0700749
750 if (phy->hw.ops.ulps_ops.is_lanes_in_ulps(lanes, ulps_lanes)) {
Padmanabhan Komanduru56611ef2016-12-19 12:21:11 +0530751 pr_err("Lanes (0x%x) stuck in ULPS\n", ulps_lanes);
Veera Sundaram Sankaranbb3680f2017-04-21 13:20:46 -0700752 return -EIO;
Padmanabhan Komanduru56611ef2016-12-19 12:21:11 +0530753 }
754
Veera Sundaram Sankaranbb3680f2017-04-21 13:20:46 -0700755 return 0;
Padmanabhan Komanduru56611ef2016-12-19 12:21:11 +0530756}
757
Aravind Venkateswaranb3fc3a02018-03-05 16:09:05 -0800758void dsi_phy_toggle_resync_fifo(struct msm_dsi_phy *phy)
759{
760 if (!phy)
761 return;
762
763 if (!phy->hw.ops.toggle_resync_fifo)
764 return;
765
766 phy->hw.ops.toggle_resync_fifo(&phy->hw);
767}
Padmanabhan Komanduru56611ef2016-12-19 12:21:11 +0530768
769int dsi_phy_set_ulps(struct msm_dsi_phy *phy, struct dsi_host_config *config,
Veera Sundaram Sankaranbb3680f2017-04-21 13:20:46 -0700770 bool enable, bool clamp_enabled)
Padmanabhan Komanduru56611ef2016-12-19 12:21:11 +0530771{
772 int rc = 0;
773
774 if (!phy) {
775 pr_err("Invalid params\n");
776 return -EINVAL;
777 }
778
779 if (!phy->hw.ops.ulps_ops.ulps_request ||
Veera Sundaram Sankaranbb3680f2017-04-21 13:20:46 -0700780 !phy->hw.ops.ulps_ops.ulps_exit ||
781 !phy->hw.ops.ulps_ops.get_lanes_in_ulps ||
782 !phy->hw.ops.ulps_ops.is_lanes_in_ulps ||
783 !phy->hw.ops.ulps_ops.wait_for_lane_idle) {
Padmanabhan Komanduru56611ef2016-12-19 12:21:11 +0530784 pr_debug("DSI PHY ULPS ops not present\n");
785 return 0;
786 }
787
788 mutex_lock(&phy->phy_lock);
789
790 if (enable)
Veera Sundaram Sankaranbb3680f2017-04-21 13:20:46 -0700791 rc = dsi_phy_enable_ulps(phy, config, clamp_enabled);
Padmanabhan Komanduru56611ef2016-12-19 12:21:11 +0530792 else
793 rc = dsi_phy_disable_ulps(phy, config);
794
795 if (rc) {
796 pr_err("[DSI_PHY%d] Ulps state change(%d) failed, rc=%d\n",
797 phy->index, enable, rc);
798 goto error;
799 }
800 pr_debug("[DSI_PHY%d] ULPS state = %d\n", phy->index, enable);
801
802error:
803 mutex_unlock(&phy->phy_lock);
804 return rc;
805}
806
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700807/**
808 * dsi_phy_enable() - enable DSI PHY hardware
809 * @dsi_phy: DSI PHY handle.
810 * @config: DSI host configuration.
811 * @pll_source: Source PLL for PHY clock.
812 * @skip_validation: Validation will not be performed on parameters.
Shashank Babu Chinta Venkata7d608732017-05-31 14:10:26 -0700813 * @is_cont_splash_enabled: check whether continuous splash enabled.
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700814 *
815 * Validates and enables DSI PHY.
816 *
817 * Return: error code.
818 */
819int dsi_phy_enable(struct msm_dsi_phy *phy,
820 struct dsi_host_config *config,
821 enum dsi_phy_pll_source pll_source,
Shashank Babu Chinta Venkata7d608732017-05-31 14:10:26 -0700822 bool skip_validation,
823 bool is_cont_splash_enabled)
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700824{
825 int rc = 0;
826
827 if (!phy || !config) {
828 pr_err("Invalid params\n");
829 return -EINVAL;
830 }
831
832 mutex_lock(&phy->phy_lock);
833
834 if (!skip_validation)
835 pr_debug("[PHY_%d] TODO: perform validation\n", phy->index);
836
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700837 memcpy(&phy->mode, &config->video_timing, sizeof(phy->mode));
Padmanabhan Komanduru8ee8ee52016-12-19 12:10:51 +0530838 memcpy(&phy->cfg.lane_map, &config->lane_map, sizeof(config->lane_map));
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700839 phy->data_lanes = config->common_config.data_lanes;
840 phy->dst_format = config->common_config.dst_format;
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700841 phy->cfg.pll_source = pll_source;
842
Padmanabhan Komanduruee89d212016-12-19 12:51:31 +0530843 /**
844 * If PHY timing parameters are not present in panel dtsi file,
845 * then calculate them in the driver
846 */
847 if (!phy->cfg.is_phy_timing_present)
848 rc = phy->hw.ops.calculate_timing_params(&phy->hw,
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700849 &phy->mode,
850 &config->common_config,
Sandeep Panda97c89dd2018-10-25 15:49:16 +0530851 &phy->cfg.timing, false);
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700852 if (rc) {
853 pr_err("[%s] failed to set timing, rc=%d\n", phy->name, rc);
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +0530854 goto error;
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700855 }
856
Shashank Babu Chinta Venkata7d608732017-05-31 14:10:26 -0700857 if (!is_cont_splash_enabled) {
858 dsi_phy_enable_hw(phy);
859 pr_debug("cont splash not enabled, phy enable required\n");
860 }
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +0530861 phy->dsi_phy_state = DSI_PHY_ENGINE_ON;
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700862
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700863error:
864 mutex_unlock(&phy->phy_lock);
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +0530865
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700866 return rc;
867}
868
Sandeep Panda97c89dd2018-10-25 15:49:16 +0530869/* update dsi phy timings for dynamic clk switch use case */
870int dsi_phy_update_phy_timings(struct msm_dsi_phy *phy,
871 struct dsi_host_config *config)
872{
873 int rc = 0;
874
875 if (!phy || !config) {
876 pr_err("invalid argument\n");
877 return -EINVAL;
878 }
879
880 memcpy(&phy->mode, &config->video_timing, sizeof(phy->mode));
881 rc = phy->hw.ops.calculate_timing_params(&phy->hw, &phy->mode,
882 &config->common_config,
883 &phy->cfg.timing, true);
884 if (rc)
885 pr_err("failed to calculate phy timings %d\n", rc);
Sandeep Pandaaf198a92019-03-07 19:33:15 +0530886 else
887 phy->cfg.is_phy_timing_present = true;
Sandeep Panda97c89dd2018-10-25 15:49:16 +0530888
889 return rc;
890}
891
Sandeep Panda11b20d82017-06-19 12:57:27 +0530892int dsi_phy_lane_reset(struct msm_dsi_phy *phy)
893{
894 int ret = 0;
895
896 if (!phy)
897 return ret;
898
899 mutex_lock(&phy->phy_lock);
900 if (phy->hw.ops.phy_lane_reset)
901 ret = phy->hw.ops.phy_lane_reset(&phy->hw);
902 mutex_unlock(&phy->phy_lock);
903
904 return ret;
905}
906
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700907/**
908 * dsi_phy_disable() - disable DSI PHY hardware.
909 * @phy: DSI PHY handle.
910 *
911 * Return: error code.
912 */
913int dsi_phy_disable(struct msm_dsi_phy *phy)
914{
915 int rc = 0;
916
917 if (!phy) {
918 pr_err("Invalid params\n");
919 return -EINVAL;
920 }
921
922 mutex_lock(&phy->phy_lock);
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700923 dsi_phy_disable_hw(phy);
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +0530924 phy->dsi_phy_state = DSI_PHY_ENGINE_OFF;
925 mutex_unlock(&phy->phy_lock);
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700926
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +0530927 return rc;
928}
929
930/**
Aravind Venkateswaran1769bed2018-05-14 17:15:17 -0700931 * dsi_phy_set_clamp_state() - configure clamps for DSI lanes
932 * @phy: DSI PHY handle.
933 * @enable: boolean to specify clamp enable/disable.
934 *
935 * Return: error code.
936 */
937int dsi_phy_set_clamp_state(struct msm_dsi_phy *phy, bool enable)
938{
939 if (!phy)
940 return -EINVAL;
941
942 pr_debug("[%s] enable=%d\n", phy->name, enable);
943
944 if (phy->hw.ops.clamp_ctrl)
945 phy->hw.ops.clamp_ctrl(&phy->hw, enable);
946
947 return 0;
948}
949
950/**
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +0530951 * dsi_phy_idle_ctrl() - enable/disable DSI PHY during idle screen
952 * @phy: DSI PHY handle
953 * @enable: boolean to specify PHY enable/disable.
954 *
955 * Return: error code.
956 */
957
958int dsi_phy_idle_ctrl(struct msm_dsi_phy *phy, bool enable)
959{
960 if (!phy) {
961 pr_err("Invalid params\n");
962 return -EINVAL;
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700963 }
964
Alan Kwong797e0892017-10-17 09:37:24 -0400965 pr_debug("[%s] enable=%d\n", phy->name, enable);
966
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +0530967 mutex_lock(&phy->phy_lock);
968 if (enable) {
969 if (phy->hw.ops.phy_idle_on)
970 phy->hw.ops.phy_idle_on(&phy->hw, &phy->cfg);
971
972 if (phy->hw.ops.regulator_enable)
973 phy->hw.ops.regulator_enable(&phy->hw,
974 &phy->cfg.regulators);
Alan Kwong797e0892017-10-17 09:37:24 -0400975
976 if (phy->hw.ops.enable)
977 phy->hw.ops.enable(&phy->hw, &phy->cfg);
978
979 phy->dsi_phy_state = DSI_PHY_ENGINE_ON;
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +0530980 } else {
Alan Kwong797e0892017-10-17 09:37:24 -0400981 phy->dsi_phy_state = DSI_PHY_ENGINE_OFF;
982
983 if (phy->hw.ops.disable)
984 phy->hw.ops.disable(&phy->hw, &phy->cfg);
985
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +0530986 if (phy->hw.ops.phy_idle_off)
987 phy->hw.ops.phy_idle_off(&phy->hw);
988 }
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700989 mutex_unlock(&phy->phy_lock);
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +0530990
991 return 0;
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700992}
993
994/**
Alan Kwong60cc3552017-11-01 22:08:48 -0400995 * dsi_phy_set_clk_freq() - set DSI PHY clock frequency setting
996 * @phy: DSI PHY handle
997 * @clk_freq: link clock frequency
998 *
999 * Return: error code.
1000 */
1001int dsi_phy_set_clk_freq(struct msm_dsi_phy *phy,
1002 struct link_clk_freq *clk_freq)
1003{
1004 if (!phy || !clk_freq) {
1005 pr_err("Invalid params\n");
1006 return -EINVAL;
1007 }
1008
1009 phy->regulator_required = clk_freq->byte_clk_rate >
1010 (phy->regulator_min_datarate_bps / BITS_PER_BYTE);
1011
Vara Reddy9cc3f932017-11-22 13:26:31 -08001012 /*
1013 * DSI PLL needs 0p9 LDO1A for Powering DSI PLL block.
1014 * PLL driver can vote for this regulator in PLL driver file, but for
1015 * the usecase where we come out of idle(static screen), if PLL and
1016 * PHY vote for regulator ,there will be performance delays as both
1017 * votes go through RPM to enable regulators.
1018 */
1019 phy->regulator_required = true;
Alan Kwong60cc3552017-11-01 22:08:48 -04001020 pr_debug("[%s] lane_datarate=%u min_datarate=%u required=%d\n",
1021 phy->name,
1022 clk_freq->byte_clk_rate * BITS_PER_BYTE,
1023 phy->regulator_min_datarate_bps,
1024 phy->regulator_required);
1025
1026 return 0;
1027}
1028
1029/**
Ajay Singh Parmar67f31322016-06-22 17:37:56 -07001030 * dsi_phy_set_timing_params() - timing parameters for the panel
1031 * @phy: DSI PHY handle
1032 * @timing: array holding timing params.
1033 * @size: size of the array.
1034 *
1035 * When PHY timing calculator is not implemented, this array will be used to
1036 * pass PHY timing information.
1037 *
1038 * Return: error code.
1039 */
1040int dsi_phy_set_timing_params(struct msm_dsi_phy *phy,
Padmanabhan Komanduruee89d212016-12-19 12:51:31 +05301041 u32 *timing, u32 size)
Ajay Singh Parmar67f31322016-06-22 17:37:56 -07001042{
1043 int rc = 0;
Ajay Singh Parmar67f31322016-06-22 17:37:56 -07001044
1045 if (!phy || !timing || !size) {
1046 pr_err("Invalid params\n");
1047 return -EINVAL;
1048 }
1049
Sandeep Pandaaf198a92019-03-07 19:33:15 +05301050 if (phy->cfg.is_phy_timing_present)
1051 return rc;
1052
Ajay Singh Parmar67f31322016-06-22 17:37:56 -07001053 mutex_lock(&phy->phy_lock);
1054
Padmanabhan Komanduruee89d212016-12-19 12:51:31 +05301055 if (phy->hw.ops.phy_timing_val)
1056 rc = phy->hw.ops.phy_timing_val(&phy->cfg.timing, timing, size);
1057 if (!rc)
1058 phy->cfg.is_phy_timing_present = true;
Sandeep Panda97c89dd2018-10-25 15:49:16 +05301059
Ajay Singh Parmar67f31322016-06-22 17:37:56 -07001060 mutex_unlock(&phy->phy_lock);
1061 return rc;
1062}
1063
Sandeep Panda97c89dd2018-10-25 15:49:16 +05301064/**
1065 * dsi_phy_dynamic_refresh_trigger() - trigger dynamic refresh
1066 * @phy: DSI PHY handle
1067 * @is_master: Boolean to indicate if for master or slave.
1068 */
1069void dsi_phy_dynamic_refresh_trigger(struct msm_dsi_phy *phy, bool is_master)
1070{
1071 u32 off;
1072
1073 if (!phy)
1074 return;
1075
1076 mutex_lock(&phy->phy_lock);
1077 /*
1078 * program PLL_SWI_INTF_SEL and SW_TRIGGER bit only for
1079 * master and program SYNC_MODE bit only for slave.
1080 */
1081 if (is_master)
1082 off = BIT(DYN_REFRESH_INTF_SEL) | BIT(DYN_REFRESH_SWI_CTRL) |
1083 BIT(DYN_REFRESH_SW_TRIGGER);
1084 else
1085 off = BIT(DYN_REFRESH_SYNC_MODE) | BIT(DYN_REFRESH_SWI_CTRL);
1086
1087 if (phy->hw.ops.dyn_refresh_ops.dyn_refresh_helper)
1088 phy->hw.ops.dyn_refresh_ops.dyn_refresh_helper(&phy->hw, off);
1089
1090 mutex_unlock(&phy->phy_lock);
1091}
1092
1093/**
1094 * dsi_phy_config_dynamic_refresh() - Configure dynamic refresh registers
1095 * @phy: DSI PHY handle
1096 * @delay: pipe delays for dynamic refresh
1097 * @is_master: Boolean to indicate if for master or slave.
1098 */
1099void dsi_phy_config_dynamic_refresh(struct msm_dsi_phy *phy,
1100 struct dsi_dyn_clk_delay *delay,
1101 bool is_master)
1102{
1103 struct dsi_phy_cfg *cfg;
1104
1105 if (!phy)
1106 return;
1107
1108 mutex_lock(&phy->phy_lock);
1109
1110 cfg = &phy->cfg;
1111
1112 if (phy->hw.ops.dyn_refresh_ops.dyn_refresh_config)
1113 phy->hw.ops.dyn_refresh_ops.dyn_refresh_config(&phy->hw, cfg,
1114 is_master);
1115 if (phy->hw.ops.dyn_refresh_ops.dyn_refresh_pipe_delay)
1116 phy->hw.ops.dyn_refresh_ops.dyn_refresh_pipe_delay(
1117 &phy->hw, delay);
1118
1119 mutex_unlock(&phy->phy_lock);
1120}
1121
1122/**
1123 * dsi_phy_cache_phy_timings - cache the phy timings calculated as part of
1124 * dynamic refresh.
1125 * @phy: DSI PHY Handle.
1126 * @dst: Pointer to cache location.
1127 * @size: Number of phy lane settings.
1128 */
1129int dsi_phy_dyn_refresh_cache_phy_timings(struct msm_dsi_phy *phy, u32 *dst,
1130 u32 size)
1131{
1132 int rc = 0;
1133
1134 if (!phy || !dst || !size)
1135 return -EINVAL;
1136
1137 if (phy->hw.ops.dyn_refresh_ops.cache_phy_timings)
1138 rc = phy->hw.ops.dyn_refresh_ops.cache_phy_timings(
1139 &phy->cfg.timing, dst, size);
1140
1141 if (rc)
1142 pr_err("failed to cache phy timings %d\n", rc);
1143
1144 return rc;
1145}
1146
1147/**
1148 * dsi_phy_dynamic_refresh_clear() - clear dynamic refresh config
1149 * @phy: DSI PHY handle
1150 */
1151void dsi_phy_dynamic_refresh_clear(struct msm_dsi_phy *phy)
1152{
1153 if (!phy)
1154 return;
1155
1156 mutex_lock(&phy->phy_lock);
1157
1158 if (phy->hw.ops.dyn_refresh_ops.dyn_refresh_helper)
1159 phy->hw.ops.dyn_refresh_ops.dyn_refresh_helper(&phy->hw, 0);
1160
1161 mutex_unlock(&phy->phy_lock);
1162}
1163
Ajay Singh Parmar64c19192016-06-10 16:44:56 -07001164void dsi_phy_drv_register(void)
Ajay Singh Parmar67f31322016-06-22 17:37:56 -07001165{
1166 platform_driver_register(&dsi_phy_platform_driver);
1167}
1168
Ajay Singh Parmar64c19192016-06-10 16:44:56 -07001169void dsi_phy_drv_unregister(void)
Ajay Singh Parmar67f31322016-06-22 17:37:56 -07001170{
1171 platform_driver_unregister(&dsi_phy_platform_driver);
1172}