These changes are the raw update to linux-4.4.6-rt14. Kernel sources
[kvmfornfv.git] / kernel / drivers / gpu / drm / msm / mdp / mdp5 / mdp5_cmd_encoder.c
1 /*
2  * Copyright (c) 2015, The Linux Foundation. All rights reserved.
3  *
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.
7  *
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.
12  */
13
14 #include "mdp5_kms.h"
15
16 #include "drm_crtc.h"
17 #include "drm_crtc_helper.h"
18
19 struct mdp5_cmd_encoder {
20         struct drm_encoder base;
21         struct mdp5_interface intf;
22         bool enabled;
23         uint32_t bsc;
24
25         struct mdp5_ctl *ctl;
26 };
27 #define to_mdp5_cmd_encoder(x) container_of(x, struct mdp5_cmd_encoder, base)
28
29 static struct mdp5_kms *get_kms(struct drm_encoder *encoder)
30 {
31         struct msm_drm_private *priv = encoder->dev->dev_private;
32         return to_mdp5_kms(to_mdp_kms(priv->kms));
33 }
34
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)            \
40         {                                               \
41                 .src = MSM_BUS_MASTER_MDP_PORT0,        \
42                 .dst = MSM_BUS_SLAVE_EBI_CH0,           \
43                 .ab = (ab_val),                         \
44                 .ib = (ib_val),                         \
45         }
46
47 static struct msm_bus_vectors mdp_bus_vectors[] = {
48         MDP_BUS_VECTOR_ENTRY(0, 0),
49         MDP_BUS_VECTOR_ENTRY(2000000000, 2000000000),
50 };
51 static struct msm_bus_paths mdp_bus_usecases[] = { {
52                 .num_paths = 1,
53                 .vectors = &mdp_bus_vectors[0],
54 }, {
55                 .num_paths = 1,
56                 .vectors = &mdp_bus_vectors[1],
57 } };
58 static struct msm_bus_scale_pdata mdp_bus_scale_table = {
59         .usecase = mdp_bus_usecases,
60         .num_usecases = ARRAY_SIZE(mdp_bus_usecases),
61         .name = "mdss_mdp",
62 };
63
64 static void bs_init(struct mdp5_cmd_encoder *mdp5_cmd_enc)
65 {
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);
69 }
70
71 static void bs_fini(struct mdp5_cmd_encoder *mdp5_cmd_enc)
72 {
73         if (mdp5_cmd_enc->bsc) {
74                 msm_bus_scale_unregister_client(mdp5_cmd_enc->bsc);
75                 mdp5_cmd_enc->bsc = 0;
76         }
77 }
78
79 static void bs_set(struct mdp5_cmd_encoder *mdp5_cmd_enc, int idx)
80 {
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
85                  * never disable:
86                  */
87                 idx = 1;
88                 msm_bus_scale_client_update_request(mdp5_cmd_enc->bsc, idx);
89         }
90 }
91 #else
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) {}
95 #endif
96
97 #define VSYNC_CLK_RATE 19200000
98 static int pingpong_tearcheck_setup(struct drm_encoder *encoder,
99                                         struct drm_display_mode *mode)
100 {
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));
106
107         if (IS_ERR_OR_NULL(mdp5_kms->vsync_clk)) {
108                 dev_err(dev, "vsync_clk is not initialized\n");
109                 return -EINVAL;
110         }
111
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);
116                 return -EINVAL;
117         }
118
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",
122                                                         vsync_clk_speed);
123                 return -EINVAL;
124         }
125         vclks_line = vsync_clk_speed * 100 / total_lines_x100;
126
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);
130
131         mdp5_write(mdp5_kms, REG_MDP5_PP_SYNC_CONFIG_VSYNC(pp_id), cfg);
132         mdp5_write(mdp5_kms,
133                 REG_MDP5_PP_SYNC_CONFIG_HEIGHT(pp_id), 0xfff0);
134         mdp5_write(mdp5_kms,
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));
141
142         return 0;
143 }
144
145 static int pingpong_tearcheck_enable(struct drm_encoder *encoder)
146 {
147         struct mdp5_kms *mdp5_kms = get_kms(encoder);
148         int pp_id = GET_PING_PONG_ID(mdp5_crtc_get_lm(encoder->crtc));
149         int ret;
150
151         ret = clk_set_rate(mdp5_kms->vsync_clk,
152                 clk_round_rate(mdp5_kms->vsync_clk, VSYNC_CLK_RATE));
153         if (ret) {
154                 dev_err(encoder->dev->dev,
155                         "vsync_clk clk_set_rate failed, %d\n", ret);
156                 return ret;
157         }
158         ret = clk_prepare_enable(mdp5_kms->vsync_clk);
159         if (ret) {
160                 dev_err(encoder->dev->dev,
161                         "vsync_clk clk_prepare_enable failed, %d\n", ret);
162                 return ret;
163         }
164
165         mdp5_write(mdp5_kms, REG_MDP5_PP_TEAR_CHECK_EN(pp_id), 1);
166
167         return 0;
168 }
169
170 static void pingpong_tearcheck_disable(struct drm_encoder *encoder)
171 {
172         struct mdp5_kms *mdp5_kms = get_kms(encoder);
173         int pp_id = GET_PING_PONG_ID(mdp5_crtc_get_lm(encoder->crtc));
174
175         mdp5_write(mdp5_kms, REG_MDP5_PP_TEAR_CHECK_EN(pp_id), 0);
176         clk_disable_unprepare(mdp5_kms->vsync_clk);
177 }
178
179 static void mdp5_cmd_encoder_destroy(struct drm_encoder *encoder)
180 {
181         struct mdp5_cmd_encoder *mdp5_cmd_enc = to_mdp5_cmd_encoder(encoder);
182         bs_fini(mdp5_cmd_enc);
183         drm_encoder_cleanup(encoder);
184         kfree(mdp5_cmd_enc);
185 }
186
187 static const struct drm_encoder_funcs mdp5_cmd_encoder_funcs = {
188         .destroy = mdp5_cmd_encoder_destroy,
189 };
190
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)
194 {
195         return true;
196 }
197
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)
201 {
202         struct mdp5_cmd_encoder *mdp5_cmd_enc = to_mdp5_cmd_encoder(encoder);
203
204         mode = adjusted_mode;
205
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,
216                                 mdp5_cmd_enc->ctl);
217 }
218
219 static void mdp5_cmd_encoder_disable(struct drm_encoder *encoder)
220 {
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;
224
225         if (WARN_ON(!mdp5_cmd_enc->enabled))
226                 return;
227
228         pingpong_tearcheck_disable(encoder);
229
230         mdp5_ctl_set_encoder_state(ctl, false);
231         mdp5_ctl_commit(ctl, mdp_ctl_flush_mask_encoder(intf));
232
233         bs_set(mdp5_cmd_enc, 0);
234
235         mdp5_cmd_enc->enabled = false;
236 }
237
238 static void mdp5_cmd_encoder_enable(struct drm_encoder *encoder)
239 {
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;
243
244         if (WARN_ON(mdp5_cmd_enc->enabled))
245                 return;
246
247         bs_set(mdp5_cmd_enc, 1);
248         if (pingpong_tearcheck_enable(encoder))
249                 return;
250
251         mdp5_ctl_commit(ctl, mdp_ctl_flush_mask_encoder(intf));
252
253         mdp5_ctl_set_encoder_state(ctl, true);
254
255         mdp5_cmd_enc->enabled = true;
256 }
257
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,
263 };
264
265 int mdp5_cmd_encoder_set_split_display(struct drm_encoder *encoder,
266                                         struct drm_encoder *slave_encoder)
267 {
268         struct mdp5_cmd_encoder *mdp5_cmd_enc = to_mdp5_cmd_encoder(encoder);
269         struct mdp5_kms *mdp5_kms;
270         int intf_num;
271         u32 data = 0;
272
273         if (!encoder || !slave_encoder)
274                 return -EINVAL;
275
276         mdp5_kms = get_kms(encoder);
277         intf_num = mdp5_cmd_enc->intf.num;
278
279         /* Switch slave encoder's trigger MUX, to use the master's
280          * start signal for the slave encoder
281          */
282         if (intf_num == 1)
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;
286         else
287                 return -EINVAL;
288
289         /* Smart Panel, Sync mode */
290         data |= MDP5_MDP_SPLIT_DPL_UPPER_SMART_PANEL;
291
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);
295
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);
300
301         return 0;
302 }
303
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)
307 {
308         struct drm_encoder *encoder = NULL;
309         struct mdp5_cmd_encoder *mdp5_cmd_enc;
310         int ret;
311
312         if (WARN_ON((intf->type != INTF_DSI) &&
313                 (intf->mode != MDP5_INTF_DSI_MODE_COMMAND))) {
314                 ret = -EINVAL;
315                 goto fail;
316         }
317
318         mdp5_cmd_enc = kzalloc(sizeof(*mdp5_cmd_enc), GFP_KERNEL);
319         if (!mdp5_cmd_enc) {
320                 ret = -ENOMEM;
321                 goto fail;
322         }
323
324         memcpy(&mdp5_cmd_enc->intf, intf, sizeof(mdp5_cmd_enc->intf));
325         encoder = &mdp5_cmd_enc->base;
326         mdp5_cmd_enc->ctl = ctl;
327
328         drm_encoder_init(dev, encoder, &mdp5_cmd_encoder_funcs,
329                         DRM_MODE_ENCODER_DSI);
330
331         drm_encoder_helper_add(encoder, &mdp5_cmd_encoder_helper_funcs);
332
333         bs_init(mdp5_cmd_enc);
334
335         return encoder;
336
337 fail:
338         if (encoder)
339                 mdp5_cmd_encoder_destroy(encoder);
340
341         return ERR_PTR(ret);
342 }
343