2 * Copyright © 2010 Intel Corporation
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
11 * The above copyright notice and this permission notice (including the next
12 * paragraph) shall be included in all copies or substantial portions of the
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21 * DEALINGS IN THE SOFTWARE.
24 * jim liu <jim.liu@intel.com>
25 * Jackie Li<yaodong.li@intel.com>
28 #include <linux/module.h>
30 #include "mdfld_dsi_output.h"
31 #include "mdfld_dsi_dpi.h"
32 #include "mdfld_output.h"
33 #include "mdfld_dsi_pkg_sender.h"
34 #include "tc35876x-dsi-lvds.h"
35 #include <linux/pm_runtime.h>
36 #include <asm/intel_scu_ipc.h>
38 /* get the LABC from command line. */
39 static int LABC_control
= 1;
42 module_param(LABC_control
, int, 0644);
45 static int __init
parse_LABC_control(char *arg
)
47 /* LABC control can be passed in as a cmdline parameter */
48 /* to enable this feature add LABC=1 to cmdline */
49 /* to disable this feature add LABC=0 to cmdline */
53 if (!strcasecmp(arg
, "0"))
55 else if (!strcasecmp(arg
, "1"))
60 early_param("LABC", parse_LABC_control
);
64 * Check and see if the generic control or data buffer is empty and ready.
66 void mdfld_dsi_gen_fifo_ready(struct drm_device
*dev
, u32 gen_fifo_stat_reg
,
69 u32 GEN_BF_time_out_count
;
71 /* Check MIPI Adatper command registers */
72 for (GEN_BF_time_out_count
= 0;
73 GEN_BF_time_out_count
< GEN_FB_TIME_OUT
;
74 GEN_BF_time_out_count
++) {
75 if ((REG_READ(gen_fifo_stat_reg
) & fifo_stat
) == fifo_stat
)
80 if (GEN_BF_time_out_count
== GEN_FB_TIME_OUT
)
81 DRM_ERROR("mdfld_dsi_gen_fifo_ready, Timeout. gen_fifo_stat_reg = 0x%x.\n",
86 * Manage the DSI MIPI keyboard and display brightness.
87 * FIXME: this is exported to OSPM code. should work out an specific
88 * display interface to OSPM.
91 void mdfld_dsi_brightness_init(struct mdfld_dsi_config
*dsi_config
, int pipe
)
93 struct mdfld_dsi_pkg_sender
*sender
=
94 mdfld_dsi_get_pkg_sender(dsi_config
);
95 struct drm_device
*dev
;
96 struct drm_psb_private
*dev_priv
;
100 DRM_ERROR("No sender found\n");
105 dev_priv
= dev
->dev_private
;
107 /* Set default display backlight value to 85% (0xd8)*/
108 mdfld_dsi_send_mcs_short(sender
, write_display_brightness
, 0xd8, 1,
111 /* Set minimum brightness setting of CABC function to 20% (0x33)*/
112 mdfld_dsi_send_mcs_short(sender
, write_cabc_min_bright
, 0x33, 1, true);
114 /* Enable backlight or/and LABC */
115 gen_ctrl_val
= BRIGHT_CNTL_BLOCK_ON
| DISPLAY_DIMMING_ON
|
117 if (LABC_control
== 1)
118 gen_ctrl_val
|= DISPLAY_DIMMING_ON
| DISPLAY_BRIGHTNESS_AUTO
121 if (LABC_control
== 1)
122 gen_ctrl_val
|= AMBIENT_LIGHT_SENSE_ON
;
124 dev_priv
->mipi_ctrl_display
= gen_ctrl_val
;
126 mdfld_dsi_send_mcs_short(sender
, write_ctrl_display
, (u8
)gen_ctrl_val
,
129 mdfld_dsi_send_mcs_short(sender
, write_ctrl_cabc
, UI_IMAGE
, 1, true);
132 void mdfld_dsi_brightness_control(struct drm_device
*dev
, int pipe
, int level
)
134 struct mdfld_dsi_pkg_sender
*sender
;
135 struct drm_psb_private
*dev_priv
;
136 struct mdfld_dsi_config
*dsi_config
;
137 u32 gen_ctrl_val
= 0;
138 int p_type
= TMD_VID
;
140 if (!dev
|| (pipe
!= 0 && pipe
!= 2)) {
141 DRM_ERROR("Invalid parameter\n");
145 p_type
= mdfld_get_panel_type(dev
, 0);
147 dev_priv
= dev
->dev_private
;
150 dsi_config
= dev_priv
->dsi_configs
[1];
152 dsi_config
= dev_priv
->dsi_configs
[0];
154 sender
= mdfld_dsi_get_pkg_sender(dsi_config
);
157 DRM_ERROR("No sender found\n");
161 gen_ctrl_val
= (level
* 0xff / MDFLD_DSI_BRIGHTNESS_MAX_LEVEL
) & 0xff;
163 dev_dbg(sender
->dev
->dev
, "pipe = %d, gen_ctrl_val = %d.\n",
166 if (p_type
== TMD_VID
) {
167 /* Set display backlight value */
168 mdfld_dsi_send_mcs_short(sender
, tmd_write_display_brightness
,
169 (u8
)gen_ctrl_val
, 1, true);
171 /* Set display backlight value */
172 mdfld_dsi_send_mcs_short(sender
, write_display_brightness
,
173 (u8
)gen_ctrl_val
, 1, true);
175 /* Enable backlight control */
179 gen_ctrl_val
= dev_priv
->mipi_ctrl_display
;
181 mdfld_dsi_send_mcs_short(sender
, write_ctrl_display
,
182 (u8
)gen_ctrl_val
, 1, true);
186 static int mdfld_dsi_get_panel_status(struct mdfld_dsi_config
*dsi_config
,
187 u8 dcs
, u32
*data
, bool hs
)
189 struct mdfld_dsi_pkg_sender
*sender
190 = mdfld_dsi_get_pkg_sender(dsi_config
);
192 if (!sender
|| !data
) {
193 DRM_ERROR("Invalid parameter\n");
197 return mdfld_dsi_read_mcs(sender
, dcs
, data
, 1, hs
);
200 int mdfld_dsi_get_power_mode(struct mdfld_dsi_config
*dsi_config
, u32
*mode
,
203 if (!dsi_config
|| !mode
) {
204 DRM_ERROR("Invalid parameter\n");
208 return mdfld_dsi_get_panel_status(dsi_config
, 0x0a, mode
, hs
);
212 * NOTE: this function was used by OSPM.
213 * TODO: will be removed later, should work out display interfaces for OSPM
215 void mdfld_dsi_controller_init(struct mdfld_dsi_config
*dsi_config
, int pipe
)
217 if (!dsi_config
|| ((pipe
!= 0) && (pipe
!= 2))) {
218 DRM_ERROR("Invalid parameters\n");
222 mdfld_dsi_dpi_controller_init(dsi_config
, pipe
);
225 static void mdfld_dsi_connector_save(struct drm_connector
*connector
)
229 static void mdfld_dsi_connector_restore(struct drm_connector
*connector
)
233 /* FIXME: start using the force parameter */
234 static enum drm_connector_status
235 mdfld_dsi_connector_detect(struct drm_connector
*connector
, bool force
)
237 struct mdfld_dsi_connector
*dsi_connector
238 = mdfld_dsi_connector(connector
);
240 dsi_connector
->status
= connector_status_connected
;
242 return dsi_connector
->status
;
245 static int mdfld_dsi_connector_set_property(struct drm_connector
*connector
,
246 struct drm_property
*property
,
249 struct drm_encoder
*encoder
= connector
->encoder
;
251 if (!strcmp(property
->name
, "scaling mode") && encoder
) {
252 struct gma_crtc
*gma_crtc
= to_gma_crtc(encoder
->crtc
);
260 case DRM_MODE_SCALE_FULLSCREEN
:
262 case DRM_MODE_SCALE_NO_SCALE
:
264 case DRM_MODE_SCALE_ASPECT
:
270 if (drm_object_property_get_value(&connector
->base
, property
, &val
))
276 if (drm_object_property_set_value(&connector
->base
,
280 centerechange
= (val
== DRM_MODE_SCALE_NO_SCALE
) ||
281 (value
== DRM_MODE_SCALE_NO_SCALE
);
283 if (gma_crtc
->saved_mode
.hdisplay
!= 0 &&
284 gma_crtc
->saved_mode
.vdisplay
!= 0) {
286 if (!drm_crtc_helper_set_mode(encoder
->crtc
,
287 &gma_crtc
->saved_mode
,
293 struct drm_encoder_helper_funcs
*funcs
=
294 encoder
->helper_private
;
295 funcs
->mode_set(encoder
,
296 &gma_crtc
->saved_mode
,
297 &gma_crtc
->saved_adjusted_mode
);
300 } else if (!strcmp(property
->name
, "backlight") && encoder
) {
301 if (drm_object_property_set_value(&connector
->base
, property
,
305 gma_backlight_set(encoder
->dev
, value
);
313 static void mdfld_dsi_connector_destroy(struct drm_connector
*connector
)
315 struct mdfld_dsi_connector
*dsi_connector
=
316 mdfld_dsi_connector(connector
);
317 struct mdfld_dsi_pkg_sender
*sender
;
321 drm_sysfs_connector_remove(connector
);
322 drm_connector_cleanup(connector
);
323 sender
= dsi_connector
->pkg_sender
;
324 mdfld_dsi_pkg_sender_destroy(sender
);
325 kfree(dsi_connector
);
328 static int mdfld_dsi_connector_get_modes(struct drm_connector
*connector
)
330 struct mdfld_dsi_connector
*dsi_connector
=
331 mdfld_dsi_connector(connector
);
332 struct mdfld_dsi_config
*dsi_config
=
333 mdfld_dsi_get_config(dsi_connector
);
334 struct drm_display_mode
*fixed_mode
= dsi_config
->fixed_mode
;
335 struct drm_display_mode
*dup_mode
= NULL
;
336 struct drm_device
*dev
= connector
->dev
;
338 connector
->display_info
.min_vfreq
= 0;
339 connector
->display_info
.max_vfreq
= 200;
340 connector
->display_info
.min_hfreq
= 0;
341 connector
->display_info
.max_hfreq
= 200;
344 dev_dbg(dev
->dev
, "fixed_mode %dx%d\n",
345 fixed_mode
->hdisplay
, fixed_mode
->vdisplay
);
346 dup_mode
= drm_mode_duplicate(dev
, fixed_mode
);
347 drm_mode_probed_add(connector
, dup_mode
);
350 DRM_ERROR("Didn't get any modes!\n");
354 static int mdfld_dsi_connector_mode_valid(struct drm_connector
*connector
,
355 struct drm_display_mode
*mode
)
357 struct mdfld_dsi_connector
*dsi_connector
=
358 mdfld_dsi_connector(connector
);
359 struct mdfld_dsi_config
*dsi_config
=
360 mdfld_dsi_get_config(dsi_connector
);
361 struct drm_display_mode
*fixed_mode
= dsi_config
->fixed_mode
;
363 if (mode
->flags
& DRM_MODE_FLAG_DBLSCAN
)
364 return MODE_NO_DBLESCAN
;
366 if (mode
->flags
& DRM_MODE_FLAG_INTERLACE
)
367 return MODE_NO_INTERLACE
;
370 * FIXME: current DC has no fitting unit, reject any mode setting
372 * Will figure out a way to do up-scaling(pannel fitting) later.
375 if (mode
->hdisplay
!= fixed_mode
->hdisplay
)
378 if (mode
->vdisplay
!= fixed_mode
->vdisplay
)
385 static void mdfld_dsi_connector_dpms(struct drm_connector
*connector
, int mode
)
387 if (mode
== connector
->dpms
)
390 /*first, execute dpms*/
392 drm_helper_connector_dpms(connector
, mode
);
395 static struct drm_encoder
*mdfld_dsi_connector_best_encoder(
396 struct drm_connector
*connector
)
398 struct mdfld_dsi_connector
*dsi_connector
=
399 mdfld_dsi_connector(connector
);
400 struct mdfld_dsi_config
*dsi_config
=
401 mdfld_dsi_get_config(dsi_connector
);
402 return &dsi_config
->encoder
->base
.base
;
405 /*DSI connector funcs*/
406 static const struct drm_connector_funcs mdfld_dsi_connector_funcs
= {
407 .dpms
= /*drm_helper_connector_dpms*/mdfld_dsi_connector_dpms
,
408 .save
= mdfld_dsi_connector_save
,
409 .restore
= mdfld_dsi_connector_restore
,
410 .detect
= mdfld_dsi_connector_detect
,
411 .fill_modes
= drm_helper_probe_single_connector_modes
,
412 .set_property
= mdfld_dsi_connector_set_property
,
413 .destroy
= mdfld_dsi_connector_destroy
,
416 /*DSI connector helper funcs*/
417 static const struct drm_connector_helper_funcs
418 mdfld_dsi_connector_helper_funcs
= {
419 .get_modes
= mdfld_dsi_connector_get_modes
,
420 .mode_valid
= mdfld_dsi_connector_mode_valid
,
421 .best_encoder
= mdfld_dsi_connector_best_encoder
,
424 static int mdfld_dsi_get_default_config(struct drm_device
*dev
,
425 struct mdfld_dsi_config
*config
, int pipe
)
427 if (!dev
|| !config
) {
428 DRM_ERROR("Invalid parameters");
433 if (mdfld_get_panel_type(dev
, pipe
) == TC35876X
)
434 config
->lane_count
= 4;
436 config
->lane_count
= 2;
437 config
->channel_num
= 0;
439 if (mdfld_get_panel_type(dev
, pipe
) == TMD_VID
)
440 config
->video_mode
= MDFLD_DSI_VIDEO_NON_BURST_MODE_SYNC_PULSE
;
441 else if (mdfld_get_panel_type(dev
, pipe
) == TC35876X
)
443 MDFLD_DSI_VIDEO_NON_BURST_MODE_SYNC_EVENTS
;
445 config
->video_mode
= MDFLD_DSI_VIDEO_BURST_MODE
;
450 int mdfld_dsi_panel_reset(int pipe
)
463 DRM_ERROR("Invalid output\n");
467 ret
= gpio_request(gpio
, "gfx");
469 DRM_ERROR("gpio_rqueset failed\n");
473 ret
= gpio_direction_output(gpio
, 1);
475 DRM_ERROR("gpio_direction_output failed\n");
482 if (gpio_is_valid(gpio
))
491 * @pipe pipe number. 0 or 2
494 * Do the initialization of a MIPI output, including create DRM mode objects
495 * initialization of DSI output on @pipe
497 void mdfld_dsi_output_init(struct drm_device
*dev
,
499 const struct panel_funcs
*p_vid_funcs
)
501 struct mdfld_dsi_config
*dsi_config
;
502 struct mdfld_dsi_connector
*dsi_connector
;
503 struct drm_connector
*connector
;
504 struct mdfld_dsi_encoder
*encoder
;
505 struct drm_psb_private
*dev_priv
= dev
->dev_private
;
506 struct panel_info dsi_panel_info
;
507 u32 width_mm
, height_mm
;
509 dev_dbg(dev
->dev
, "init DSI output on pipe %d\n", pipe
);
511 if (pipe
!= 0 && pipe
!= 2) {
512 DRM_ERROR("Invalid parameter\n");
516 /*create a new connetor*/
517 dsi_connector
= kzalloc(sizeof(struct mdfld_dsi_connector
), GFP_KERNEL
);
518 if (!dsi_connector
) {
519 DRM_ERROR("No memory");
523 dsi_connector
->pipe
= pipe
;
525 dsi_config
= kzalloc(sizeof(struct mdfld_dsi_config
),
528 DRM_ERROR("cannot allocate memory for DSI config\n");
531 mdfld_dsi_get_default_config(dev
, dsi_config
, pipe
);
533 dsi_connector
->private = dsi_config
;
535 dsi_config
->changed
= 1;
536 dsi_config
->dev
= dev
;
538 dsi_config
->fixed_mode
= p_vid_funcs
->get_config_mode(dev
);
539 if (p_vid_funcs
->get_panel_info(dev
, pipe
, &dsi_panel_info
))
542 width_mm
= dsi_panel_info
.width_mm
;
543 height_mm
= dsi_panel_info
.height_mm
;
545 dsi_config
->mode
= dsi_config
->fixed_mode
;
546 dsi_config
->connector
= dsi_connector
;
548 if (!dsi_config
->fixed_mode
) {
549 DRM_ERROR("No pannel fixed mode was found\n");
553 if (pipe
&& dev_priv
->dsi_configs
[0]) {
554 dsi_config
->dvr_ic_inited
= 0;
555 dev_priv
->dsi_configs
[1] = dsi_config
;
556 } else if (pipe
== 0) {
557 dsi_config
->dvr_ic_inited
= 1;
558 dev_priv
->dsi_configs
[0] = dsi_config
;
560 DRM_ERROR("Trying to init MIPI1 before MIPI0\n");
565 connector
= &dsi_connector
->base
.base
;
566 drm_connector_init(dev
, connector
, &mdfld_dsi_connector_funcs
,
567 DRM_MODE_CONNECTOR_LVDS
);
568 drm_connector_helper_add(connector
, &mdfld_dsi_connector_helper_funcs
);
570 connector
->display_info
.subpixel_order
= SubPixelHorizontalRGB
;
571 connector
->display_info
.width_mm
= width_mm
;
572 connector
->display_info
.height_mm
= height_mm
;
573 connector
->interlace_allowed
= false;
574 connector
->doublescan_allowed
= false;
576 /*attach properties*/
577 drm_object_attach_property(&connector
->base
,
578 dev
->mode_config
.scaling_mode_property
,
579 DRM_MODE_SCALE_FULLSCREEN
);
580 drm_object_attach_property(&connector
->base
,
581 dev_priv
->backlight_property
,
582 MDFLD_DSI_BRIGHTNESS_MAX_LEVEL
);
584 /*init DSI package sender on this output*/
585 if (mdfld_dsi_pkg_sender_init(dsi_connector
, pipe
)) {
586 DRM_ERROR("Package Sender initialization failed on pipe %d\n",
591 encoder
= mdfld_dsi_dpi_init(dev
, dsi_connector
, p_vid_funcs
);
593 DRM_ERROR("Create DPI encoder failed\n");
596 encoder
->private = dsi_config
;
597 dsi_config
->encoder
= encoder
;
598 encoder
->base
.type
= (pipe
== 0) ? INTEL_OUTPUT_MIPI
:
600 drm_sysfs_connector_add(connector
);
603 /*TODO: add code to destroy outputs on error*/
606 mdfld_dsi_pkg_sender_destroy(dsi_connector
->pkg_sender
);
608 drm_connector_cleanup(connector
);
610 kfree(dsi_config
->fixed_mode
);
613 kfree(dsi_connector
);