aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/msm/dsi/dsi_manager.c
diff options
context:
space:
mode:
authorHai Li <hali@codeaurora.org>2017-01-07 03:54:38 -0500
committerRob Clark <robdclark@gmail.com>2017-02-06 11:28:45 -0500
commitb62aa70a98c5401ada63657eee7c88da70bdbb27 (patch)
treef4e2363af3d9bcfc03743939ae0fd8f981192a26 /drivers/gpu/drm/msm/dsi/dsi_manager.c
parent34d9545b9f769c6553e31a6820c9cb51f5e93099 (diff)
drm/msm/dsi: Move PHY operations out of host
Since DSI PHY has been a separate platform device, it should not depend on the resources in host to be functional. This change is to trigger PHY operations in manager, instead of host, so that host and PHY can be completely separated. Signed-off-by: Hai Li <hali@codeaurora.org> Signed-off-by: Archit Taneja <architt@codeaurora.org> Signed-off-by: Rob Clark <robdclark@gmail.com>
Diffstat (limited to 'drivers/gpu/drm/msm/dsi/dsi_manager.c')
-rw-r--r--drivers/gpu/drm/msm/dsi/dsi_manager.c178
1 files changed, 105 insertions, 73 deletions
diff --git a/drivers/gpu/drm/msm/dsi/dsi_manager.c b/drivers/gpu/drm/msm/dsi/dsi_manager.c
index cb67e78d775b..921270ea6059 100644
--- a/drivers/gpu/drm/msm/dsi/dsi_manager.c
+++ b/drivers/gpu/drm/msm/dsi/dsi_manager.c
@@ -125,6 +125,84 @@ static int dsi_mgr_setup_components(int id)
125 return ret; 125 return ret;
126} 126}
127 127
128static int enable_phy(struct msm_dsi *msm_dsi, int src_pll_id,
129 struct msm_dsi_phy_shared_timings *shared_timings)
130{
131 struct msm_dsi_phy_clk_request clk_req;
132 int ret;
133
134 msm_dsi_host_get_phy_clk_req(msm_dsi->host, &clk_req);
135
136 ret = msm_dsi_phy_enable(msm_dsi->phy, src_pll_id, &clk_req);
137 msm_dsi_phy_get_shared_timings(msm_dsi->phy, shared_timings);
138
139 return ret;
140}
141
142static int
143dsi_mgr_phy_enable(int id,
144 struct msm_dsi_phy_shared_timings shared_timings[DSI_MAX])
145{
146 struct msm_dsi *msm_dsi = dsi_mgr_get_dsi(id);
147 struct msm_dsi *mdsi = dsi_mgr_get_dsi(DSI_CLOCK_MASTER);
148 struct msm_dsi *sdsi = dsi_mgr_get_dsi(DSI_CLOCK_SLAVE);
149 int src_pll_id = IS_DUAL_DSI() ? DSI_CLOCK_MASTER : id;
150 int ret;
151
152 /* In case of dual DSI, some registers in PHY1 have been programmed
153 * during PLL0 clock's set_rate. The PHY1 reset called by host1 here
154 * will silently reset those PHY1 registers. Therefore we need to reset
155 * and enable both PHYs before any PLL clock operation.
156 */
157 if (IS_DUAL_DSI() && mdsi && sdsi) {
158 if (!mdsi->phy_enabled && !sdsi->phy_enabled) {
159 msm_dsi_host_reset_phy(mdsi->host);
160 msm_dsi_host_reset_phy(sdsi->host);
161
162 ret = enable_phy(mdsi, src_pll_id,
163 &shared_timings[DSI_CLOCK_MASTER]);
164 if (ret)
165 return ret;
166 ret = enable_phy(sdsi, src_pll_id,
167 &shared_timings[DSI_CLOCK_SLAVE]);
168 if (ret) {
169 msm_dsi_phy_disable(mdsi->phy);
170 return ret;
171 }
172 }
173 } else {
174 msm_dsi_host_reset_phy(mdsi->host);
175 ret = enable_phy(msm_dsi, src_pll_id, &shared_timings[id]);
176 if (ret)
177 return ret;
178 }
179
180 msm_dsi->phy_enabled = true;
181
182 return 0;
183}
184
185static void dsi_mgr_phy_disable(int id)
186{
187 struct msm_dsi *msm_dsi = dsi_mgr_get_dsi(id);
188 struct msm_dsi *mdsi = dsi_mgr_get_dsi(DSI_CLOCK_MASTER);
189 struct msm_dsi *sdsi = dsi_mgr_get_dsi(DSI_CLOCK_SLAVE);
190
191 /* disable DSI phy
192 * In dual-dsi configuration, the phy should be disabled for the
193 * first controller only when the second controller is disabled.
194 */
195 msm_dsi->phy_enabled = false;
196 if (IS_DUAL_DSI() && mdsi && sdsi) {
197 if (!mdsi->phy_enabled && !sdsi->phy_enabled) {
198 msm_dsi_phy_disable(sdsi->phy);
199 msm_dsi_phy_disable(mdsi->phy);
200 }
201 } else {
202 msm_dsi_phy_disable(msm_dsi->phy);
203 }
204}
205
128struct dsi_connector { 206struct dsi_connector {
129 struct drm_connector base; 207 struct drm_connector base;
130 int id; 208 int id;
@@ -360,22 +438,31 @@ static void dsi_mgr_bridge_pre_enable(struct drm_bridge *bridge)
360 struct msm_dsi *msm_dsi1 = dsi_mgr_get_dsi(DSI_1); 438 struct msm_dsi *msm_dsi1 = dsi_mgr_get_dsi(DSI_1);
361 struct mipi_dsi_host *host = msm_dsi->host; 439 struct mipi_dsi_host *host = msm_dsi->host;
362 struct drm_panel *panel = msm_dsi->panel; 440 struct drm_panel *panel = msm_dsi->panel;
441 struct msm_dsi_phy_shared_timings phy_shared_timings[DSI_MAX];
363 bool is_dual_dsi = IS_DUAL_DSI(); 442 bool is_dual_dsi = IS_DUAL_DSI();
364 int ret; 443 int ret;
365 444
366 DBG("id=%d", id); 445 DBG("id=%d", id);
367 if (!msm_dsi_device_connected(msm_dsi) || 446 if (!msm_dsi_device_connected(msm_dsi))
368 (is_dual_dsi && (DSI_1 == id)))
369 return; 447 return;
370 448
371 ret = msm_dsi_host_power_on(host); 449 ret = dsi_mgr_phy_enable(id, phy_shared_timings);
450 if (ret)
451 goto phy_en_fail;
452
453 /* Do nothing with the host if it is DSI 1 in case of dual DSI */
454 if (is_dual_dsi && (DSI_1 == id))
455 return;
456
457 ret = msm_dsi_host_power_on(host, &phy_shared_timings[id]);
372 if (ret) { 458 if (ret) {
373 pr_err("%s: power on host %d failed, %d\n", __func__, id, ret); 459 pr_err("%s: power on host %d failed, %d\n", __func__, id, ret);
374 goto host_on_fail; 460 goto host_on_fail;
375 } 461 }
376 462
377 if (is_dual_dsi && msm_dsi1) { 463 if (is_dual_dsi && msm_dsi1) {
378 ret = msm_dsi_host_power_on(msm_dsi1->host); 464 ret = msm_dsi_host_power_on(msm_dsi1->host,
465 &phy_shared_timings[DSI_1]);
379 if (ret) { 466 if (ret) {
380 pr_err("%s: power on host1 failed, %d\n", 467 pr_err("%s: power on host1 failed, %d\n",
381 __func__, ret); 468 __func__, ret);
@@ -434,6 +521,8 @@ panel_prep_fail:
434host1_on_fail: 521host1_on_fail:
435 msm_dsi_host_power_off(host); 522 msm_dsi_host_power_off(host);
436host_on_fail: 523host_on_fail:
524 dsi_mgr_phy_disable(id);
525phy_en_fail:
437 return; 526 return;
438} 527}
439 528
@@ -459,10 +548,17 @@ static void dsi_mgr_bridge_post_disable(struct drm_bridge *bridge)
459 548
460 DBG("id=%d", id); 549 DBG("id=%d", id);
461 550
462 if (!msm_dsi_device_connected(msm_dsi) || 551 if (!msm_dsi_device_connected(msm_dsi))
463 (is_dual_dsi && (DSI_1 == id)))
464 return; 552 return;
465 553
554 /*
555 * Do nothing with the host if it is DSI 1 in case of dual DSI.
556 * It is safe to call dsi_mgr_phy_disable() here because a single PHY
557 * won't be diabled until both PHYs request disable.
558 */
559 if (is_dual_dsi && (DSI_1 == id))
560 goto disable_phy;
561
466 if (panel) { 562 if (panel) {
467 ret = drm_panel_disable(panel); 563 ret = drm_panel_disable(panel);
468 if (ret) 564 if (ret)
@@ -497,6 +593,9 @@ static void dsi_mgr_bridge_post_disable(struct drm_bridge *bridge)
497 pr_err("%s: host1 power off failed, %d\n", 593 pr_err("%s: host1 power off failed, %d\n",
498 __func__, ret); 594 __func__, ret);
499 } 595 }
596
597disable_phy:
598 dsi_mgr_phy_disable(id);
500} 599}
501 600
502static void dsi_mgr_bridge_mode_set(struct drm_bridge *bridge, 601static void dsi_mgr_bridge_mode_set(struct drm_bridge *bridge,
@@ -664,73 +763,6 @@ void msm_dsi_manager_bridge_destroy(struct drm_bridge *bridge)
664{ 763{
665} 764}
666 765
667int msm_dsi_manager_phy_enable(int id,
668 const unsigned long bit_rate, const unsigned long esc_rate,
669 struct msm_dsi_phy_shared_timings *shared_timings)
670{
671 struct msm_dsi *msm_dsi = dsi_mgr_get_dsi(id);
672 struct msm_dsi *mdsi = dsi_mgr_get_dsi(DSI_CLOCK_MASTER);
673 struct msm_dsi *sdsi = dsi_mgr_get_dsi(DSI_CLOCK_SLAVE);
674 struct msm_dsi_phy *phy = msm_dsi->phy;
675 int src_pll_id = IS_DUAL_DSI() ? DSI_CLOCK_MASTER : id;
676 int ret;
677
678 /* In case of dual DSI, some registers in PHY1 have been programmed
679 * during PLL0 clock's set_rate. The PHY1 reset called by host1 here
680 * will silently reset those PHY1 registers. Therefore we need to reset
681 * and enable both PHYs before any PLL clock operation.
682 */
683 if (IS_DUAL_DSI() && mdsi && sdsi) {
684 if (!mdsi->phy_enabled && !sdsi->phy_enabled) {
685 msm_dsi_host_reset_phy(mdsi->host);
686 msm_dsi_host_reset_phy(sdsi->host);
687 ret = msm_dsi_phy_enable(mdsi->phy, src_pll_id,
688 bit_rate, esc_rate);
689 if (ret)
690 return ret;
691 ret = msm_dsi_phy_enable(sdsi->phy, src_pll_id,
692 bit_rate, esc_rate);
693 if (ret) {
694 msm_dsi_phy_disable(mdsi->phy);
695 return ret;
696 }
697 }
698 } else {
699 msm_dsi_host_reset_phy(msm_dsi->host);
700 ret = msm_dsi_phy_enable(msm_dsi->phy, src_pll_id, bit_rate,
701 esc_rate);
702 if (ret)
703 return ret;
704 }
705
706 msm_dsi->phy_enabled = true;
707 msm_dsi_phy_get_shared_timings(phy, shared_timings);
708
709 return 0;
710}
711
712void msm_dsi_manager_phy_disable(int id)
713{
714 struct msm_dsi *msm_dsi = dsi_mgr_get_dsi(id);
715 struct msm_dsi *mdsi = dsi_mgr_get_dsi(DSI_CLOCK_MASTER);
716 struct msm_dsi *sdsi = dsi_mgr_get_dsi(DSI_CLOCK_SLAVE);
717 struct msm_dsi_phy *phy = msm_dsi->phy;
718
719 /* disable DSI phy
720 * In dual-dsi configuration, the phy should be disabled for the
721 * first controller only when the second controller is disabled.
722 */
723 msm_dsi->phy_enabled = false;
724 if (IS_DUAL_DSI() && mdsi && sdsi) {
725 if (!mdsi->phy_enabled && !sdsi->phy_enabled) {
726 msm_dsi_phy_disable(sdsi->phy);
727 msm_dsi_phy_disable(mdsi->phy);
728 }
729 } else {
730 msm_dsi_phy_disable(phy);
731 }
732}
733
734int msm_dsi_manager_cmd_xfer(int id, const struct mipi_dsi_msg *msg) 766int msm_dsi_manager_cmd_xfer(int id, const struct mipi_dsi_msg *msg)
735{ 767{
736 struct msm_dsi *msm_dsi = dsi_mgr_get_dsi(id); 768 struct msm_dsi *msm_dsi = dsi_mgr_get_dsi(id);