2 * Copyright (C) 2014 Red Hat
3 * Author: Rob Clark <robdclark@gmail.com>
4 * Author: Vinay Simha <vinaysimha@inforcecomputing.com>
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License version 2 as published by
8 * the Free Software Foundation.
10 * This program is distributed in the hope that it will be useful, but WITHOUT
11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
15 * You should have received a copy of the GNU General Public License along with
16 * this program. If not, see <http://www.gnu.org/licenses/>.
22 #include "drm_crtc_helper.h"
24 struct mdp4_lcdc_encoder
{
25 struct drm_encoder base
;
26 struct drm_panel
*panel
;
28 unsigned long int pixclock
;
29 struct regulator
*regs
[3];
33 #define to_mdp4_lcdc_encoder(x) container_of(x, struct mdp4_lcdc_encoder, base)
35 static struct mdp4_kms
*get_kms(struct drm_encoder
*encoder
)
37 struct msm_drm_private
*priv
= encoder
->dev
->dev_private
;
38 return to_mdp4_kms(to_mdp_kms(priv
->kms
));
41 #ifdef DOWNSTREAM_CONFIG_MSM_BUS_SCALING
42 #include <mach/board.h>
43 static void bs_init(struct mdp4_lcdc_encoder
*mdp4_lcdc_encoder
)
45 struct drm_device
*dev
= mdp4_lcdc_encoder
->base
.dev
;
46 struct lcdc_platform_data
*lcdc_pdata
= mdp4_find_pdata("lvds.0");
49 dev_err(dev
->dev
, "could not find lvds pdata\n");
53 if (lcdc_pdata
->bus_scale_table
) {
54 mdp4_lcdc_encoder
->bsc
= msm_bus_scale_register_client(
55 lcdc_pdata
->bus_scale_table
);
56 DBG("lvds : bus scale client: %08x", mdp4_lcdc_encoder
->bsc
);
60 static void bs_fini(struct mdp4_lcdc_encoder
*mdp4_lcdc_encoder
)
62 if (mdp4_lcdc_encoder
->bsc
) {
63 msm_bus_scale_unregister_client(mdp4_lcdc_encoder
->bsc
);
64 mdp4_lcdc_encoder
->bsc
= 0;
68 static void bs_set(struct mdp4_lcdc_encoder
*mdp4_lcdc_encoder
, int idx
)
70 if (mdp4_lcdc_encoder
->bsc
) {
71 DBG("set bus scaling: %d", idx
);
72 msm_bus_scale_client_update_request(mdp4_lcdc_encoder
->bsc
, idx
);
76 static void bs_init(struct mdp4_lcdc_encoder
*mdp4_lcdc_encoder
) {}
77 static void bs_fini(struct mdp4_lcdc_encoder
*mdp4_lcdc_encoder
) {}
78 static void bs_set(struct mdp4_lcdc_encoder
*mdp4_lcdc_encoder
, int idx
) {}
81 static void mdp4_lcdc_encoder_destroy(struct drm_encoder
*encoder
)
83 struct mdp4_lcdc_encoder
*mdp4_lcdc_encoder
=
84 to_mdp4_lcdc_encoder(encoder
);
85 bs_fini(mdp4_lcdc_encoder
);
86 drm_encoder_cleanup(encoder
);
87 kfree(mdp4_lcdc_encoder
);
90 static const struct drm_encoder_funcs mdp4_lcdc_encoder_funcs
= {
91 .destroy
= mdp4_lcdc_encoder_destroy
,
94 /* this should probably be a helper: */
95 struct drm_connector
*get_connector(struct drm_encoder
*encoder
)
97 struct drm_device
*dev
= encoder
->dev
;
98 struct drm_connector
*connector
;
100 list_for_each_entry(connector
, &dev
->mode_config
.connector_list
, head
)
101 if (connector
->encoder
== encoder
)
107 static void setup_phy(struct drm_encoder
*encoder
)
109 struct drm_device
*dev
= encoder
->dev
;
110 struct drm_connector
*connector
= get_connector(encoder
);
111 struct mdp4_kms
*mdp4_kms
= get_kms(encoder
);
112 uint32_t lvds_intf
= 0, lvds_phy_cfg0
= 0;
113 int bpp
, nchan
, swap
;
118 bpp
= 3 * connector
->display_info
.bpc
;
123 /* TODO, these should come from panel somehow: */
129 mdp4_write(mdp4_kms
, REG_MDP4_LCDC_LVDS_MUX_CTL_3_TO_0(0),
130 MDP4_LCDC_LVDS_MUX_CTL_3_TO_0_BIT0(0x08) |
131 MDP4_LCDC_LVDS_MUX_CTL_3_TO_0_BIT1(0x05) |
132 MDP4_LCDC_LVDS_MUX_CTL_3_TO_0_BIT2(0x04) |
133 MDP4_LCDC_LVDS_MUX_CTL_3_TO_0_BIT3(0x03));
134 mdp4_write(mdp4_kms
, REG_MDP4_LCDC_LVDS_MUX_CTL_6_TO_4(0),
135 MDP4_LCDC_LVDS_MUX_CTL_6_TO_4_BIT4(0x02) |
136 MDP4_LCDC_LVDS_MUX_CTL_6_TO_4_BIT5(0x01) |
137 MDP4_LCDC_LVDS_MUX_CTL_6_TO_4_BIT6(0x00));
138 mdp4_write(mdp4_kms
, REG_MDP4_LCDC_LVDS_MUX_CTL_3_TO_0(1),
139 MDP4_LCDC_LVDS_MUX_CTL_3_TO_0_BIT0(0x11) |
140 MDP4_LCDC_LVDS_MUX_CTL_3_TO_0_BIT1(0x10) |
141 MDP4_LCDC_LVDS_MUX_CTL_3_TO_0_BIT2(0x0d) |
142 MDP4_LCDC_LVDS_MUX_CTL_3_TO_0_BIT3(0x0c));
143 mdp4_write(mdp4_kms
, REG_MDP4_LCDC_LVDS_MUX_CTL_6_TO_4(1),
144 MDP4_LCDC_LVDS_MUX_CTL_6_TO_4_BIT4(0x0b) |
145 MDP4_LCDC_LVDS_MUX_CTL_6_TO_4_BIT5(0x0a) |
146 MDP4_LCDC_LVDS_MUX_CTL_6_TO_4_BIT6(0x09));
147 mdp4_write(mdp4_kms
, REG_MDP4_LCDC_LVDS_MUX_CTL_3_TO_0(2),
148 MDP4_LCDC_LVDS_MUX_CTL_3_TO_0_BIT0(0x1a) |
149 MDP4_LCDC_LVDS_MUX_CTL_3_TO_0_BIT1(0x19) |
150 MDP4_LCDC_LVDS_MUX_CTL_3_TO_0_BIT2(0x18) |
151 MDP4_LCDC_LVDS_MUX_CTL_3_TO_0_BIT3(0x15));
152 mdp4_write(mdp4_kms
, REG_MDP4_LCDC_LVDS_MUX_CTL_6_TO_4(2),
153 MDP4_LCDC_LVDS_MUX_CTL_6_TO_4_BIT4(0x14) |
154 MDP4_LCDC_LVDS_MUX_CTL_6_TO_4_BIT5(0x13) |
155 MDP4_LCDC_LVDS_MUX_CTL_6_TO_4_BIT6(0x12));
156 mdp4_write(mdp4_kms
, REG_MDP4_LCDC_LVDS_MUX_CTL_3_TO_0(3),
157 MDP4_LCDC_LVDS_MUX_CTL_3_TO_0_BIT0(0x1b) |
158 MDP4_LCDC_LVDS_MUX_CTL_3_TO_0_BIT1(0x17) |
159 MDP4_LCDC_LVDS_MUX_CTL_3_TO_0_BIT2(0x16) |
160 MDP4_LCDC_LVDS_MUX_CTL_3_TO_0_BIT3(0x0f));
161 mdp4_write(mdp4_kms
, REG_MDP4_LCDC_LVDS_MUX_CTL_6_TO_4(3),
162 MDP4_LCDC_LVDS_MUX_CTL_6_TO_4_BIT4(0x0e) |
163 MDP4_LCDC_LVDS_MUX_CTL_6_TO_4_BIT5(0x07) |
164 MDP4_LCDC_LVDS_MUX_CTL_6_TO_4_BIT6(0x06));
166 lvds_intf
|= MDP4_LCDC_LVDS_INTF_CTL_CH2_DATA_LANE3_EN
|
167 MDP4_LCDC_LVDS_INTF_CTL_CH2_DATA_LANE2_EN
|
168 MDP4_LCDC_LVDS_INTF_CTL_CH2_DATA_LANE1_EN
|
169 MDP4_LCDC_LVDS_INTF_CTL_CH2_DATA_LANE0_EN
|
170 MDP4_LCDC_LVDS_INTF_CTL_CH1_DATA_LANE3_EN
|
171 MDP4_LCDC_LVDS_INTF_CTL_CH1_DATA_LANE2_EN
|
172 MDP4_LCDC_LVDS_INTF_CTL_CH1_DATA_LANE1_EN
|
173 MDP4_LCDC_LVDS_INTF_CTL_CH1_DATA_LANE0_EN
;
175 lvds_intf
|= MDP4_LCDC_LVDS_INTF_CTL_CH1_DATA_LANE3_EN
|
176 MDP4_LCDC_LVDS_INTF_CTL_CH1_DATA_LANE2_EN
|
177 MDP4_LCDC_LVDS_INTF_CTL_CH1_DATA_LANE1_EN
|
178 MDP4_LCDC_LVDS_INTF_CTL_CH1_DATA_LANE0_EN
;
183 mdp4_write(mdp4_kms
, REG_MDP4_LCDC_LVDS_MUX_CTL_3_TO_0(0),
184 MDP4_LCDC_LVDS_MUX_CTL_3_TO_0_BIT0(0x0a) |
185 MDP4_LCDC_LVDS_MUX_CTL_3_TO_0_BIT1(0x07) |
186 MDP4_LCDC_LVDS_MUX_CTL_3_TO_0_BIT2(0x06) |
187 MDP4_LCDC_LVDS_MUX_CTL_3_TO_0_BIT3(0x05));
188 mdp4_write(mdp4_kms
, REG_MDP4_LCDC_LVDS_MUX_CTL_6_TO_4(0),
189 MDP4_LCDC_LVDS_MUX_CTL_6_TO_4_BIT4(0x04) |
190 MDP4_LCDC_LVDS_MUX_CTL_6_TO_4_BIT5(0x03) |
191 MDP4_LCDC_LVDS_MUX_CTL_6_TO_4_BIT6(0x02));
192 mdp4_write(mdp4_kms
, REG_MDP4_LCDC_LVDS_MUX_CTL_3_TO_0(1),
193 MDP4_LCDC_LVDS_MUX_CTL_3_TO_0_BIT0(0x13) |
194 MDP4_LCDC_LVDS_MUX_CTL_3_TO_0_BIT1(0x12) |
195 MDP4_LCDC_LVDS_MUX_CTL_3_TO_0_BIT2(0x0f) |
196 MDP4_LCDC_LVDS_MUX_CTL_3_TO_0_BIT3(0x0e));
197 mdp4_write(mdp4_kms
, REG_MDP4_LCDC_LVDS_MUX_CTL_6_TO_4(1),
198 MDP4_LCDC_LVDS_MUX_CTL_6_TO_4_BIT4(0x0d) |
199 MDP4_LCDC_LVDS_MUX_CTL_6_TO_4_BIT5(0x0c) |
200 MDP4_LCDC_LVDS_MUX_CTL_6_TO_4_BIT6(0x0b));
201 mdp4_write(mdp4_kms
, REG_MDP4_LCDC_LVDS_MUX_CTL_3_TO_0(2),
202 MDP4_LCDC_LVDS_MUX_CTL_3_TO_0_BIT0(0x1a) |
203 MDP4_LCDC_LVDS_MUX_CTL_3_TO_0_BIT1(0x19) |
204 MDP4_LCDC_LVDS_MUX_CTL_3_TO_0_BIT2(0x18) |
205 MDP4_LCDC_LVDS_MUX_CTL_3_TO_0_BIT3(0x17));
206 mdp4_write(mdp4_kms
, REG_MDP4_LCDC_LVDS_MUX_CTL_6_TO_4(2),
207 MDP4_LCDC_LVDS_MUX_CTL_6_TO_4_BIT4(0x16) |
208 MDP4_LCDC_LVDS_MUX_CTL_6_TO_4_BIT5(0x15) |
209 MDP4_LCDC_LVDS_MUX_CTL_6_TO_4_BIT6(0x14));
211 lvds_intf
|= MDP4_LCDC_LVDS_INTF_CTL_CH2_DATA_LANE2_EN
|
212 MDP4_LCDC_LVDS_INTF_CTL_CH2_DATA_LANE1_EN
|
213 MDP4_LCDC_LVDS_INTF_CTL_CH2_DATA_LANE0_EN
|
214 MDP4_LCDC_LVDS_INTF_CTL_CH1_DATA_LANE2_EN
|
215 MDP4_LCDC_LVDS_INTF_CTL_CH1_DATA_LANE1_EN
|
216 MDP4_LCDC_LVDS_INTF_CTL_CH1_DATA_LANE0_EN
;
218 lvds_intf
|= MDP4_LCDC_LVDS_INTF_CTL_CH1_DATA_LANE2_EN
|
219 MDP4_LCDC_LVDS_INTF_CTL_CH1_DATA_LANE1_EN
|
220 MDP4_LCDC_LVDS_INTF_CTL_CH1_DATA_LANE0_EN
;
222 lvds_intf
|= MDP4_LCDC_LVDS_INTF_CTL_RGB_OUT
;
226 dev_err(dev
->dev
, "unknown bpp: %d\n", bpp
);
232 lvds_phy_cfg0
= MDP4_LVDS_PHY_CFG0_CHANNEL0
;
233 lvds_intf
|= MDP4_LCDC_LVDS_INTF_CTL_CH1_CLK_LANE_EN
|
234 MDP4_LCDC_LVDS_INTF_CTL_MODE_SEL
;
237 lvds_phy_cfg0
= MDP4_LVDS_PHY_CFG0_CHANNEL0
|
238 MDP4_LVDS_PHY_CFG0_CHANNEL1
;
239 lvds_intf
|= MDP4_LCDC_LVDS_INTF_CTL_CH2_CLK_LANE_EN
|
240 MDP4_LCDC_LVDS_INTF_CTL_CH1_CLK_LANE_EN
;
243 dev_err(dev
->dev
, "unknown # of channels: %d\n", nchan
);
248 lvds_intf
|= MDP4_LCDC_LVDS_INTF_CTL_CH_SWAP
;
250 lvds_intf
|= MDP4_LCDC_LVDS_INTF_CTL_ENABLE
;
252 mdp4_write(mdp4_kms
, REG_MDP4_LVDS_PHY_CFG0
, lvds_phy_cfg0
);
253 mdp4_write(mdp4_kms
, REG_MDP4_LCDC_LVDS_INTF_CTL
, lvds_intf
);
254 mdp4_write(mdp4_kms
, REG_MDP4_LVDS_PHY_CFG2
, 0x30);
258 lvds_phy_cfg0
|= MDP4_LVDS_PHY_CFG0_SERIALIZATION_ENBLE
;
259 mdp4_write(mdp4_kms
, REG_MDP4_LVDS_PHY_CFG0
, lvds_phy_cfg0
);
262 static bool mdp4_lcdc_encoder_mode_fixup(struct drm_encoder
*encoder
,
263 const struct drm_display_mode
*mode
,
264 struct drm_display_mode
*adjusted_mode
)
269 static void mdp4_lcdc_encoder_mode_set(struct drm_encoder
*encoder
,
270 struct drm_display_mode
*mode
,
271 struct drm_display_mode
*adjusted_mode
)
273 struct mdp4_lcdc_encoder
*mdp4_lcdc_encoder
=
274 to_mdp4_lcdc_encoder(encoder
);
275 struct mdp4_kms
*mdp4_kms
= get_kms(encoder
);
276 uint32_t lcdc_hsync_skew
, vsync_period
, vsync_len
, ctrl_pol
;
277 uint32_t display_v_start
, display_v_end
;
278 uint32_t hsync_start_x
, hsync_end_x
;
280 mode
= adjusted_mode
;
282 DBG("set mode: %d:\"%s\" %d %d %d %d %d %d %d %d %d %d 0x%x 0x%x",
283 mode
->base
.id
, mode
->name
,
284 mode
->vrefresh
, mode
->clock
,
285 mode
->hdisplay
, mode
->hsync_start
,
286 mode
->hsync_end
, mode
->htotal
,
287 mode
->vdisplay
, mode
->vsync_start
,
288 mode
->vsync_end
, mode
->vtotal
,
289 mode
->type
, mode
->flags
);
291 mdp4_lcdc_encoder
->pixclock
= mode
->clock
* 1000;
293 DBG("pixclock=%lu", mdp4_lcdc_encoder
->pixclock
);
296 if (mode
->flags
& DRM_MODE_FLAG_NHSYNC
)
297 ctrl_pol
|= MDP4_LCDC_CTRL_POLARITY_HSYNC_LOW
;
298 if (mode
->flags
& DRM_MODE_FLAG_NVSYNC
)
299 ctrl_pol
|= MDP4_LCDC_CTRL_POLARITY_VSYNC_LOW
;
300 /* probably need to get DATA_EN polarity from panel.. */
302 lcdc_hsync_skew
= 0; /* get this from panel? */
304 hsync_start_x
= (mode
->htotal
- mode
->hsync_start
);
305 hsync_end_x
= mode
->htotal
- (mode
->hsync_start
- mode
->hdisplay
) - 1;
307 vsync_period
= mode
->vtotal
* mode
->htotal
;
308 vsync_len
= (mode
->vsync_end
- mode
->vsync_start
) * mode
->htotal
;
309 display_v_start
= (mode
->vtotal
- mode
->vsync_start
) * mode
->htotal
+ lcdc_hsync_skew
;
310 display_v_end
= vsync_period
- ((mode
->vsync_start
- mode
->vdisplay
) * mode
->htotal
) + lcdc_hsync_skew
- 1;
312 mdp4_write(mdp4_kms
, REG_MDP4_LCDC_HSYNC_CTRL
,
313 MDP4_LCDC_HSYNC_CTRL_PULSEW(mode
->hsync_end
- mode
->hsync_start
) |
314 MDP4_LCDC_HSYNC_CTRL_PERIOD(mode
->htotal
));
315 mdp4_write(mdp4_kms
, REG_MDP4_LCDC_VSYNC_PERIOD
, vsync_period
);
316 mdp4_write(mdp4_kms
, REG_MDP4_LCDC_VSYNC_LEN
, vsync_len
);
317 mdp4_write(mdp4_kms
, REG_MDP4_LCDC_DISPLAY_HCTRL
,
318 MDP4_LCDC_DISPLAY_HCTRL_START(hsync_start_x
) |
319 MDP4_LCDC_DISPLAY_HCTRL_END(hsync_end_x
));
320 mdp4_write(mdp4_kms
, REG_MDP4_LCDC_DISPLAY_VSTART
, display_v_start
);
321 mdp4_write(mdp4_kms
, REG_MDP4_LCDC_DISPLAY_VEND
, display_v_end
);
322 mdp4_write(mdp4_kms
, REG_MDP4_LCDC_BORDER_CLR
, 0);
323 mdp4_write(mdp4_kms
, REG_MDP4_LCDC_UNDERFLOW_CLR
,
324 MDP4_LCDC_UNDERFLOW_CLR_ENABLE_RECOVERY
|
325 MDP4_LCDC_UNDERFLOW_CLR_COLOR(0xff));
326 mdp4_write(mdp4_kms
, REG_MDP4_LCDC_HSYNC_SKEW
, lcdc_hsync_skew
);
327 mdp4_write(mdp4_kms
, REG_MDP4_LCDC_CTRL_POLARITY
, ctrl_pol
);
328 mdp4_write(mdp4_kms
, REG_MDP4_LCDC_ACTIVE_HCTL
,
329 MDP4_LCDC_ACTIVE_HCTL_START(0) |
330 MDP4_LCDC_ACTIVE_HCTL_END(0));
331 mdp4_write(mdp4_kms
, REG_MDP4_LCDC_ACTIVE_VSTART
, 0);
332 mdp4_write(mdp4_kms
, REG_MDP4_LCDC_ACTIVE_VEND
, 0);
335 static void mdp4_lcdc_encoder_disable(struct drm_encoder
*encoder
)
337 struct drm_device
*dev
= encoder
->dev
;
338 struct mdp4_lcdc_encoder
*mdp4_lcdc_encoder
=
339 to_mdp4_lcdc_encoder(encoder
);
340 struct mdp4_kms
*mdp4_kms
= get_kms(encoder
);
341 struct drm_panel
*panel
= mdp4_lcdc_encoder
->panel
;
344 if (WARN_ON(!mdp4_lcdc_encoder
->enabled
))
347 mdp4_write(mdp4_kms
, REG_MDP4_LCDC_ENABLE
, 0);
350 drm_panel_disable(panel
);
351 drm_panel_unprepare(panel
);
355 * Wait for a vsync so we know the ENABLE=0 latched before
356 * the (connector) source of the vsync's gets disabled,
357 * otherwise we end up in a funny state if we re-enable
358 * before the disable latches, which results that some of
359 * the settings changes for the new modeset (like new
360 * scanout buffer) don't latch properly..
362 mdp_irq_wait(&mdp4_kms
->base
, MDP4_IRQ_PRIMARY_VSYNC
);
364 clk_disable_unprepare(mdp4_lcdc_encoder
->lcdc_clk
);
366 for (i
= 0; i
< ARRAY_SIZE(mdp4_lcdc_encoder
->regs
); i
++) {
367 ret
= regulator_disable(mdp4_lcdc_encoder
->regs
[i
]);
369 dev_err(dev
->dev
, "failed to disable regulator: %d\n", ret
);
372 bs_set(mdp4_lcdc_encoder
, 0);
374 mdp4_lcdc_encoder
->enabled
= false;
377 static void mdp4_lcdc_encoder_enable(struct drm_encoder
*encoder
)
379 struct drm_device
*dev
= encoder
->dev
;
380 struct mdp4_lcdc_encoder
*mdp4_lcdc_encoder
=
381 to_mdp4_lcdc_encoder(encoder
);
382 unsigned long pc
= mdp4_lcdc_encoder
->pixclock
;
383 struct mdp4_kms
*mdp4_kms
= get_kms(encoder
);
384 struct drm_panel
*panel
= mdp4_lcdc_encoder
->panel
;
387 if (WARN_ON(mdp4_lcdc_encoder
->enabled
))
390 /* TODO: hard-coded for 18bpp: */
391 mdp4_crtc_set_config(encoder
->crtc
,
392 MDP4_DMA_CONFIG_R_BPC(BPC6
) |
393 MDP4_DMA_CONFIG_G_BPC(BPC6
) |
394 MDP4_DMA_CONFIG_B_BPC(BPC6
) |
395 MDP4_DMA_CONFIG_PACK_ALIGN_MSB
|
396 MDP4_DMA_CONFIG_PACK(0x21) |
397 MDP4_DMA_CONFIG_DEFLKR_EN
|
398 MDP4_DMA_CONFIG_DITHER_EN
);
399 mdp4_crtc_set_intf(encoder
->crtc
, INTF_LCDC_DTV
, 0);
401 bs_set(mdp4_lcdc_encoder
, 1);
403 for (i
= 0; i
< ARRAY_SIZE(mdp4_lcdc_encoder
->regs
); i
++) {
404 ret
= regulator_enable(mdp4_lcdc_encoder
->regs
[i
]);
406 dev_err(dev
->dev
, "failed to enable regulator: %d\n", ret
);
409 DBG("setting lcdc_clk=%lu", pc
);
410 ret
= clk_set_rate(mdp4_lcdc_encoder
->lcdc_clk
, pc
);
412 dev_err(dev
->dev
, "failed to configure lcdc_clk: %d\n", ret
);
413 ret
= clk_prepare_enable(mdp4_lcdc_encoder
->lcdc_clk
);
415 dev_err(dev
->dev
, "failed to enable lcdc_clk: %d\n", ret
);
418 drm_panel_prepare(panel
);
419 drm_panel_enable(panel
);
424 mdp4_write(mdp4_kms
, REG_MDP4_LCDC_ENABLE
, 1);
426 mdp4_lcdc_encoder
->enabled
= true;
429 static const struct drm_encoder_helper_funcs mdp4_lcdc_encoder_helper_funcs
= {
430 .mode_fixup
= mdp4_lcdc_encoder_mode_fixup
,
431 .mode_set
= mdp4_lcdc_encoder_mode_set
,
432 .disable
= mdp4_lcdc_encoder_disable
,
433 .enable
= mdp4_lcdc_encoder_enable
,
436 long mdp4_lcdc_round_pixclk(struct drm_encoder
*encoder
, unsigned long rate
)
438 struct mdp4_lcdc_encoder
*mdp4_lcdc_encoder
=
439 to_mdp4_lcdc_encoder(encoder
);
440 return clk_round_rate(mdp4_lcdc_encoder
->lcdc_clk
, rate
);
443 /* initialize encoder */
444 struct drm_encoder
*mdp4_lcdc_encoder_init(struct drm_device
*dev
,
445 struct drm_panel
*panel
)
447 struct drm_encoder
*encoder
= NULL
;
448 struct mdp4_lcdc_encoder
*mdp4_lcdc_encoder
;
449 struct regulator
*reg
;
452 mdp4_lcdc_encoder
= kzalloc(sizeof(*mdp4_lcdc_encoder
), GFP_KERNEL
);
453 if (!mdp4_lcdc_encoder
) {
458 mdp4_lcdc_encoder
->panel
= panel
;
460 encoder
= &mdp4_lcdc_encoder
->base
;
462 drm_encoder_init(dev
, encoder
, &mdp4_lcdc_encoder_funcs
,
463 DRM_MODE_ENCODER_LVDS
, NULL
);
464 drm_encoder_helper_add(encoder
, &mdp4_lcdc_encoder_helper_funcs
);
466 /* TODO: do we need different pll in other cases? */
467 mdp4_lcdc_encoder
->lcdc_clk
= mpd4_lvds_pll_init(dev
);
468 if (IS_ERR(mdp4_lcdc_encoder
->lcdc_clk
)) {
469 dev_err(dev
->dev
, "failed to get lvds_clk\n");
470 ret
= PTR_ERR(mdp4_lcdc_encoder
->lcdc_clk
);
474 /* TODO: different regulators in other cases? */
475 reg
= devm_regulator_get(dev
->dev
, "lvds-vccs-3p3v");
478 dev_err(dev
->dev
, "failed to get lvds-vccs-3p3v: %d\n", ret
);
481 mdp4_lcdc_encoder
->regs
[0] = reg
;
483 reg
= devm_regulator_get(dev
->dev
, "lvds-pll-vdda");
486 dev_err(dev
->dev
, "failed to get lvds-pll-vdda: %d\n", ret
);
489 mdp4_lcdc_encoder
->regs
[1] = reg
;
491 reg
= devm_regulator_get(dev
->dev
, "lvds-vdda");
494 dev_err(dev
->dev
, "failed to get lvds-vdda: %d\n", ret
);
497 mdp4_lcdc_encoder
->regs
[2] = reg
;
499 bs_init(mdp4_lcdc_encoder
);
505 mdp4_lcdc_encoder_destroy(encoder
);