2 * Copyright (C) STMicroelectronics SA 2014
3 * Authors: Benjamin Gaignard <benjamin.gaignard@st.com>
4 * Vincent Abriou <vincent.abriou@st.com>
5 * for STMicroelectronics.
6 * License terms: GNU General Public License (GPL), version 2
10 #include <linux/component.h>
11 #include <linux/module.h>
12 #include <linux/of_platform.h>
13 #include <linux/platform_device.h>
14 #include <linux/reset.h>
17 #include <drm/drm_crtc_helper.h>
19 #include "sti_drm_crtc.h"
22 #define TVO_CSC_MAIN_M0 0x000
23 #define TVO_CSC_MAIN_M1 0x004
24 #define TVO_CSC_MAIN_M2 0x008
25 #define TVO_CSC_MAIN_M3 0x00c
26 #define TVO_CSC_MAIN_M4 0x010
27 #define TVO_CSC_MAIN_M5 0x014
28 #define TVO_CSC_MAIN_M6 0x018
29 #define TVO_CSC_MAIN_M7 0x01c
30 #define TVO_MAIN_IN_VID_FORMAT 0x030
31 #define TVO_CSC_AUX_M0 0x100
32 #define TVO_CSC_AUX_M1 0x104
33 #define TVO_CSC_AUX_M2 0x108
34 #define TVO_CSC_AUX_M3 0x10c
35 #define TVO_CSC_AUX_M4 0x110
36 #define TVO_CSC_AUX_M5 0x114
37 #define TVO_CSC_AUX_M6 0x118
38 #define TVO_CSC_AUX_M7 0x11c
39 #define TVO_AUX_IN_VID_FORMAT 0x130
40 #define TVO_VIP_HDF 0x400
41 #define TVO_HD_SYNC_SEL 0x418
42 #define TVO_HD_DAC_CFG_OFF 0x420
43 #define TVO_VIP_HDMI 0x500
44 #define TVO_HDMI_FORCE_COLOR_0 0x504
45 #define TVO_HDMI_FORCE_COLOR_1 0x508
46 #define TVO_HDMI_CLIP_VALUE_B_CB 0x50c
47 #define TVO_HDMI_CLIP_VALUE_Y_G 0x510
48 #define TVO_HDMI_CLIP_VALUE_R_CR 0x514
49 #define TVO_HDMI_SYNC_SEL 0x518
50 #define TVO_HDMI_DFV_OBS 0x540
51 #define TVO_VIP_DVO 0x600
52 #define TVO_DVO_SYNC_SEL 0x618
53 #define TVO_DVO_CONFIG 0x620
55 #define TVO_IN_FMT_SIGNED BIT(0)
56 #define TVO_SYNC_EXT BIT(4)
58 #define TVO_VIP_REORDER_R_SHIFT 24
59 #define TVO_VIP_REORDER_G_SHIFT 20
60 #define TVO_VIP_REORDER_B_SHIFT 16
61 #define TVO_VIP_REORDER_MASK 0x3
62 #define TVO_VIP_REORDER_Y_G_SEL 0
63 #define TVO_VIP_REORDER_CB_B_SEL 1
64 #define TVO_VIP_REORDER_CR_R_SEL 2
66 #define TVO_VIP_CLIP_SHIFT 8
67 #define TVO_VIP_CLIP_MASK 0x7
68 #define TVO_VIP_CLIP_DISABLED 0
69 #define TVO_VIP_CLIP_EAV_SAV 1
70 #define TVO_VIP_CLIP_LIMITED_RANGE_RGB_Y 2
71 #define TVO_VIP_CLIP_LIMITED_RANGE_CB_CR 3
72 #define TVO_VIP_CLIP_PROG_RANGE 4
74 #define TVO_VIP_RND_SHIFT 4
75 #define TVO_VIP_RND_MASK 0x3
76 #define TVO_VIP_RND_8BIT_ROUNDED 0
77 #define TVO_VIP_RND_10BIT_ROUNDED 1
78 #define TVO_VIP_RND_12BIT_ROUNDED 2
80 #define TVO_VIP_SEL_INPUT_MASK 0xf
81 #define TVO_VIP_SEL_INPUT_MAIN 0x0
82 #define TVO_VIP_SEL_INPUT_AUX 0x8
83 #define TVO_VIP_SEL_INPUT_FORCE_COLOR 0xf
84 #define TVO_VIP_SEL_INPUT_BYPASS_MASK 0x1
85 #define TVO_VIP_SEL_INPUT_BYPASSED 1
87 #define TVO_SYNC_MAIN_VTG_SET_REF 0x00
88 #define TVO_SYNC_MAIN_VTG_SET_1 0x01
89 #define TVO_SYNC_MAIN_VTG_SET_2 0x02
90 #define TVO_SYNC_MAIN_VTG_SET_3 0x03
91 #define TVO_SYNC_MAIN_VTG_SET_4 0x04
92 #define TVO_SYNC_MAIN_VTG_SET_5 0x05
93 #define TVO_SYNC_MAIN_VTG_SET_6 0x06
94 #define TVO_SYNC_AUX_VTG_SET_REF 0x10
95 #define TVO_SYNC_AUX_VTG_SET_1 0x11
96 #define TVO_SYNC_AUX_VTG_SET_2 0x12
97 #define TVO_SYNC_AUX_VTG_SET_3 0x13
98 #define TVO_SYNC_AUX_VTG_SET_4 0x14
99 #define TVO_SYNC_AUX_VTG_SET_5 0x15
100 #define TVO_SYNC_AUX_VTG_SET_6 0x16
102 #define TVO_SYNC_HD_DCS_SHIFT 8
104 #define TVO_SYNC_DVO_PAD_HSYNC_SHIFT 8
105 #define TVO_SYNC_DVO_PAD_VSYNC_SHIFT 16
107 #define ENCODER_CRTC_MASK (BIT(0) | BIT(1))
109 /* enum listing the supported output data format */
110 enum sti_tvout_video_out_type
{
111 STI_TVOUT_VIDEO_OUT_RGB
,
112 STI_TVOUT_VIDEO_OUT_YUV
,
117 struct drm_device
*drm_dev
;
119 struct reset_control
*reset
;
120 struct drm_encoder
*hdmi
;
121 struct drm_encoder
*hda
;
122 struct drm_encoder
*dvo
;
125 struct sti_tvout_encoder
{
126 struct drm_encoder encoder
;
127 struct sti_tvout
*tvout
;
130 #define to_sti_tvout_encoder(x) \
131 container_of(x, struct sti_tvout_encoder, encoder)
133 #define to_sti_tvout(x) to_sti_tvout_encoder(x)->tvout
135 /* preformatter conversion matrix */
136 static const u32 rgb_to_ycbcr_601
[8] = {
137 0xF927082E, 0x04C9FEAB, 0x01D30964, 0xFA95FD3D,
138 0x0000082E, 0x00002000, 0x00002000, 0x00000000
141 /* 709 RGB to YCbCr */
142 static const u32 rgb_to_ycbcr_709
[8] = {
143 0xF891082F, 0x0367FF40, 0x01280B71, 0xF9B1FE20,
144 0x0000082F, 0x00002000, 0x00002000, 0x00000000
147 static u32
tvout_read(struct sti_tvout
*tvout
, int offset
)
149 return readl(tvout
->regs
+ offset
);
152 static void tvout_write(struct sti_tvout
*tvout
, u32 val
, int offset
)
154 writel(val
, tvout
->regs
+ offset
);
158 * Set the clipping mode of a VIP
160 * @tvout: tvout structure
161 * @reg: register to set
166 static void tvout_vip_set_color_order(struct sti_tvout
*tvout
, int reg
,
167 u32 cr_r
, u32 y_g
, u32 cb_b
)
169 u32 val
= tvout_read(tvout
, reg
);
171 val
&= ~(TVO_VIP_REORDER_MASK
<< TVO_VIP_REORDER_R_SHIFT
);
172 val
&= ~(TVO_VIP_REORDER_MASK
<< TVO_VIP_REORDER_G_SHIFT
);
173 val
&= ~(TVO_VIP_REORDER_MASK
<< TVO_VIP_REORDER_B_SHIFT
);
174 val
|= cr_r
<< TVO_VIP_REORDER_R_SHIFT
;
175 val
|= y_g
<< TVO_VIP_REORDER_G_SHIFT
;
176 val
|= cb_b
<< TVO_VIP_REORDER_B_SHIFT
;
178 tvout_write(tvout
, val
, reg
);
182 * Set the clipping mode of a VIP
184 * @tvout: tvout structure
185 * @reg: register to set
186 * @range: clipping range
188 static void tvout_vip_set_clip_mode(struct sti_tvout
*tvout
, int reg
, u32 range
)
190 u32 val
= tvout_read(tvout
, reg
);
192 val
&= ~(TVO_VIP_CLIP_MASK
<< TVO_VIP_CLIP_SHIFT
);
193 val
|= range
<< TVO_VIP_CLIP_SHIFT
;
194 tvout_write(tvout
, val
, reg
);
198 * Set the rounded value of a VIP
200 * @tvout: tvout structure
201 * @reg: register to set
202 * @rnd: rounded val per component
204 static void tvout_vip_set_rnd(struct sti_tvout
*tvout
, int reg
, u32 rnd
)
206 u32 val
= tvout_read(tvout
, reg
);
208 val
&= ~(TVO_VIP_RND_MASK
<< TVO_VIP_RND_SHIFT
);
209 val
|= rnd
<< TVO_VIP_RND_SHIFT
;
210 tvout_write(tvout
, val
, reg
);
214 * Select the VIP input
216 * @tvout: tvout structure
217 * @reg: register to set
218 * @main_path: main or auxiliary path
219 * @sel_input_logic_inverted: need to invert the logic
220 * @sel_input: selected_input (main/aux + conv)
222 static void tvout_vip_set_sel_input(struct sti_tvout
*tvout
,
225 bool sel_input_logic_inverted
,
226 enum sti_tvout_video_out_type video_out
)
229 u32 val
= tvout_read(tvout
, reg
);
232 sel_input
= TVO_VIP_SEL_INPUT_MAIN
;
234 sel_input
= TVO_VIP_SEL_INPUT_AUX
;
237 case STI_TVOUT_VIDEO_OUT_RGB
:
238 sel_input
|= TVO_VIP_SEL_INPUT_BYPASSED
;
240 case STI_TVOUT_VIDEO_OUT_YUV
:
241 sel_input
&= ~TVO_VIP_SEL_INPUT_BYPASSED
;
245 /* on stih407 chip the sel_input bypass mode logic is inverted */
246 if (sel_input_logic_inverted
)
247 sel_input
= sel_input
^ TVO_VIP_SEL_INPUT_BYPASS_MASK
;
249 val
&= ~TVO_VIP_SEL_INPUT_MASK
;
251 tvout_write(tvout
, val
, reg
);
255 * Select the input video signed or unsigned
257 * @tvout: tvout structure
258 * @reg: register to set
259 * @in_vid_signed: used video input format
261 static void tvout_vip_set_in_vid_fmt(struct sti_tvout
*tvout
,
262 int reg
, u32 in_vid_fmt
)
264 u32 val
= tvout_read(tvout
, reg
);
266 val
&= ~TVO_IN_FMT_SIGNED
;
268 tvout_write(tvout
, val
, reg
);
272 * Start VIP block for DVO output
274 * @tvout: pointer on tvout structure
275 * @main_path: true if main path has to be used in the vip configuration
276 * else aux path is used.
278 static void tvout_dvo_start(struct sti_tvout
*tvout
, bool main_path
)
280 struct device_node
*node
= tvout
->dev
->of_node
;
281 bool sel_input_logic_inverted
= false;
282 u32 tvo_in_vid_format
;
285 dev_dbg(tvout
->dev
, "%s\n", __func__
);
288 DRM_DEBUG_DRIVER("main vip for DVO\n");
289 /* Select the input sync for dvo = VTG set 4 */
290 val
= TVO_SYNC_MAIN_VTG_SET_4
<< TVO_SYNC_DVO_PAD_VSYNC_SHIFT
;
291 val
|= TVO_SYNC_MAIN_VTG_SET_4
<< TVO_SYNC_DVO_PAD_HSYNC_SHIFT
;
292 val
|= TVO_SYNC_MAIN_VTG_SET_4
;
293 tvout_write(tvout
, val
, TVO_DVO_SYNC_SEL
);
294 tvo_in_vid_format
= TVO_MAIN_IN_VID_FORMAT
;
296 DRM_DEBUG_DRIVER("aux vip for DVO\n");
297 /* Select the input sync for dvo = VTG set 4 */
298 val
= TVO_SYNC_AUX_VTG_SET_4
<< TVO_SYNC_DVO_PAD_VSYNC_SHIFT
;
299 val
|= TVO_SYNC_AUX_VTG_SET_4
<< TVO_SYNC_DVO_PAD_HSYNC_SHIFT
;
300 val
|= TVO_SYNC_AUX_VTG_SET_4
;
301 tvout_write(tvout
, val
, TVO_DVO_SYNC_SEL
);
302 tvo_in_vid_format
= TVO_AUX_IN_VID_FORMAT
;
305 /* Set color channel order */
306 tvout_vip_set_color_order(tvout
, TVO_VIP_DVO
,
307 TVO_VIP_REORDER_CR_R_SEL
,
308 TVO_VIP_REORDER_Y_G_SEL
,
309 TVO_VIP_REORDER_CB_B_SEL
);
311 /* Set clipping mode (Limited range RGB/Y) */
312 tvout_vip_set_clip_mode(tvout
, TVO_VIP_DVO
,
313 TVO_VIP_CLIP_LIMITED_RANGE_RGB_Y
);
315 /* Set round mode (rounded to 8-bit per component) */
316 tvout_vip_set_rnd(tvout
, TVO_VIP_DVO
, TVO_VIP_RND_8BIT_ROUNDED
);
318 if (of_device_is_compatible(node
, "st,stih407-tvout")) {
319 /* Set input video format */
320 tvout_vip_set_in_vid_fmt(tvout
, tvo_in_vid_format
,
322 sel_input_logic_inverted
= true;
325 /* Input selection */
326 tvout_vip_set_sel_input(tvout
, TVO_VIP_DVO
, main_path
,
327 sel_input_logic_inverted
,
328 STI_TVOUT_VIDEO_OUT_RGB
);
332 * Start VIP block for HDMI output
334 * @tvout: pointer on tvout structure
335 * @main_path: true if main path has to be used in the vip configuration
336 * else aux path is used.
338 static void tvout_hdmi_start(struct sti_tvout
*tvout
, bool main_path
)
340 struct device_node
*node
= tvout
->dev
->of_node
;
341 bool sel_input_logic_inverted
= false;
342 u32 tvo_in_vid_format
;
344 dev_dbg(tvout
->dev
, "%s\n", __func__
);
347 DRM_DEBUG_DRIVER("main vip for hdmi\n");
348 /* select the input sync for hdmi = VTG set 1 */
349 tvout_write(tvout
, TVO_SYNC_MAIN_VTG_SET_1
, TVO_HDMI_SYNC_SEL
);
350 tvo_in_vid_format
= TVO_MAIN_IN_VID_FORMAT
;
352 DRM_DEBUG_DRIVER("aux vip for hdmi\n");
353 /* select the input sync for hdmi = VTG set 1 */
354 tvout_write(tvout
, TVO_SYNC_AUX_VTG_SET_1
, TVO_HDMI_SYNC_SEL
);
355 tvo_in_vid_format
= TVO_AUX_IN_VID_FORMAT
;
358 /* set color channel order */
359 tvout_vip_set_color_order(tvout
, TVO_VIP_HDMI
,
360 TVO_VIP_REORDER_CR_R_SEL
,
361 TVO_VIP_REORDER_Y_G_SEL
,
362 TVO_VIP_REORDER_CB_B_SEL
);
364 /* set clipping mode (Limited range RGB/Y) */
365 tvout_vip_set_clip_mode(tvout
, TVO_VIP_HDMI
,
366 TVO_VIP_CLIP_LIMITED_RANGE_RGB_Y
);
368 /* set round mode (rounded to 8-bit per component) */
369 tvout_vip_set_rnd(tvout
, TVO_VIP_HDMI
, TVO_VIP_RND_8BIT_ROUNDED
);
371 if (of_device_is_compatible(node
, "st,stih407-tvout")) {
372 /* set input video format */
373 tvout_vip_set_in_vid_fmt(tvout
, tvo_in_vid_format
,
375 sel_input_logic_inverted
= true;
378 /* input selection */
379 tvout_vip_set_sel_input(tvout
, TVO_VIP_HDMI
, main_path
,
380 sel_input_logic_inverted
, STI_TVOUT_VIDEO_OUT_RGB
);
384 * Start HDF VIP and HD DAC
386 * @tvout: pointer on tvout structure
387 * @main_path: true if main path has to be used in the vip configuration
388 * else aux path is used.
390 static void tvout_hda_start(struct sti_tvout
*tvout
, bool main_path
)
392 struct device_node
*node
= tvout
->dev
->of_node
;
393 bool sel_input_logic_inverted
= false;
394 u32 tvo_in_vid_format
;
397 dev_dbg(tvout
->dev
, "%s\n", __func__
);
400 val
= TVO_SYNC_MAIN_VTG_SET_2
<< TVO_SYNC_HD_DCS_SHIFT
;
401 val
|= TVO_SYNC_MAIN_VTG_SET_3
;
402 tvout_write(tvout
, val
, TVO_HD_SYNC_SEL
);
403 tvo_in_vid_format
= TVO_MAIN_IN_VID_FORMAT
;
405 val
= TVO_SYNC_AUX_VTG_SET_2
<< TVO_SYNC_HD_DCS_SHIFT
;
406 val
|= TVO_SYNC_AUX_VTG_SET_3
;
407 tvout_write(tvout
, val
, TVO_HD_SYNC_SEL
);
408 tvo_in_vid_format
= TVO_AUX_IN_VID_FORMAT
;
411 /* set color channel order */
412 tvout_vip_set_color_order(tvout
, TVO_VIP_HDF
,
413 TVO_VIP_REORDER_CR_R_SEL
,
414 TVO_VIP_REORDER_Y_G_SEL
,
415 TVO_VIP_REORDER_CB_B_SEL
);
417 /* set clipping mode (EAV/SAV clipping) */
418 tvout_vip_set_clip_mode(tvout
, TVO_VIP_HDF
, TVO_VIP_CLIP_EAV_SAV
);
420 /* set round mode (rounded to 10-bit per component) */
421 tvout_vip_set_rnd(tvout
, TVO_VIP_HDF
, TVO_VIP_RND_10BIT_ROUNDED
);
423 if (of_device_is_compatible(node
, "st,stih407-tvout")) {
424 /* set input video format */
425 tvout_vip_set_in_vid_fmt(tvout
,
426 tvo_in_vid_format
, TVO_IN_FMT_SIGNED
);
427 sel_input_logic_inverted
= true;
430 /* Input selection */
431 tvout_vip_set_sel_input(tvout
, TVO_VIP_HDF
, main_path
,
432 sel_input_logic_inverted
,
433 STI_TVOUT_VIDEO_OUT_YUV
);
435 /* power up HD DAC */
436 tvout_write(tvout
, 0, TVO_HD_DAC_CFG_OFF
);
439 static void sti_tvout_encoder_dpms(struct drm_encoder
*encoder
, int mode
)
443 static bool sti_tvout_encoder_mode_fixup(struct drm_encoder
*encoder
,
444 const struct drm_display_mode
*mode
,
445 struct drm_display_mode
*adjusted_mode
)
450 static void sti_tvout_encoder_mode_set(struct drm_encoder
*encoder
,
451 struct drm_display_mode
*mode
,
452 struct drm_display_mode
*adjusted_mode
)
456 static void sti_tvout_encoder_prepare(struct drm_encoder
*encoder
)
460 static void sti_tvout_encoder_destroy(struct drm_encoder
*encoder
)
462 struct sti_tvout_encoder
*sti_encoder
= to_sti_tvout_encoder(encoder
);
464 drm_encoder_cleanup(encoder
);
468 static const struct drm_encoder_funcs sti_tvout_encoder_funcs
= {
469 .destroy
= sti_tvout_encoder_destroy
,
472 static void sti_dvo_encoder_commit(struct drm_encoder
*encoder
)
474 struct sti_tvout
*tvout
= to_sti_tvout(encoder
);
476 tvout_dvo_start(tvout
, sti_drm_crtc_is_main(encoder
->crtc
));
479 static void sti_dvo_encoder_disable(struct drm_encoder
*encoder
)
481 struct sti_tvout
*tvout
= to_sti_tvout(encoder
);
483 /* Reset VIP register */
484 tvout_write(tvout
, 0x0, TVO_VIP_DVO
);
487 static const struct drm_encoder_helper_funcs sti_dvo_encoder_helper_funcs
= {
488 .dpms
= sti_tvout_encoder_dpms
,
489 .mode_fixup
= sti_tvout_encoder_mode_fixup
,
490 .mode_set
= sti_tvout_encoder_mode_set
,
491 .prepare
= sti_tvout_encoder_prepare
,
492 .commit
= sti_dvo_encoder_commit
,
493 .disable
= sti_dvo_encoder_disable
,
496 static struct drm_encoder
*
497 sti_tvout_create_dvo_encoder(struct drm_device
*dev
,
498 struct sti_tvout
*tvout
)
500 struct sti_tvout_encoder
*encoder
;
501 struct drm_encoder
*drm_encoder
;
503 encoder
= devm_kzalloc(tvout
->dev
, sizeof(*encoder
), GFP_KERNEL
);
507 encoder
->tvout
= tvout
;
509 drm_encoder
= (struct drm_encoder
*)encoder
;
511 drm_encoder
->possible_crtcs
= ENCODER_CRTC_MASK
;
512 drm_encoder
->possible_clones
= 1 << 0;
514 drm_encoder_init(dev
, drm_encoder
,
515 &sti_tvout_encoder_funcs
, DRM_MODE_ENCODER_LVDS
);
517 drm_encoder_helper_add(drm_encoder
, &sti_dvo_encoder_helper_funcs
);
522 static void sti_hda_encoder_commit(struct drm_encoder
*encoder
)
524 struct sti_tvout
*tvout
= to_sti_tvout(encoder
);
526 tvout_hda_start(tvout
, sti_drm_crtc_is_main(encoder
->crtc
));
529 static void sti_hda_encoder_disable(struct drm_encoder
*encoder
)
531 struct sti_tvout
*tvout
= to_sti_tvout(encoder
);
533 /* reset VIP register */
534 tvout_write(tvout
, 0x0, TVO_VIP_HDF
);
536 /* power down HD DAC */
537 tvout_write(tvout
, 1, TVO_HD_DAC_CFG_OFF
);
540 static const struct drm_encoder_helper_funcs sti_hda_encoder_helper_funcs
= {
541 .dpms
= sti_tvout_encoder_dpms
,
542 .mode_fixup
= sti_tvout_encoder_mode_fixup
,
543 .mode_set
= sti_tvout_encoder_mode_set
,
544 .prepare
= sti_tvout_encoder_prepare
,
545 .commit
= sti_hda_encoder_commit
,
546 .disable
= sti_hda_encoder_disable
,
549 static struct drm_encoder
*sti_tvout_create_hda_encoder(struct drm_device
*dev
,
550 struct sti_tvout
*tvout
)
552 struct sti_tvout_encoder
*encoder
;
553 struct drm_encoder
*drm_encoder
;
555 encoder
= devm_kzalloc(tvout
->dev
, sizeof(*encoder
), GFP_KERNEL
);
559 encoder
->tvout
= tvout
;
561 drm_encoder
= (struct drm_encoder
*) encoder
;
563 drm_encoder
->possible_crtcs
= ENCODER_CRTC_MASK
;
564 drm_encoder
->possible_clones
= 1 << 0;
566 drm_encoder_init(dev
, drm_encoder
,
567 &sti_tvout_encoder_funcs
, DRM_MODE_ENCODER_DAC
);
569 drm_encoder_helper_add(drm_encoder
, &sti_hda_encoder_helper_funcs
);
574 static void sti_hdmi_encoder_commit(struct drm_encoder
*encoder
)
576 struct sti_tvout
*tvout
= to_sti_tvout(encoder
);
578 tvout_hdmi_start(tvout
, sti_drm_crtc_is_main(encoder
->crtc
));
581 static void sti_hdmi_encoder_disable(struct drm_encoder
*encoder
)
583 struct sti_tvout
*tvout
= to_sti_tvout(encoder
);
585 /* reset VIP register */
586 tvout_write(tvout
, 0x0, TVO_VIP_HDMI
);
589 static const struct drm_encoder_helper_funcs sti_hdmi_encoder_helper_funcs
= {
590 .dpms
= sti_tvout_encoder_dpms
,
591 .mode_fixup
= sti_tvout_encoder_mode_fixup
,
592 .mode_set
= sti_tvout_encoder_mode_set
,
593 .prepare
= sti_tvout_encoder_prepare
,
594 .commit
= sti_hdmi_encoder_commit
,
595 .disable
= sti_hdmi_encoder_disable
,
598 static struct drm_encoder
*sti_tvout_create_hdmi_encoder(struct drm_device
*dev
,
599 struct sti_tvout
*tvout
)
601 struct sti_tvout_encoder
*encoder
;
602 struct drm_encoder
*drm_encoder
;
604 encoder
= devm_kzalloc(tvout
->dev
, sizeof(*encoder
), GFP_KERNEL
);
608 encoder
->tvout
= tvout
;
610 drm_encoder
= (struct drm_encoder
*) encoder
;
612 drm_encoder
->possible_crtcs
= ENCODER_CRTC_MASK
;
613 drm_encoder
->possible_clones
= 1 << 1;
615 drm_encoder_init(dev
, drm_encoder
,
616 &sti_tvout_encoder_funcs
, DRM_MODE_ENCODER_TMDS
);
618 drm_encoder_helper_add(drm_encoder
, &sti_hdmi_encoder_helper_funcs
);
623 static void sti_tvout_create_encoders(struct drm_device
*dev
,
624 struct sti_tvout
*tvout
)
626 tvout
->hdmi
= sti_tvout_create_hdmi_encoder(dev
, tvout
);
627 tvout
->hda
= sti_tvout_create_hda_encoder(dev
, tvout
);
628 tvout
->dvo
= sti_tvout_create_dvo_encoder(dev
, tvout
);
631 static void sti_tvout_destroy_encoders(struct sti_tvout
*tvout
)
634 drm_encoder_cleanup(tvout
->hdmi
);
638 drm_encoder_cleanup(tvout
->hda
);
642 static int sti_tvout_bind(struct device
*dev
, struct device
*master
, void *data
)
644 struct sti_tvout
*tvout
= dev_get_drvdata(dev
);
645 struct drm_device
*drm_dev
= data
;
649 tvout
->drm_dev
= drm_dev
;
651 /* set preformatter matrix */
652 for (i
= 0; i
< 8; i
++) {
653 tvout_write(tvout
, rgb_to_ycbcr_601
[i
],
654 TVO_CSC_MAIN_M0
+ (i
* 4));
655 tvout_write(tvout
, rgb_to_ycbcr_601
[i
],
656 TVO_CSC_AUX_M0
+ (i
* 4));
659 sti_tvout_create_encoders(drm_dev
, tvout
);
661 ret
= component_bind_all(dev
, drm_dev
);
663 sti_tvout_destroy_encoders(tvout
);
668 static void sti_tvout_unbind(struct device
*dev
, struct device
*master
,
674 static const struct component_ops sti_tvout_ops
= {
675 .bind
= sti_tvout_bind
,
676 .unbind
= sti_tvout_unbind
,
679 static int compare_of(struct device
*dev
, void *data
)
681 return dev
->of_node
== data
;
684 static int sti_tvout_master_bind(struct device
*dev
)
689 static void sti_tvout_master_unbind(struct device
*dev
)
694 static const struct component_master_ops sti_tvout_master_ops
= {
695 .bind
= sti_tvout_master_bind
,
696 .unbind
= sti_tvout_master_unbind
,
699 static int sti_tvout_probe(struct platform_device
*pdev
)
701 struct device
*dev
= &pdev
->dev
;
702 struct device_node
*node
= dev
->of_node
;
703 struct sti_tvout
*tvout
;
704 struct resource
*res
;
705 struct device_node
*child_np
;
706 struct component_match
*match
= NULL
;
708 DRM_INFO("%s\n", __func__
);
713 tvout
= devm_kzalloc(dev
, sizeof(*tvout
), GFP_KERNEL
);
719 /* get Memory ressources */
720 res
= platform_get_resource_byname(pdev
, IORESOURCE_MEM
, "tvout-reg");
722 DRM_ERROR("Invalid glue resource\n");
725 tvout
->regs
= devm_ioremap_nocache(dev
, res
->start
, resource_size(res
));
729 /* get reset resources */
730 tvout
->reset
= devm_reset_control_get(dev
, "tvout");
731 /* take tvout out of reset */
732 if (!IS_ERR(tvout
->reset
))
733 reset_control_deassert(tvout
->reset
);
735 platform_set_drvdata(pdev
, tvout
);
737 of_platform_populate(node
, NULL
, NULL
, dev
);
739 child_np
= of_get_next_available_child(node
, NULL
);
742 component_match_add(dev
, &match
, compare_of
, child_np
);
743 of_node_put(child_np
);
744 child_np
= of_get_next_available_child(node
, child_np
);
747 component_master_add_with_match(dev
, &sti_tvout_master_ops
, match
);
749 return component_add(dev
, &sti_tvout_ops
);
752 static int sti_tvout_remove(struct platform_device
*pdev
)
754 component_master_del(&pdev
->dev
, &sti_tvout_master_ops
);
755 component_del(&pdev
->dev
, &sti_tvout_ops
);
759 static const struct of_device_id tvout_of_match
[] = {
760 { .compatible
= "st,stih416-tvout", },
761 { .compatible
= "st,stih407-tvout", },
764 MODULE_DEVICE_TABLE(of
, tvout_of_match
);
766 struct platform_driver sti_tvout_driver
= {
769 .owner
= THIS_MODULE
,
770 .of_match_table
= tvout_of_match
,
772 .probe
= sti_tvout_probe
,
773 .remove
= sti_tvout_remove
,
776 module_platform_driver(sti_tvout_driver
);
778 MODULE_AUTHOR("Benjamin Gaignard <benjamin.gaignard@st.com>");
779 MODULE_DESCRIPTION("STMicroelectronics SoC DRM driver");
780 MODULE_LICENSE("GPL");