1
2
3
4
5
6#include <drm/drm_crtc.h>
7#include <drm/drm_probe_helper.h>
8
9#include "mdp5_kms.h"
10
11static struct mdp5_kms *get_kms(struct drm_encoder *encoder)
12{
13 struct msm_drm_private *priv = encoder->dev->dev_private;
14 return to_mdp5_kms(to_mdp_kms(priv->kms));
15}
16
17#define VSYNC_CLK_RATE 19200000
18static int pingpong_tearcheck_setup(struct drm_encoder *encoder,
19 struct drm_display_mode *mode)
20{
21 struct mdp5_kms *mdp5_kms = get_kms(encoder);
22 struct device *dev = encoder->dev->dev;
23 u32 total_lines_x100, vclks_line, cfg;
24 long vsync_clk_speed;
25 struct mdp5_hw_mixer *mixer = mdp5_crtc_get_mixer(encoder->crtc);
26 int pp_id = mixer->pp;
27
28 if (IS_ERR_OR_NULL(mdp5_kms->vsync_clk)) {
29 DRM_DEV_ERROR(dev, "vsync_clk is not initialized\n");
30 return -EINVAL;
31 }
32
33 total_lines_x100 = mode->vtotal * drm_mode_vrefresh(mode);
34 if (!total_lines_x100) {
35 DRM_DEV_ERROR(dev, "%s: vtotal(%d) or vrefresh(%d) is 0\n",
36 __func__, mode->vtotal, drm_mode_vrefresh(mode));
37 return -EINVAL;
38 }
39
40 vsync_clk_speed = clk_round_rate(mdp5_kms->vsync_clk, VSYNC_CLK_RATE);
41 if (vsync_clk_speed <= 0) {
42 DRM_DEV_ERROR(dev, "vsync_clk round rate failed %ld\n",
43 vsync_clk_speed);
44 return -EINVAL;
45 }
46 vclks_line = vsync_clk_speed * 100 / total_lines_x100;
47
48 cfg = MDP5_PP_SYNC_CONFIG_VSYNC_COUNTER_EN
49 | MDP5_PP_SYNC_CONFIG_VSYNC_IN_EN;
50 cfg |= MDP5_PP_SYNC_CONFIG_VSYNC_COUNT(vclks_line);
51
52 mdp5_write(mdp5_kms, REG_MDP5_PP_SYNC_CONFIG_VSYNC(pp_id), cfg);
53 mdp5_write(mdp5_kms,
54 REG_MDP5_PP_SYNC_CONFIG_HEIGHT(pp_id), 0xfff0);
55 mdp5_write(mdp5_kms,
56 REG_MDP5_PP_VSYNC_INIT_VAL(pp_id), mode->vdisplay);
57 mdp5_write(mdp5_kms, REG_MDP5_PP_RD_PTR_IRQ(pp_id), mode->vdisplay + 1);
58 mdp5_write(mdp5_kms, REG_MDP5_PP_START_POS(pp_id), mode->vdisplay);
59 mdp5_write(mdp5_kms, REG_MDP5_PP_SYNC_THRESH(pp_id),
60 MDP5_PP_SYNC_THRESH_START(4) |
61 MDP5_PP_SYNC_THRESH_CONTINUE(4));
62
63 return 0;
64}
65
66static int pingpong_tearcheck_enable(struct drm_encoder *encoder)
67{
68 struct mdp5_kms *mdp5_kms = get_kms(encoder);
69 struct mdp5_hw_mixer *mixer = mdp5_crtc_get_mixer(encoder->crtc);
70 int pp_id = mixer->pp;
71 int ret;
72
73 ret = clk_set_rate(mdp5_kms->vsync_clk,
74 clk_round_rate(mdp5_kms->vsync_clk, VSYNC_CLK_RATE));
75 if (ret) {
76 DRM_DEV_ERROR(encoder->dev->dev,
77 "vsync_clk clk_set_rate failed, %d\n", ret);
78 return ret;
79 }
80 ret = clk_prepare_enable(mdp5_kms->vsync_clk);
81 if (ret) {
82 DRM_DEV_ERROR(encoder->dev->dev,
83 "vsync_clk clk_prepare_enable failed, %d\n", ret);
84 return ret;
85 }
86
87 mdp5_write(mdp5_kms, REG_MDP5_PP_TEAR_CHECK_EN(pp_id), 1);
88
89 return 0;
90}
91
92static void pingpong_tearcheck_disable(struct drm_encoder *encoder)
93{
94 struct mdp5_kms *mdp5_kms = get_kms(encoder);
95 struct mdp5_hw_mixer *mixer = mdp5_crtc_get_mixer(encoder->crtc);
96 int pp_id = mixer->pp;
97
98 mdp5_write(mdp5_kms, REG_MDP5_PP_TEAR_CHECK_EN(pp_id), 0);
99 clk_disable_unprepare(mdp5_kms->vsync_clk);
100}
101
102void mdp5_cmd_encoder_mode_set(struct drm_encoder *encoder,
103 struct drm_display_mode *mode,
104 struct drm_display_mode *adjusted_mode)
105{
106 mode = adjusted_mode;
107
108 DBG("set mode: " DRM_MODE_FMT, DRM_MODE_ARG(mode));
109 pingpong_tearcheck_setup(encoder, mode);
110 mdp5_crtc_set_pipeline(encoder->crtc);
111}
112
113void mdp5_cmd_encoder_disable(struct drm_encoder *encoder)
114{
115 struct mdp5_encoder *mdp5_cmd_enc = to_mdp5_encoder(encoder);
116 struct mdp5_ctl *ctl = mdp5_cmd_enc->ctl;
117 struct mdp5_interface *intf = mdp5_cmd_enc->intf;
118 struct mdp5_pipeline *pipeline = mdp5_crtc_get_pipeline(encoder->crtc);
119
120 if (WARN_ON(!mdp5_cmd_enc->enabled))
121 return;
122
123 pingpong_tearcheck_disable(encoder);
124
125 mdp5_ctl_set_encoder_state(ctl, pipeline, false);
126 mdp5_ctl_commit(ctl, pipeline, mdp_ctl_flush_mask_encoder(intf), true);
127
128 mdp5_cmd_enc->enabled = false;
129}
130
131void mdp5_cmd_encoder_enable(struct drm_encoder *encoder)
132{
133 struct mdp5_encoder *mdp5_cmd_enc = to_mdp5_encoder(encoder);
134 struct mdp5_ctl *ctl = mdp5_cmd_enc->ctl;
135 struct mdp5_interface *intf = mdp5_cmd_enc->intf;
136 struct mdp5_pipeline *pipeline = mdp5_crtc_get_pipeline(encoder->crtc);
137
138 if (WARN_ON(mdp5_cmd_enc->enabled))
139 return;
140
141 if (pingpong_tearcheck_enable(encoder))
142 return;
143
144 mdp5_ctl_commit(ctl, pipeline, mdp_ctl_flush_mask_encoder(intf), true);
145
146 mdp5_ctl_set_encoder_state(ctl, pipeline, true);
147
148 mdp5_cmd_enc->enabled = true;
149}
150
151int mdp5_cmd_encoder_set_split_display(struct drm_encoder *encoder,
152 struct drm_encoder *slave_encoder)
153{
154 struct mdp5_encoder *mdp5_cmd_enc = to_mdp5_encoder(encoder);
155 struct mdp5_kms *mdp5_kms;
156 struct device *dev;
157 int intf_num;
158 u32 data = 0;
159
160 if (!encoder || !slave_encoder)
161 return -EINVAL;
162
163 mdp5_kms = get_kms(encoder);
164 intf_num = mdp5_cmd_enc->intf->num;
165
166
167
168
169 if (intf_num == 1)
170 data |= MDP5_SPLIT_DPL_UPPER_INTF2_SW_TRG_MUX;
171 else if (intf_num == 2)
172 data |= MDP5_SPLIT_DPL_UPPER_INTF1_SW_TRG_MUX;
173 else
174 return -EINVAL;
175
176
177 data |= MDP5_SPLIT_DPL_UPPER_SMART_PANEL;
178
179 dev = &mdp5_kms->pdev->dev;
180
181
182 pm_runtime_get_sync(dev);
183 mdp5_write(mdp5_kms, REG_MDP5_SPLIT_DPL_UPPER, data);
184
185 mdp5_write(mdp5_kms, REG_MDP5_SPLIT_DPL_LOWER,
186 MDP5_SPLIT_DPL_LOWER_SMART_PANEL);
187 mdp5_write(mdp5_kms, REG_MDP5_SPLIT_DPL_EN, 1);
188 pm_runtime_put_sync(dev);
189
190 return 0;
191}
192