Merge tag 'io_uring-5.11-2021-01-16' of git://git.kernel.dk/linux-block
[linux/fpc-iii.git] / drivers / gpu / drm / msm / disp / mdp5 / mdp5_cmd_encoder.c
blobff2c1d583c7922a6c57f98910c658098b6eaef76
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3 * Copyright (c) 2015, The Linux Foundation. All rights reserved.
4 */
6 #include <drm/drm_crtc.h>
7 #include <drm/drm_probe_helper.h>
9 #include "mdp5_kms.h"
11 static struct mdp5_kms *get_kms(struct drm_encoder *encoder)
13 struct msm_drm_private *priv = encoder->dev->dev_private;
14 return to_mdp5_kms(to_mdp_kms(priv->kms));
17 #define VSYNC_CLK_RATE 19200000
18 static int pingpong_tearcheck_setup(struct drm_encoder *encoder,
19 struct drm_display_mode *mode)
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;
28 if (IS_ERR_OR_NULL(mdp5_kms->vsync_clk)) {
29 DRM_DEV_ERROR(dev, "vsync_clk is not initialized\n");
30 return -EINVAL;
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;
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;
46 vclks_line = vsync_clk_speed * 100 / total_lines_x100;
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);
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));
63 return 0;
66 static int pingpong_tearcheck_enable(struct drm_encoder *encoder)
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;
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;
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;
87 mdp5_write(mdp5_kms, REG_MDP5_PP_TEAR_CHECK_EN(pp_id), 1);
89 return 0;
92 static void pingpong_tearcheck_disable(struct drm_encoder *encoder)
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;
98 mdp5_write(mdp5_kms, REG_MDP5_PP_TEAR_CHECK_EN(pp_id), 0);
99 clk_disable_unprepare(mdp5_kms->vsync_clk);
102 void mdp5_cmd_encoder_mode_set(struct drm_encoder *encoder,
103 struct drm_display_mode *mode,
104 struct drm_display_mode *adjusted_mode)
106 mode = adjusted_mode;
108 DBG("set mode: " DRM_MODE_FMT, DRM_MODE_ARG(mode));
109 pingpong_tearcheck_setup(encoder, mode);
110 mdp5_crtc_set_pipeline(encoder->crtc);
113 void mdp5_cmd_encoder_disable(struct drm_encoder *encoder)
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);
120 if (WARN_ON(!mdp5_cmd_enc->enabled))
121 return;
123 pingpong_tearcheck_disable(encoder);
125 mdp5_ctl_set_encoder_state(ctl, pipeline, false);
126 mdp5_ctl_commit(ctl, pipeline, mdp_ctl_flush_mask_encoder(intf), true);
128 mdp5_cmd_enc->enabled = false;
131 void mdp5_cmd_encoder_enable(struct drm_encoder *encoder)
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);
138 if (WARN_ON(mdp5_cmd_enc->enabled))
139 return;
141 if (pingpong_tearcheck_enable(encoder))
142 return;
144 mdp5_ctl_commit(ctl, pipeline, mdp_ctl_flush_mask_encoder(intf), true);
146 mdp5_ctl_set_encoder_state(ctl, pipeline, true);
148 mdp5_cmd_enc->enabled = true;
151 int mdp5_cmd_encoder_set_split_display(struct drm_encoder *encoder,
152 struct drm_encoder *slave_encoder)
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;
160 if (!encoder || !slave_encoder)
161 return -EINVAL;
163 mdp5_kms = get_kms(encoder);
164 intf_num = mdp5_cmd_enc->intf->num;
166 /* Switch slave encoder's trigger MUX, to use the master's
167 * start signal for the slave encoder
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;
176 /* Smart Panel, Sync mode */
177 data |= MDP5_SPLIT_DPL_UPPER_SMART_PANEL;
179 dev = &mdp5_kms->pdev->dev;
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);
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);
190 return 0;