Merge tag 'powerpc-4.8-2' of git://git.kernel.org/pub/scm/linux/kernel/git/powerpc...
[cascardo/linux.git] / 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 void mdp5_cmd_encoder_mode_set(struct drm_encoder *encoder,
192                 struct drm_display_mode *mode,
193                 struct drm_display_mode *adjusted_mode)
194 {
195         struct mdp5_cmd_encoder *mdp5_cmd_enc = to_mdp5_cmd_encoder(encoder);
196
197         mode = adjusted_mode;
198
199         DBG("set mode: %d:\"%s\" %d %d %d %d %d %d %d %d %d %d 0x%x 0x%x",
200                         mode->base.id, mode->name,
201                         mode->vrefresh, mode->clock,
202                         mode->hdisplay, mode->hsync_start,
203                         mode->hsync_end, mode->htotal,
204                         mode->vdisplay, mode->vsync_start,
205                         mode->vsync_end, mode->vtotal,
206                         mode->type, mode->flags);
207         pingpong_tearcheck_setup(encoder, mode);
208         mdp5_crtc_set_pipeline(encoder->crtc, &mdp5_cmd_enc->intf,
209                                 mdp5_cmd_enc->ctl);
210 }
211
212 static void mdp5_cmd_encoder_disable(struct drm_encoder *encoder)
213 {
214         struct mdp5_cmd_encoder *mdp5_cmd_enc = to_mdp5_cmd_encoder(encoder);
215         struct mdp5_ctl *ctl = mdp5_cmd_enc->ctl;
216         struct mdp5_interface *intf = &mdp5_cmd_enc->intf;
217
218         if (WARN_ON(!mdp5_cmd_enc->enabled))
219                 return;
220
221         pingpong_tearcheck_disable(encoder);
222
223         mdp5_ctl_set_encoder_state(ctl, false);
224         mdp5_ctl_commit(ctl, mdp_ctl_flush_mask_encoder(intf));
225
226         bs_set(mdp5_cmd_enc, 0);
227
228         mdp5_cmd_enc->enabled = false;
229 }
230
231 static void mdp5_cmd_encoder_enable(struct drm_encoder *encoder)
232 {
233         struct mdp5_cmd_encoder *mdp5_cmd_enc = to_mdp5_cmd_encoder(encoder);
234         struct mdp5_ctl *ctl = mdp5_cmd_enc->ctl;
235         struct mdp5_interface *intf = &mdp5_cmd_enc->intf;
236
237         if (WARN_ON(mdp5_cmd_enc->enabled))
238                 return;
239
240         bs_set(mdp5_cmd_enc, 1);
241         if (pingpong_tearcheck_enable(encoder))
242                 return;
243
244         mdp5_ctl_commit(ctl, mdp_ctl_flush_mask_encoder(intf));
245
246         mdp5_ctl_set_encoder_state(ctl, true);
247
248         mdp5_cmd_enc->enabled = true;
249 }
250
251 static const struct drm_encoder_helper_funcs mdp5_cmd_encoder_helper_funcs = {
252         .mode_set = mdp5_cmd_encoder_mode_set,
253         .disable = mdp5_cmd_encoder_disable,
254         .enable = mdp5_cmd_encoder_enable,
255 };
256
257 int mdp5_cmd_encoder_set_split_display(struct drm_encoder *encoder,
258                                         struct drm_encoder *slave_encoder)
259 {
260         struct mdp5_cmd_encoder *mdp5_cmd_enc = to_mdp5_cmd_encoder(encoder);
261         struct mdp5_kms *mdp5_kms;
262         int intf_num;
263         u32 data = 0;
264
265         if (!encoder || !slave_encoder)
266                 return -EINVAL;
267
268         mdp5_kms = get_kms(encoder);
269         intf_num = mdp5_cmd_enc->intf.num;
270
271         /* Switch slave encoder's trigger MUX, to use the master's
272          * start signal for the slave encoder
273          */
274         if (intf_num == 1)
275                 data |= MDP5_SPLIT_DPL_UPPER_INTF2_SW_TRG_MUX;
276         else if (intf_num == 2)
277                 data |= MDP5_SPLIT_DPL_UPPER_INTF1_SW_TRG_MUX;
278         else
279                 return -EINVAL;
280
281         /* Smart Panel, Sync mode */
282         data |= MDP5_SPLIT_DPL_UPPER_SMART_PANEL;
283
284         /* Make sure clocks are on when connectors calling this function. */
285         mdp5_enable(mdp5_kms);
286         mdp5_write(mdp5_kms, REG_MDP5_SPLIT_DPL_UPPER, data);
287
288         mdp5_write(mdp5_kms, REG_MDP5_SPLIT_DPL_LOWER,
289                    MDP5_SPLIT_DPL_LOWER_SMART_PANEL);
290         mdp5_write(mdp5_kms, REG_MDP5_SPLIT_DPL_EN, 1);
291         mdp5_disable(mdp5_kms);
292
293         return 0;
294 }
295
296 /* initialize command mode encoder */
297 struct drm_encoder *mdp5_cmd_encoder_init(struct drm_device *dev,
298                         struct mdp5_interface *intf, struct mdp5_ctl *ctl)
299 {
300         struct drm_encoder *encoder = NULL;
301         struct mdp5_cmd_encoder *mdp5_cmd_enc;
302         int ret;
303
304         if (WARN_ON((intf->type != INTF_DSI) &&
305                 (intf->mode != MDP5_INTF_DSI_MODE_COMMAND))) {
306                 ret = -EINVAL;
307                 goto fail;
308         }
309
310         mdp5_cmd_enc = kzalloc(sizeof(*mdp5_cmd_enc), GFP_KERNEL);
311         if (!mdp5_cmd_enc) {
312                 ret = -ENOMEM;
313                 goto fail;
314         }
315
316         memcpy(&mdp5_cmd_enc->intf, intf, sizeof(mdp5_cmd_enc->intf));
317         encoder = &mdp5_cmd_enc->base;
318         mdp5_cmd_enc->ctl = ctl;
319
320         drm_encoder_init(dev, encoder, &mdp5_cmd_encoder_funcs,
321                         DRM_MODE_ENCODER_DSI, NULL);
322
323         drm_encoder_helper_add(encoder, &mdp5_cmd_encoder_helper_funcs);
324
325         bs_init(mdp5_cmd_enc);
326
327         return encoder;
328
329 fail:
330         if (encoder)
331                 mdp5_cmd_encoder_destroy(encoder);
332
333         return ERR_PTR(ret);
334 }