2 * Copyright (c) 2015, The Linux Foundation. All rights reserved.
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.
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.
17 #include "drm_crtc_helper.h"
19 struct mdp5_cmd_encoder
{
20 struct drm_encoder base
;
21 struct mdp5_interface intf
;
27 #define to_mdp5_cmd_encoder(x) container_of(x, struct mdp5_cmd_encoder, base)
29 static struct mdp5_kms
*get_kms(struct drm_encoder
*encoder
)
31 struct msm_drm_private
*priv
= encoder
->dev
->dev_private
;
32 return to_mdp5_kms(to_mdp_kms(priv
->kms
));
35 #ifdef DOWNSTREAM_CONFIG_MSM_BUS_SCALING
36 #include <mach/board.h>
37 #include <linux/msm-bus.h>
38 #include <linux/msm-bus-board.h>
39 #define MDP_BUS_VECTOR_ENTRY(ab_val, ib_val) \
41 .src = MSM_BUS_MASTER_MDP_PORT0, \
42 .dst = MSM_BUS_SLAVE_EBI_CH0, \
47 static struct msm_bus_vectors mdp_bus_vectors
[] = {
48 MDP_BUS_VECTOR_ENTRY(0, 0),
49 MDP_BUS_VECTOR_ENTRY(2000000000, 2000000000),
51 static struct msm_bus_paths mdp_bus_usecases
[] = { {
53 .vectors
= &mdp_bus_vectors
[0],
56 .vectors
= &mdp_bus_vectors
[1],
58 static struct msm_bus_scale_pdata mdp_bus_scale_table
= {
59 .usecase
= mdp_bus_usecases
,
60 .num_usecases
= ARRAY_SIZE(mdp_bus_usecases
),
64 static void bs_init(struct mdp5_cmd_encoder
*mdp5_cmd_enc
)
66 mdp5_cmd_enc
->bsc
= msm_bus_scale_register_client(
67 &mdp_bus_scale_table
);
68 DBG("bus scale client: %08x", mdp5_cmd_enc
->bsc
);
71 static void bs_fini(struct mdp5_cmd_encoder
*mdp5_cmd_enc
)
73 if (mdp5_cmd_enc
->bsc
) {
74 msm_bus_scale_unregister_client(mdp5_cmd_enc
->bsc
);
75 mdp5_cmd_enc
->bsc
= 0;
79 static void bs_set(struct mdp5_cmd_encoder
*mdp5_cmd_enc
, int idx
)
81 if (mdp5_cmd_enc
->bsc
) {
82 DBG("set bus scaling: %d", idx
);
83 /* HACK: scaling down, and then immediately back up
84 * seems to leave things broken (underflow).. so
88 msm_bus_scale_client_update_request(mdp5_cmd_enc
->bsc
, idx
);
92 static void bs_init(struct mdp5_cmd_encoder
*mdp5_cmd_enc
) {}
93 static void bs_fini(struct mdp5_cmd_encoder
*mdp5_cmd_enc
) {}
94 static void bs_set(struct mdp5_cmd_encoder
*mdp5_cmd_enc
, int idx
) {}
97 #define VSYNC_CLK_RATE 19200000
98 static int pingpong_tearcheck_setup(struct drm_encoder
*encoder
,
99 struct drm_display_mode
*mode
)
101 struct mdp5_kms
*mdp5_kms
= get_kms(encoder
);
102 struct device
*dev
= encoder
->dev
->dev
;
103 u32 total_lines_x100
, vclks_line
, cfg
;
104 long vsync_clk_speed
;
105 int pp_id
= GET_PING_PONG_ID(mdp5_crtc_get_lm(encoder
->crtc
));
107 if (IS_ERR_OR_NULL(mdp5_kms
->vsync_clk
)) {
108 dev_err(dev
, "vsync_clk is not initialized\n");
112 total_lines_x100
= mode
->vtotal
* mode
->vrefresh
;
113 if (!total_lines_x100
) {
114 dev_err(dev
, "%s: vtotal(%d) or vrefresh(%d) is 0\n",
115 __func__
, mode
->vtotal
, mode
->vrefresh
);
119 vsync_clk_speed
= clk_round_rate(mdp5_kms
->vsync_clk
, VSYNC_CLK_RATE
);
120 if (vsync_clk_speed
<= 0) {
121 dev_err(dev
, "vsync_clk round rate failed %ld\n",
125 vclks_line
= vsync_clk_speed
* 100 / total_lines_x100
;
127 cfg
= MDP5_PP_SYNC_CONFIG_VSYNC_COUNTER_EN
128 | MDP5_PP_SYNC_CONFIG_VSYNC_IN_EN
;
129 cfg
|= MDP5_PP_SYNC_CONFIG_VSYNC_COUNT(vclks_line
);
131 mdp5_write(mdp5_kms
, REG_MDP5_PP_SYNC_CONFIG_VSYNC(pp_id
), cfg
);
133 REG_MDP5_PP_SYNC_CONFIG_HEIGHT(pp_id
), 0xfff0);
135 REG_MDP5_PP_VSYNC_INIT_VAL(pp_id
), mode
->vdisplay
);
136 mdp5_write(mdp5_kms
, REG_MDP5_PP_RD_PTR_IRQ(pp_id
), mode
->vdisplay
+ 1);
137 mdp5_write(mdp5_kms
, REG_MDP5_PP_START_POS(pp_id
), mode
->vdisplay
);
138 mdp5_write(mdp5_kms
, REG_MDP5_PP_SYNC_THRESH(pp_id
),
139 MDP5_PP_SYNC_THRESH_START(4) |
140 MDP5_PP_SYNC_THRESH_CONTINUE(4));
145 static int pingpong_tearcheck_enable(struct drm_encoder
*encoder
)
147 struct mdp5_kms
*mdp5_kms
= get_kms(encoder
);
148 int pp_id
= GET_PING_PONG_ID(mdp5_crtc_get_lm(encoder
->crtc
));
151 ret
= clk_set_rate(mdp5_kms
->vsync_clk
,
152 clk_round_rate(mdp5_kms
->vsync_clk
, VSYNC_CLK_RATE
));
154 dev_err(encoder
->dev
->dev
,
155 "vsync_clk clk_set_rate failed, %d\n", ret
);
158 ret
= clk_prepare_enable(mdp5_kms
->vsync_clk
);
160 dev_err(encoder
->dev
->dev
,
161 "vsync_clk clk_prepare_enable failed, %d\n", ret
);
165 mdp5_write(mdp5_kms
, REG_MDP5_PP_TEAR_CHECK_EN(pp_id
), 1);
170 static void pingpong_tearcheck_disable(struct drm_encoder
*encoder
)
172 struct mdp5_kms
*mdp5_kms
= get_kms(encoder
);
173 int pp_id
= GET_PING_PONG_ID(mdp5_crtc_get_lm(encoder
->crtc
));
175 mdp5_write(mdp5_kms
, REG_MDP5_PP_TEAR_CHECK_EN(pp_id
), 0);
176 clk_disable_unprepare(mdp5_kms
->vsync_clk
);
179 static void mdp5_cmd_encoder_destroy(struct drm_encoder
*encoder
)
181 struct mdp5_cmd_encoder
*mdp5_cmd_enc
= to_mdp5_cmd_encoder(encoder
);
182 bs_fini(mdp5_cmd_enc
);
183 drm_encoder_cleanup(encoder
);
187 static const struct drm_encoder_funcs mdp5_cmd_encoder_funcs
= {
188 .destroy
= mdp5_cmd_encoder_destroy
,
191 static bool mdp5_cmd_encoder_mode_fixup(struct drm_encoder
*encoder
,
192 const struct drm_display_mode
*mode
,
193 struct drm_display_mode
*adjusted_mode
)
198 static void mdp5_cmd_encoder_mode_set(struct drm_encoder
*encoder
,
199 struct drm_display_mode
*mode
,
200 struct drm_display_mode
*adjusted_mode
)
202 struct mdp5_cmd_encoder
*mdp5_cmd_enc
= to_mdp5_cmd_encoder(encoder
);
204 mode
= adjusted_mode
;
206 DBG("set mode: %d:\"%s\" %d %d %d %d %d %d %d %d %d %d 0x%x 0x%x",
207 mode
->base
.id
, mode
->name
,
208 mode
->vrefresh
, mode
->clock
,
209 mode
->hdisplay
, mode
->hsync_start
,
210 mode
->hsync_end
, mode
->htotal
,
211 mode
->vdisplay
, mode
->vsync_start
,
212 mode
->vsync_end
, mode
->vtotal
,
213 mode
->type
, mode
->flags
);
214 pingpong_tearcheck_setup(encoder
, mode
);
215 mdp5_crtc_set_pipeline(encoder
->crtc
, &mdp5_cmd_enc
->intf
,
219 static void mdp5_cmd_encoder_disable(struct drm_encoder
*encoder
)
221 struct mdp5_cmd_encoder
*mdp5_cmd_enc
= to_mdp5_cmd_encoder(encoder
);
222 struct mdp5_ctl
*ctl
= mdp5_cmd_enc
->ctl
;
223 struct mdp5_interface
*intf
= &mdp5_cmd_enc
->intf
;
225 if (WARN_ON(!mdp5_cmd_enc
->enabled
))
228 pingpong_tearcheck_disable(encoder
);
230 mdp5_ctl_set_encoder_state(ctl
, false);
231 mdp5_ctl_commit(ctl
, mdp_ctl_flush_mask_encoder(intf
));
233 bs_set(mdp5_cmd_enc
, 0);
235 mdp5_cmd_enc
->enabled
= false;
238 static void mdp5_cmd_encoder_enable(struct drm_encoder
*encoder
)
240 struct mdp5_cmd_encoder
*mdp5_cmd_enc
= to_mdp5_cmd_encoder(encoder
);
241 struct mdp5_ctl
*ctl
= mdp5_cmd_enc
->ctl
;
242 struct mdp5_interface
*intf
= &mdp5_cmd_enc
->intf
;
244 if (WARN_ON(mdp5_cmd_enc
->enabled
))
247 bs_set(mdp5_cmd_enc
, 1);
248 if (pingpong_tearcheck_enable(encoder
))
251 mdp5_ctl_commit(ctl
, mdp_ctl_flush_mask_encoder(intf
));
253 mdp5_ctl_set_encoder_state(ctl
, true);
255 mdp5_cmd_enc
->enabled
= true;
258 static const struct drm_encoder_helper_funcs mdp5_cmd_encoder_helper_funcs
= {
259 .mode_fixup
= mdp5_cmd_encoder_mode_fixup
,
260 .mode_set
= mdp5_cmd_encoder_mode_set
,
261 .disable
= mdp5_cmd_encoder_disable
,
262 .enable
= mdp5_cmd_encoder_enable
,
265 int mdp5_cmd_encoder_set_split_display(struct drm_encoder
*encoder
,
266 struct drm_encoder
*slave_encoder
)
268 struct mdp5_cmd_encoder
*mdp5_cmd_enc
= to_mdp5_cmd_encoder(encoder
);
269 struct mdp5_kms
*mdp5_kms
;
273 if (!encoder
|| !slave_encoder
)
276 mdp5_kms
= get_kms(encoder
);
277 intf_num
= mdp5_cmd_enc
->intf
.num
;
279 /* Switch slave encoder's trigger MUX, to use the master's
280 * start signal for the slave encoder
283 data
|= MDP5_MDP_SPLIT_DPL_UPPER_INTF2_SW_TRG_MUX
;
284 else if (intf_num
== 2)
285 data
|= MDP5_MDP_SPLIT_DPL_UPPER_INTF1_SW_TRG_MUX
;
289 /* Smart Panel, Sync mode */
290 data
|= MDP5_MDP_SPLIT_DPL_UPPER_SMART_PANEL
;
292 /* Make sure clocks are on when connectors calling this function. */
293 mdp5_enable(mdp5_kms
);
294 mdp5_write(mdp5_kms
, REG_MDP5_MDP_SPLIT_DPL_UPPER(0), data
);
296 mdp5_write(mdp5_kms
, REG_MDP5_MDP_SPLIT_DPL_LOWER(0),
297 MDP5_MDP_SPLIT_DPL_LOWER_SMART_PANEL
);
298 mdp5_write(mdp5_kms
, REG_MDP5_MDP_SPLIT_DPL_EN(0), 1);
299 mdp5_disable(mdp5_kms
);
304 /* initialize command mode encoder */
305 struct drm_encoder
*mdp5_cmd_encoder_init(struct drm_device
*dev
,
306 struct mdp5_interface
*intf
, struct mdp5_ctl
*ctl
)
308 struct drm_encoder
*encoder
= NULL
;
309 struct mdp5_cmd_encoder
*mdp5_cmd_enc
;
312 if (WARN_ON((intf
->type
!= INTF_DSI
) &&
313 (intf
->mode
!= MDP5_INTF_DSI_MODE_COMMAND
))) {
318 mdp5_cmd_enc
= kzalloc(sizeof(*mdp5_cmd_enc
), GFP_KERNEL
);
324 memcpy(&mdp5_cmd_enc
->intf
, intf
, sizeof(mdp5_cmd_enc
->intf
));
325 encoder
= &mdp5_cmd_enc
->base
;
326 mdp5_cmd_enc
->ctl
= ctl
;
328 drm_encoder_init(dev
, encoder
, &mdp5_cmd_encoder_funcs
,
329 DRM_MODE_ENCODER_DSI
);
331 drm_encoder_helper_add(encoder
, &mdp5_cmd_encoder_helper_funcs
);
333 bs_init(mdp5_cmd_enc
);
339 mdp5_cmd_encoder_destroy(encoder
);