1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * Copyright (c) 2015, The Linux Foundation. All rights reserved.
4  */
5 
6 #include <drm/drm_crtc.h>
7 #include <drm/drm_probe_helper.h>
8 
9 #include "mdp5_kms.h"
10 
11 static 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
18 static 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 
66 static 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 
92 static 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 
102 void 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 
113 void 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 
131 void 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 
151 int 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 	/* Switch slave encoder's trigger MUX, to use the master's
167 	 * start signal for the slave encoder
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 	/* Smart Panel, Sync mode */
177 	data |= MDP5_SPLIT_DPL_UPPER_SMART_PANEL;
178 
179 	dev = &mdp5_kms->pdev->dev;
180 
181 	/* Make sure clocks are on when connectors calling this function. */
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