1 // SPDX-License-Identifier: GPL-2.0-only
3 * Copyright (C) 2013 Red Hat
4 * Author: Rob Clark <robdclark@gmail.com>
7 #include <drm/drm_crtc.h>
8 #include <drm/drm_probe_helper.h>
12 struct mdp4_dtv_encoder
{
13 struct drm_encoder base
;
16 unsigned long int pixclock
;
20 #define to_mdp4_dtv_encoder(x) container_of(x, struct mdp4_dtv_encoder, base)
22 static struct mdp4_kms
*get_kms(struct drm_encoder
*encoder
)
24 struct msm_drm_private
*priv
= encoder
->dev
->dev_private
;
25 return to_mdp4_kms(to_mdp_kms(priv
->kms
));
28 static void mdp4_dtv_encoder_destroy(struct drm_encoder
*encoder
)
30 struct mdp4_dtv_encoder
*mdp4_dtv_encoder
= to_mdp4_dtv_encoder(encoder
);
31 drm_encoder_cleanup(encoder
);
32 kfree(mdp4_dtv_encoder
);
35 static const struct drm_encoder_funcs mdp4_dtv_encoder_funcs
= {
36 .destroy
= mdp4_dtv_encoder_destroy
,
39 static void mdp4_dtv_encoder_mode_set(struct drm_encoder
*encoder
,
40 struct drm_display_mode
*mode
,
41 struct drm_display_mode
*adjusted_mode
)
43 struct mdp4_dtv_encoder
*mdp4_dtv_encoder
= to_mdp4_dtv_encoder(encoder
);
44 struct mdp4_kms
*mdp4_kms
= get_kms(encoder
);
45 uint32_t dtv_hsync_skew
, vsync_period
, vsync_len
, ctrl_pol
;
46 uint32_t display_v_start
, display_v_end
;
47 uint32_t hsync_start_x
, hsync_end_x
;
51 DBG("set mode: " DRM_MODE_FMT
, DRM_MODE_ARG(mode
));
53 mdp4_dtv_encoder
->pixclock
= mode
->clock
* 1000;
55 DBG("pixclock=%lu", mdp4_dtv_encoder
->pixclock
);
58 if (mode
->flags
& DRM_MODE_FLAG_NHSYNC
)
59 ctrl_pol
|= MDP4_DTV_CTRL_POLARITY_HSYNC_LOW
;
60 if (mode
->flags
& DRM_MODE_FLAG_NVSYNC
)
61 ctrl_pol
|= MDP4_DTV_CTRL_POLARITY_VSYNC_LOW
;
62 /* probably need to get DATA_EN polarity from panel.. */
64 dtv_hsync_skew
= 0; /* get this from panel? */
66 hsync_start_x
= (mode
->htotal
- mode
->hsync_start
);
67 hsync_end_x
= mode
->htotal
- (mode
->hsync_start
- mode
->hdisplay
) - 1;
69 vsync_period
= mode
->vtotal
* mode
->htotal
;
70 vsync_len
= (mode
->vsync_end
- mode
->vsync_start
) * mode
->htotal
;
71 display_v_start
= (mode
->vtotal
- mode
->vsync_start
) * mode
->htotal
+ dtv_hsync_skew
;
72 display_v_end
= vsync_period
- ((mode
->vsync_start
- mode
->vdisplay
) * mode
->htotal
) + dtv_hsync_skew
- 1;
74 mdp4_write(mdp4_kms
, REG_MDP4_DTV_HSYNC_CTRL
,
75 MDP4_DTV_HSYNC_CTRL_PULSEW(mode
->hsync_end
- mode
->hsync_start
) |
76 MDP4_DTV_HSYNC_CTRL_PERIOD(mode
->htotal
));
77 mdp4_write(mdp4_kms
, REG_MDP4_DTV_VSYNC_PERIOD
, vsync_period
);
78 mdp4_write(mdp4_kms
, REG_MDP4_DTV_VSYNC_LEN
, vsync_len
);
79 mdp4_write(mdp4_kms
, REG_MDP4_DTV_DISPLAY_HCTRL
,
80 MDP4_DTV_DISPLAY_HCTRL_START(hsync_start_x
) |
81 MDP4_DTV_DISPLAY_HCTRL_END(hsync_end_x
));
82 mdp4_write(mdp4_kms
, REG_MDP4_DTV_DISPLAY_VSTART
, display_v_start
);
83 mdp4_write(mdp4_kms
, REG_MDP4_DTV_DISPLAY_VEND
, display_v_end
);
84 mdp4_write(mdp4_kms
, REG_MDP4_DTV_BORDER_CLR
, 0);
85 mdp4_write(mdp4_kms
, REG_MDP4_DTV_UNDERFLOW_CLR
,
86 MDP4_DTV_UNDERFLOW_CLR_ENABLE_RECOVERY
|
87 MDP4_DTV_UNDERFLOW_CLR_COLOR(0xff));
88 mdp4_write(mdp4_kms
, REG_MDP4_DTV_HSYNC_SKEW
, dtv_hsync_skew
);
89 mdp4_write(mdp4_kms
, REG_MDP4_DTV_CTRL_POLARITY
, ctrl_pol
);
90 mdp4_write(mdp4_kms
, REG_MDP4_DTV_ACTIVE_HCTL
,
91 MDP4_DTV_ACTIVE_HCTL_START(0) |
92 MDP4_DTV_ACTIVE_HCTL_END(0));
93 mdp4_write(mdp4_kms
, REG_MDP4_DTV_ACTIVE_VSTART
, 0);
94 mdp4_write(mdp4_kms
, REG_MDP4_DTV_ACTIVE_VEND
, 0);
97 static void mdp4_dtv_encoder_disable(struct drm_encoder
*encoder
)
99 struct mdp4_dtv_encoder
*mdp4_dtv_encoder
= to_mdp4_dtv_encoder(encoder
);
100 struct mdp4_kms
*mdp4_kms
= get_kms(encoder
);
102 if (WARN_ON(!mdp4_dtv_encoder
->enabled
))
105 mdp4_write(mdp4_kms
, REG_MDP4_DTV_ENABLE
, 0);
108 * Wait for a vsync so we know the ENABLE=0 latched before
109 * the (connector) source of the vsync's gets disabled,
110 * otherwise we end up in a funny state if we re-enable
111 * before the disable latches, which results that some of
112 * the settings changes for the new modeset (like new
113 * scanout buffer) don't latch properly..
115 mdp_irq_wait(&mdp4_kms
->base
, MDP4_IRQ_EXTERNAL_VSYNC
);
117 clk_disable_unprepare(mdp4_dtv_encoder
->hdmi_clk
);
118 clk_disable_unprepare(mdp4_dtv_encoder
->mdp_clk
);
120 mdp4_dtv_encoder
->enabled
= false;
123 static void mdp4_dtv_encoder_enable(struct drm_encoder
*encoder
)
125 struct drm_device
*dev
= encoder
->dev
;
126 struct mdp4_dtv_encoder
*mdp4_dtv_encoder
= to_mdp4_dtv_encoder(encoder
);
127 struct mdp4_kms
*mdp4_kms
= get_kms(encoder
);
128 unsigned long pc
= mdp4_dtv_encoder
->pixclock
;
131 if (WARN_ON(mdp4_dtv_encoder
->enabled
))
134 mdp4_crtc_set_config(encoder
->crtc
,
135 MDP4_DMA_CONFIG_R_BPC(BPC8
) |
136 MDP4_DMA_CONFIG_G_BPC(BPC8
) |
137 MDP4_DMA_CONFIG_B_BPC(BPC8
) |
138 MDP4_DMA_CONFIG_PACK(0x21));
139 mdp4_crtc_set_intf(encoder
->crtc
, INTF_LCDC_DTV
, 1);
141 DBG("setting mdp_clk=%lu", pc
);
143 ret
= clk_set_rate(mdp4_dtv_encoder
->mdp_clk
, pc
);
145 DRM_DEV_ERROR(dev
->dev
, "failed to set mdp_clk to %lu: %d\n",
148 ret
= clk_prepare_enable(mdp4_dtv_encoder
->mdp_clk
);
150 DRM_DEV_ERROR(dev
->dev
, "failed to enabled mdp_clk: %d\n", ret
);
152 ret
= clk_prepare_enable(mdp4_dtv_encoder
->hdmi_clk
);
154 DRM_DEV_ERROR(dev
->dev
, "failed to enable hdmi_clk: %d\n", ret
);
156 mdp4_write(mdp4_kms
, REG_MDP4_DTV_ENABLE
, 1);
158 mdp4_dtv_encoder
->enabled
= true;
161 static const struct drm_encoder_helper_funcs mdp4_dtv_encoder_helper_funcs
= {
162 .mode_set
= mdp4_dtv_encoder_mode_set
,
163 .enable
= mdp4_dtv_encoder_enable
,
164 .disable
= mdp4_dtv_encoder_disable
,
167 long mdp4_dtv_round_pixclk(struct drm_encoder
*encoder
, unsigned long rate
)
169 struct mdp4_dtv_encoder
*mdp4_dtv_encoder
= to_mdp4_dtv_encoder(encoder
);
170 return clk_round_rate(mdp4_dtv_encoder
->mdp_clk
, rate
);
173 /* initialize encoder */
174 struct drm_encoder
*mdp4_dtv_encoder_init(struct drm_device
*dev
)
176 struct drm_encoder
*encoder
= NULL
;
177 struct mdp4_dtv_encoder
*mdp4_dtv_encoder
;
180 mdp4_dtv_encoder
= kzalloc(sizeof(*mdp4_dtv_encoder
), GFP_KERNEL
);
181 if (!mdp4_dtv_encoder
) {
186 encoder
= &mdp4_dtv_encoder
->base
;
188 drm_encoder_init(dev
, encoder
, &mdp4_dtv_encoder_funcs
,
189 DRM_MODE_ENCODER_TMDS
, NULL
);
190 drm_encoder_helper_add(encoder
, &mdp4_dtv_encoder_helper_funcs
);
192 mdp4_dtv_encoder
->hdmi_clk
= devm_clk_get(dev
->dev
, "hdmi_clk");
193 if (IS_ERR(mdp4_dtv_encoder
->hdmi_clk
)) {
194 DRM_DEV_ERROR(dev
->dev
, "failed to get hdmi_clk\n");
195 ret
= PTR_ERR(mdp4_dtv_encoder
->hdmi_clk
);
199 mdp4_dtv_encoder
->mdp_clk
= devm_clk_get(dev
->dev
, "tv_clk");
200 if (IS_ERR(mdp4_dtv_encoder
->mdp_clk
)) {
201 DRM_DEV_ERROR(dev
->dev
, "failed to get tv_clk\n");
202 ret
= PTR_ERR(mdp4_dtv_encoder
->mdp_clk
);
210 mdp4_dtv_encoder_destroy(encoder
);