2 *-----------------------------------------------------------------------------
3 * Filename: emgd_encoder.c
5 *-----------------------------------------------------------------------------
6 * Copyright (c) 2002-2011, Intel Corporation.
8 * Permission is hereby granted, free of charge, to any person obtaining a copy
9 * of this software and associated documentation files (the "Software"), to deal
10 * in the Software without restriction, including without limitation the rights
11 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 * copies of the Software, and to permit persons to whom the Software is
13 * furnished to do so, subject to the following conditions:
15 * The above copyright notice and this permission notice shall be included in
16 * all copies or substantial portions of the Software.
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
26 *-----------------------------------------------------------------------------
28 * Encoder / kenrel mode setting functions.
29 *-----------------------------------------------------------------------------
31 #define MODULE_NAME hal.oal
34 #include <drm_crtc_helper.h>
35 #include <linux/version.h>
37 #include <mode_dispatch.h>
38 #include "drm_emgd_private.h"
44 /*------------------------------------------------------------------------------
46 *------------------------------------------------------------------------------
48 extern int calculate_eld(igd_display_port_t *port,
49 igd_timing_info_t *timing_info);
53 static void emgd_encoder_destroy(struct drm_encoder *encoder);
54 static void emgd_encoder_dpms(struct drm_encoder *encoder, int mode);
55 static bool emgd_encoder_mode_fixup(struct drm_encoder *encoder,
56 struct drm_display_mode *mode,
57 struct drm_display_mode *adjusted_mode);
58 static void emgd_encoder_prepare(struct drm_encoder *encoder);
59 static void emgd_encoder_mode_set(struct drm_encoder *encoder,
60 struct drm_display_mode *mode,
61 struct drm_display_mode *adjusted_mode);
62 static void emgd_encoder_commit(struct drm_encoder *encoder);
65 const struct drm_encoder_funcs emgd_encoder_funcs = {
66 .destroy = emgd_encoder_destroy,
69 const struct drm_encoder_helper_funcs emgd_encoder_helper_funcs = {
70 .dpms = emgd_encoder_dpms,
71 .mode_fixup = emgd_encoder_mode_fixup,
72 .prepare = emgd_encoder_prepare,
73 .mode_set = emgd_encoder_mode_set,
74 .commit = emgd_encoder_commit,
81 * This function will put the encoder to either an ON or OFF state. Anything
82 * that is not DRM_MODE_DPMS_ON is treated as an off-state.
84 * @param encoder (IN) Encoder
85 * @param mode (IN) power mode
89 static void emgd_encoder_dpms(struct drm_encoder *encoder, int mode)
91 emgd_crtc_t *emgd_crtc = container_of(encoder->crtc, emgd_crtc_t, base);
92 emgd_encoder_t *emgd_encoder = container_of(encoder, emgd_encoder_t, base);
93 igd_display_port_t *igd_port = emgd_encoder->igd_port;
97 /* The following check is a work around for KMS tries to
98 * program both the crtcs and ports (LVDS and SDVO)
99 * even if it is in single mode. It results in a SIGSEGV.
100 * By putting this check we ensure that it moves forward
101 * only if there is a valid context associated with the
104 if(emgd_crtc->igd_pipe->owner) {
106 EMGD_DEBUG("Setting port %lx power to %d",
107 igd_port->port_number, mode);
111 case DRM_MODE_DPMS_ON:
112 mode_context->kms_dispatch->kms_program_port(emgd_encoder,
114 mode_context->kms_dispatch->kms_post_program_port(emgd_encoder,
118 case DRM_MODE_DPMS_STANDBY:
119 case DRM_MODE_DPMS_SUSPEND:
120 case DRM_MODE_DPMS_OFF:
121 mode_context->kms_dispatch->kms_program_port(emgd_encoder,
122 IGD_DISPLAY_DISABLE);
126 EMGD_ERROR_EXIT("Unsupported DPMS mode");
130 EMGD_DEBUG("Owner is null for this pipe");
139 * emgd_encoder_mode_fixup
141 * Called before a mode set, takes the input "mode", matches it to the closest
142 * supported mode, then put the supported mode into "adjusted_mode" to let the
145 * Note: We cannot handle centered and scaled mode with this. To handle this
146 * we need to program the pipe and the port to different sets of timings.
147 * The CRTC Helper does not allow this. It wants to send adjusted_mode
148 * to both the CRTC and the Encoder. We can maybe get around this by
149 * modifying the "mode" parameter, but that is not the right approach.
151 * @param encoder (IN) Encoder being prepared
152 * @param mode (IN) Requested mode
153 * @param adjusted_mode (IN) Encoder supported mode
155 * @return true, false (details TBD)
157 static bool emgd_encoder_mode_fixup(struct drm_encoder *encoder,
158 struct drm_display_mode *mode,
159 struct drm_display_mode *adjusted_mode)
161 struct drm_device *dev = NULL;
162 igd_context_t *context = NULL;
163 igd_display_port_t *port = NULL;
164 igd_framebuffer_info_t *fb_info = NULL;
165 emgd_encoder_t *emgd_encoder = NULL;
166 igd_timing_info_t *timing = NULL;
167 igd_display_info_t *pt_info = NULL;
168 emgd_crtc_t *emgd_crtc = NULL;
169 igd_display_pipe_t *pipe = NULL;
170 unsigned long existing_height = 0;
171 unsigned long existing_width = 0;
172 unsigned long existing_refresh = 0;
177 /* Check ajusted mode to see if it's valid. If not, populate it */
178 if (adjusted_mode->crtc_htotal == 0) {
179 EMGD_DEBUG("No valid mode in adjusted mode, setting valid mode");
180 drm_mode_set_crtcinfo(adjusted_mode, 0);
184 context = ((drm_emgd_priv_t *)dev->dev_private)->context;
185 emgd_encoder = container_of(encoder, emgd_encoder_t, base);
186 port = emgd_encoder->igd_port;
187 if (!port->pt_info) {
188 port->pt_info = kzalloc(sizeof(igd_display_info_t), GFP_KERNEL);
189 if (!port->pt_info) {
190 EMGD_DEBUG("Cannot allocate igd_display_into_t");
194 existing_height = port->pt_info->height;
195 existing_width = port->pt_info->width;
196 existing_refresh = port->pt_info->refresh;
197 pt_info = port->pt_info;
199 fb_info = kzalloc(sizeof(igd_framebuffer_info_t), GFP_KERNEL);
201 EMGD_DEBUG("Cannot allocate framebuffer info");
205 /* Get the dimension of the framebuffer linked to the CRTC. If it is
206 * smaller than the resolution, kms_match_mode will either center it
207 * or let the encoder hardware scale it */
208 fb_info->width = encoder->crtc->fb->width;
209 fb_info->height = encoder->crtc->fb->height;
210 EMGD_DEBUG("Setting fb_info to: %dx%d", fb_info->width, fb_info->height);
212 pt_info->width = mode->crtc_hdisplay;
213 pt_info->height = mode->crtc_vdisplay;
214 pt_info->refresh = mode->vrefresh;
215 pt_info->dclk = mode->synth_clock;
216 pt_info->htotal = mode->crtc_htotal;
217 pt_info->hblank_start = mode->crtc_hblank_start;
218 pt_info->hblank_end = mode->crtc_hblank_end;
219 pt_info->hsync_start = mode->crtc_hsync_start;
220 pt_info->hsync_end = mode->crtc_hsync_end;
221 pt_info->vtotal = mode->crtc_vtotal;
222 pt_info->vblank_start = mode->crtc_vblank_start;
223 pt_info->vblank_end = mode->crtc_vblank_end;
224 pt_info->vsync_start = mode->crtc_vsync_start;
225 pt_info->vsync_end = mode->crtc_vsync_end;
226 pt_info->mode_number = mode->clock_index;
228 EMGD_DEBUG("Setting pt_info to: %dx%d", pt_info->width, pt_info->height);
230 ret = mode_context->kms_dispatch->kms_match_mode((void *)emgd_encoder,
231 (void *)fb_info, &timing);
234 adjusted_mode->crtc_hdisplay = timing->width;
235 adjusted_mode->crtc_vdisplay = timing->height;
236 adjusted_mode->vrefresh = timing->refresh;
237 adjusted_mode->synth_clock = timing->dclk;
238 adjusted_mode->crtc_htotal = timing->htotal;
239 adjusted_mode->crtc_hblank_start = timing->hblank_start;
240 adjusted_mode->crtc_hblank_end = timing->hblank_end;
241 adjusted_mode->crtc_hsync_start = timing->hsync_start;
242 adjusted_mode->crtc_hsync_end = timing->hsync_end;
243 adjusted_mode->crtc_vtotal = timing->vtotal;
244 adjusted_mode->crtc_vblank_start = timing->vblank_start;
245 adjusted_mode->crtc_vblank_end = timing->vblank_end;
246 adjusted_mode->crtc_vsync_start = timing->vsync_start;
247 adjusted_mode->crtc_vsync_end = timing->vsync_end;
248 adjusted_mode->clock_index = timing->mode_number;
249 adjusted_mode->private_flags = timing->mode_info_flags;
251 EMGD_DEBUG("(%dx%d@%d)->(%dx%d@%d)",
252 mode->crtc_hdisplay, mode->crtc_vdisplay, mode->vrefresh,
253 adjusted_mode->crtc_hdisplay, adjusted_mode->crtc_vdisplay,
254 adjusted_mode->vrefresh);
256 /* Check our new mode against what currently there
257 * to see if we can do a seamless mode-set
259 if (emgd_encoder->flags & ENCODER_FLAG_FIRST_ALTER) {
260 if (mode_context->fw_info) {
262 emgd_crtc = container_of(encoder->crtc, emgd_crtc_t, base);
263 pipe = emgd_crtc->igd_pipe;
265 existing_width = mode_context->fw_info->
266 timing_arr[pipe->pipe_num].width;
267 existing_height = mode_context->fw_info->
268 timing_arr[pipe->pipe_num].height;
269 existing_refresh = mode_context->fw_info->
270 timing_arr[pipe->pipe_num].refresh;
275 if (adjusted_mode->crtc_hdisplay == existing_width &&
276 adjusted_mode->crtc_vdisplay == existing_height) {
278 if (abs(adjusted_mode->vrefresh - existing_refresh) <= 1) {
279 emgd_encoder->flags |= ENCODER_FLAG_SEAMLESS;
293 * emgd_encoder_prepare
295 * Based on the available documentation at the moment, this function gets
296 * called right before a mode change. Its job is to turn off the display.
298 * @param encoder (IN) Encoder being prepared
302 static void emgd_encoder_prepare(struct drm_encoder *encoder)
304 struct drm_encoder_helper_funcs *encoder_funcs;
305 emgd_encoder_t *emgd_encoder;
309 emgd_encoder = container_of(encoder, emgd_encoder_t, base);
311 if (!(emgd_encoder->flags & ENCODER_FLAG_SEAMLESS)) {
312 encoder_funcs = encoder->helper_private;
313 encoder_funcs->dpms(encoder, DRM_MODE_DPMS_OFF);
316 emgd_encoder->flags &= ~ENCODER_FLAG_FIRST_ALTER;
324 * emgd_encoder_commit
326 * This function commits the mode change sequence by actually programming
329 * @param encoder (IN) Encoder being prepared
333 static void emgd_encoder_commit(struct drm_encoder *encoder)
335 struct drm_encoder_helper_funcs *encoder_funcs;
336 emgd_encoder_t *emgd_encoder = NULL;
337 emgd_crtc_t *emgd_crtc;
338 igd_display_port_t *port;
339 igd_display_pipe_t *pipe;
343 emgd_encoder = container_of(encoder, emgd_encoder_t, base);
346 if (!(emgd_encoder->flags & ENCODER_FLAG_SEAMLESS)) {
348 port = emgd_encoder->igd_port;
349 emgd_crtc = container_of(encoder->crtc, emgd_crtc_t, base);
350 pipe = emgd_crtc->igd_pipe;
352 /* mode_context->kms_dispatch->kms_program_port(emgd_encoder,
353 IGD_DISPLAY_ENABLE);*/
355 port->pd_driver->set_mode(port->pd_context, pipe->timing,
356 1<<pipe->pipe_num);*/
359 encoder_funcs = encoder->helper_private;
360 encoder_funcs->dpms(encoder, DRM_MODE_DPMS_ON);
363 /* Reset our seamless variable */
364 emgd_encoder->flags &= ~ENCODER_FLAG_SEAMLESS;
366 /* TODO: Add call to check_display */
374 * emgd_encoder_mode_set
376 * This function saves the requested timings into the Port Timing Info
377 * structure. At emgd_encoder_commit() time we should be using these
378 * timings to program the port, but currently we are using timings from
379 * the pipe. This is fine for now, but at one point we should investigate
380 * the centering case in which the port timings may not match the pipe timings.
382 * @param encoder (IN) Encoder being prepared
384 * @param adjusted_mode (IN)
388 static void emgd_encoder_mode_set(struct drm_encoder *encoder,
389 struct drm_display_mode *mode,
390 struct drm_display_mode *adjusted_mode)
392 emgd_crtc_t *emgd_crtc = NULL;
393 emgd_encoder_t *emgd_encoder = NULL;
394 igd_display_pipe_t *pipe = NULL;
395 igd_display_port_t *port = NULL;
396 pd_timing_t *timing = NULL;
401 emgd_encoder = container_of(encoder, emgd_encoder_t, base);
403 if (!(emgd_encoder->flags & ENCODER_FLAG_SEAMLESS)) {
404 port = emgd_encoder->igd_port;
405 emgd_crtc = container_of(encoder->crtc, emgd_crtc_t, base);
406 pipe = emgd_crtc->igd_pipe;
409 timing = (pd_timing_t *)pipe->timing;
411 if (NULL == port->pt_info) {
412 port->pt_info = kzalloc(sizeof(igd_display_info_t), GFP_KERNEL);
414 if (!port->pt_info) {
415 EMGD_ERROR_EXIT("Unable to allocate pt_info.");
420 port->pt_info->width = adjusted_mode->crtc_hdisplay;
421 port->pt_info->height = adjusted_mode->crtc_vdisplay;
422 port->pt_info->refresh = adjusted_mode->vrefresh;
423 port->pt_info->dclk = adjusted_mode->synth_clock;
424 port->pt_info->htotal = adjusted_mode->crtc_htotal;
425 port->pt_info->hblank_start = adjusted_mode->crtc_hblank_start;
426 port->pt_info->hblank_end = adjusted_mode->crtc_hblank_end;
427 port->pt_info->hsync_start = adjusted_mode->crtc_hsync_start;
428 port->pt_info->hsync_end = adjusted_mode->crtc_hsync_end;
429 port->pt_info->vtotal = adjusted_mode->crtc_vtotal;
430 port->pt_info->vblank_start = adjusted_mode->crtc_vblank_start;
431 port->pt_info->vblank_end = adjusted_mode->crtc_vblank_end;
432 port->pt_info->vsync_start = adjusted_mode->crtc_vsync_start;
433 port->pt_info->vsync_end = adjusted_mode->crtc_vsync_end;
434 port->pt_info->mode_number = adjusted_mode->clock_index;
435 port->pt_info->flags = adjusted_mode->private_flags;
437 port->pt_info->x_offset = timing->x_offset;
438 port->pt_info->y_offset = timing->y_offset;
439 port->pt_info->flags |= IGD_DISPLAY_ENABLE;
442 EMGD_DEBUG("Calculate ELD");
443 if (calculate_eld(port, timing)) {
444 EMGD_DEBUG("Fail to calculate ELD");
448 EMGD_ERROR("Trying to set the mode without a pipe attached.");
458 * emgd_encoder_destroy
460 * Frees the resources allocated for this encoder during "create_encoder()"
462 * @param encoder (IN) Encoder to be freed
466 static void emgd_encoder_destroy(struct drm_encoder *encoder)
468 emgd_encoder_t *emgd_encoder;
471 emgd_encoder = container_of(encoder, emgd_encoder_t, base);
473 drm_encoder_cleanup(encoder);