blob: 3d6711fd33e981680728406e93a669e692ad15b6 [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"));
Sandeep Panda440b33a2018-05-10 22:25:03 +0530568 sde_dbg_reg_register_dump_range(dbg_name, dbg_name, 0,
569 msm_iomap_size(dsi_phy->pdev, "dsi_phy"), 0);
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700570 return 0;
571}
572
573/**
574 * dsi_phy_drv_deinit() - de-initialize dsi phy driver
575 * @dsi_phy: DSI PHY handle.
576 *
577 * Release all resources acquired by dsi_phy_drv_init().
578 *
579 * Return: error code.
580 */
581int dsi_phy_drv_deinit(struct msm_dsi_phy *dsi_phy)
582{
583 return 0;
584}
585
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +0530586int dsi_phy_clk_cb_register(struct msm_dsi_phy *dsi_phy,
587 struct clk_ctrl_cb *clk_cb)
588{
589 if (!dsi_phy || !clk_cb) {
590 pr_err("Invalid params\n");
591 return -EINVAL;
592 }
593
594 dsi_phy->clk_cb.priv = clk_cb->priv;
595 dsi_phy->clk_cb.dsi_clk_cb = clk_cb->dsi_clk_cb;
596 return 0;
597}
598
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700599/**
600 * dsi_phy_validate_mode() - validate a display mode
601 * @dsi_phy: DSI PHY handle.
602 * @mode: Mode information.
603 *
604 * Validation will fail if the mode cannot be supported by the PHY driver or
605 * hardware.
606 *
607 * Return: error code.
608 */
609int dsi_phy_validate_mode(struct msm_dsi_phy *dsi_phy,
610 struct dsi_mode_info *mode)
611{
612 int rc = 0;
613
614 if (!dsi_phy || !mode) {
615 pr_err("Invalid params\n");
616 return -EINVAL;
617 }
618
619 mutex_lock(&dsi_phy->phy_lock);
620
621 pr_debug("[PHY_%d] Skipping validation\n", dsi_phy->index);
622
623 mutex_unlock(&dsi_phy->phy_lock);
624 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,
851 &phy->cfg.timing);
852 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 Panda11b20d82017-06-19 12:57:27 +0530869int dsi_phy_lane_reset(struct msm_dsi_phy *phy)
870{
871 int ret = 0;
872
873 if (!phy)
874 return ret;
875
876 mutex_lock(&phy->phy_lock);
877 if (phy->hw.ops.phy_lane_reset)
878 ret = phy->hw.ops.phy_lane_reset(&phy->hw);
879 mutex_unlock(&phy->phy_lock);
880
881 return ret;
882}
883
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700884/**
885 * dsi_phy_disable() - disable DSI PHY hardware.
886 * @phy: DSI PHY handle.
887 *
888 * Return: error code.
889 */
890int dsi_phy_disable(struct msm_dsi_phy *phy)
891{
892 int rc = 0;
893
894 if (!phy) {
895 pr_err("Invalid params\n");
896 return -EINVAL;
897 }
898
899 mutex_lock(&phy->phy_lock);
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700900 dsi_phy_disable_hw(phy);
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +0530901 phy->dsi_phy_state = DSI_PHY_ENGINE_OFF;
902 mutex_unlock(&phy->phy_lock);
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700903
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +0530904 return rc;
905}
906
907/**
Aravind Venkateswaran1769bed2018-05-14 17:15:17 -0700908 * dsi_phy_set_clamp_state() - configure clamps for DSI lanes
909 * @phy: DSI PHY handle.
910 * @enable: boolean to specify clamp enable/disable.
911 *
912 * Return: error code.
913 */
914int dsi_phy_set_clamp_state(struct msm_dsi_phy *phy, bool enable)
915{
916 if (!phy)
917 return -EINVAL;
918
919 pr_debug("[%s] enable=%d\n", phy->name, enable);
920
921 if (phy->hw.ops.clamp_ctrl)
922 phy->hw.ops.clamp_ctrl(&phy->hw, enable);
923
924 return 0;
925}
926
927/**
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +0530928 * dsi_phy_idle_ctrl() - enable/disable DSI PHY during idle screen
929 * @phy: DSI PHY handle
930 * @enable: boolean to specify PHY enable/disable.
931 *
932 * Return: error code.
933 */
934
935int dsi_phy_idle_ctrl(struct msm_dsi_phy *phy, bool enable)
936{
937 if (!phy) {
938 pr_err("Invalid params\n");
939 return -EINVAL;
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700940 }
941
Alan Kwong797e0892017-10-17 09:37:24 -0400942 pr_debug("[%s] enable=%d\n", phy->name, enable);
943
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +0530944 mutex_lock(&phy->phy_lock);
945 if (enable) {
946 if (phy->hw.ops.phy_idle_on)
947 phy->hw.ops.phy_idle_on(&phy->hw, &phy->cfg);
948
949 if (phy->hw.ops.regulator_enable)
950 phy->hw.ops.regulator_enable(&phy->hw,
951 &phy->cfg.regulators);
Alan Kwong797e0892017-10-17 09:37:24 -0400952
953 if (phy->hw.ops.enable)
954 phy->hw.ops.enable(&phy->hw, &phy->cfg);
955
956 phy->dsi_phy_state = DSI_PHY_ENGINE_ON;
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +0530957 } else {
Alan Kwong797e0892017-10-17 09:37:24 -0400958 phy->dsi_phy_state = DSI_PHY_ENGINE_OFF;
959
960 if (phy->hw.ops.disable)
961 phy->hw.ops.disable(&phy->hw, &phy->cfg);
962
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +0530963 if (phy->hw.ops.phy_idle_off)
964 phy->hw.ops.phy_idle_off(&phy->hw);
965 }
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700966 mutex_unlock(&phy->phy_lock);
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +0530967
968 return 0;
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700969}
970
971/**
Alan Kwong60cc3552017-11-01 22:08:48 -0400972 * dsi_phy_set_clk_freq() - set DSI PHY clock frequency setting
973 * @phy: DSI PHY handle
974 * @clk_freq: link clock frequency
975 *
976 * Return: error code.
977 */
978int dsi_phy_set_clk_freq(struct msm_dsi_phy *phy,
979 struct link_clk_freq *clk_freq)
980{
981 if (!phy || !clk_freq) {
982 pr_err("Invalid params\n");
983 return -EINVAL;
984 }
985
986 phy->regulator_required = clk_freq->byte_clk_rate >
987 (phy->regulator_min_datarate_bps / BITS_PER_BYTE);
988
Vara Reddy9cc3f932017-11-22 13:26:31 -0800989 /*
990 * DSI PLL needs 0p9 LDO1A for Powering DSI PLL block.
991 * PLL driver can vote for this regulator in PLL driver file, but for
992 * the usecase where we come out of idle(static screen), if PLL and
993 * PHY vote for regulator ,there will be performance delays as both
994 * votes go through RPM to enable regulators.
995 */
996 phy->regulator_required = true;
Alan Kwong60cc3552017-11-01 22:08:48 -0400997 pr_debug("[%s] lane_datarate=%u min_datarate=%u required=%d\n",
998 phy->name,
999 clk_freq->byte_clk_rate * BITS_PER_BYTE,
1000 phy->regulator_min_datarate_bps,
1001 phy->regulator_required);
1002
1003 return 0;
1004}
1005
1006/**
Ajay Singh Parmar67f31322016-06-22 17:37:56 -07001007 * dsi_phy_set_timing_params() - timing parameters for the panel
1008 * @phy: DSI PHY handle
1009 * @timing: array holding timing params.
1010 * @size: size of the array.
1011 *
1012 * When PHY timing calculator is not implemented, this array will be used to
1013 * pass PHY timing information.
1014 *
1015 * Return: error code.
1016 */
1017int dsi_phy_set_timing_params(struct msm_dsi_phy *phy,
Padmanabhan Komanduruee89d212016-12-19 12:51:31 +05301018 u32 *timing, u32 size)
Ajay Singh Parmar67f31322016-06-22 17:37:56 -07001019{
1020 int rc = 0;
Ajay Singh Parmar67f31322016-06-22 17:37:56 -07001021
1022 if (!phy || !timing || !size) {
1023 pr_err("Invalid params\n");
1024 return -EINVAL;
1025 }
1026
1027 mutex_lock(&phy->phy_lock);
1028
Padmanabhan Komanduruee89d212016-12-19 12:51:31 +05301029 if (phy->hw.ops.phy_timing_val)
1030 rc = phy->hw.ops.phy_timing_val(&phy->cfg.timing, timing, size);
1031 if (!rc)
1032 phy->cfg.is_phy_timing_present = true;
Ajay Singh Parmar67f31322016-06-22 17:37:56 -07001033 mutex_unlock(&phy->phy_lock);
1034 return rc;
1035}
1036
Ajay Singh Parmar64c19192016-06-10 16:44:56 -07001037void dsi_phy_drv_register(void)
Ajay Singh Parmar67f31322016-06-22 17:37:56 -07001038{
1039 platform_driver_register(&dsi_phy_platform_driver);
1040}
1041
Ajay Singh Parmar64c19192016-06-10 16:44:56 -07001042void dsi_phy_drv_unregister(void)
Ajay Singh Parmar67f31322016-06-22 17:37:56 -07001043{
1044 platform_driver_unregister(&dsi_phy_platform_driver);
1045}