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
= sender
->dev
;
96 struct drm_psb_private
*dev_priv
= dev
->dev_private
;
100 DRM_ERROR("No sender found\n");
104 /* Set default display backlight value to 85% (0xd8)*/
105 mdfld_dsi_send_mcs_short(sender
, write_display_brightness
, 0xd8, 1,
108 /* Set minimum brightness setting of CABC function to 20% (0x33)*/
109 mdfld_dsi_send_mcs_short(sender
, write_cabc_min_bright
, 0x33, 1, true);
111 /* Enable backlight or/and LABC */
112 gen_ctrl_val
= BRIGHT_CNTL_BLOCK_ON
| DISPLAY_DIMMING_ON
|
114 if (LABC_control
== 1)
115 gen_ctrl_val
|= DISPLAY_DIMMING_ON
| DISPLAY_BRIGHTNESS_AUTO
118 if (LABC_control
== 1)
119 gen_ctrl_val
|= AMBIENT_LIGHT_SENSE_ON
;
121 dev_priv
->mipi_ctrl_display
= gen_ctrl_val
;
123 mdfld_dsi_send_mcs_short(sender
, write_ctrl_display
, (u8
)gen_ctrl_val
,
126 mdfld_dsi_send_mcs_short(sender
, write_ctrl_cabc
, UI_IMAGE
, 1, true);
129 void mdfld_dsi_brightness_control(struct drm_device
*dev
, int pipe
, int level
)
131 struct mdfld_dsi_pkg_sender
*sender
;
132 struct drm_psb_private
*dev_priv
;
133 struct mdfld_dsi_config
*dsi_config
;
134 u32 gen_ctrl_val
= 0;
135 int p_type
= TMD_VID
;
137 if (!dev
|| (pipe
!= 0 && pipe
!= 2)) {
138 DRM_ERROR("Invalid parameter\n");
142 p_type
= mdfld_get_panel_type(dev
, 0);
144 dev_priv
= dev
->dev_private
;
147 dsi_config
= dev_priv
->dsi_configs
[1];
149 dsi_config
= dev_priv
->dsi_configs
[0];
151 sender
= mdfld_dsi_get_pkg_sender(dsi_config
);
154 DRM_ERROR("No sender found\n");
158 gen_ctrl_val
= (level
* 0xff / MDFLD_DSI_BRIGHTNESS_MAX_LEVEL
) & 0xff;
160 dev_dbg(sender
->dev
->dev
, "pipe = %d, gen_ctrl_val = %d.\n",
163 if (p_type
== TMD_VID
) {
164 /* Set display backlight value */
165 mdfld_dsi_send_mcs_short(sender
, tmd_write_display_brightness
,
166 (u8
)gen_ctrl_val
, 1, true);
168 /* Set display backlight value */
169 mdfld_dsi_send_mcs_short(sender
, write_display_brightness
,
170 (u8
)gen_ctrl_val
, 1, true);
172 /* Enable backlight control */
176 gen_ctrl_val
= dev_priv
->mipi_ctrl_display
;
178 mdfld_dsi_send_mcs_short(sender
, write_ctrl_display
,
179 (u8
)gen_ctrl_val
, 1, true);
183 static int mdfld_dsi_get_panel_status(struct mdfld_dsi_config
*dsi_config
,
184 u8 dcs
, u32
*data
, bool hs
)
186 struct mdfld_dsi_pkg_sender
*sender
187 = mdfld_dsi_get_pkg_sender(dsi_config
);
189 if (!sender
|| !data
) {
190 DRM_ERROR("Invalid parameter\n");
194 return mdfld_dsi_read_mcs(sender
, dcs
, data
, 1, hs
);
197 int mdfld_dsi_get_power_mode(struct mdfld_dsi_config
*dsi_config
, u32
*mode
,
200 if (!dsi_config
|| !mode
) {
201 DRM_ERROR("Invalid parameter\n");
205 return mdfld_dsi_get_panel_status(dsi_config
, 0x0a, mode
, hs
);
209 * NOTE: this function was used by OSPM.
210 * TODO: will be removed later, should work out display interfaces for OSPM
212 void mdfld_dsi_controller_init(struct mdfld_dsi_config
*dsi_config
, int pipe
)
214 if (!dsi_config
|| ((pipe
!= 0) && (pipe
!= 2))) {
215 DRM_ERROR("Invalid parameters\n");
219 mdfld_dsi_dpi_controller_init(dsi_config
, pipe
);
222 static void mdfld_dsi_connector_save(struct drm_connector
*connector
)
226 static void mdfld_dsi_connector_restore(struct drm_connector
*connector
)
230 /* FIXME: start using the force parameter */
231 static enum drm_connector_status
232 mdfld_dsi_connector_detect(struct drm_connector
*connector
, bool force
)
234 struct mdfld_dsi_connector
*dsi_connector
235 = mdfld_dsi_connector(connector
);
237 dsi_connector
->status
= connector_status_connected
;
239 return dsi_connector
->status
;
242 static int mdfld_dsi_connector_set_property(struct drm_connector
*connector
,
243 struct drm_property
*property
,
246 struct drm_encoder
*encoder
= connector
->encoder
;
248 if (!strcmp(property
->name
, "scaling mode") && encoder
) {
249 struct psb_intel_crtc
*psb_crtc
=
250 to_psb_intel_crtc(encoder
->crtc
);
258 case DRM_MODE_SCALE_FULLSCREEN
:
260 case DRM_MODE_SCALE_NO_SCALE
:
262 case DRM_MODE_SCALE_ASPECT
:
268 if (drm_connector_property_get_value(connector
, property
, &val
))
274 if (drm_connector_property_set_value(connector
,
278 centerechange
= (val
== DRM_MODE_SCALE_NO_SCALE
) ||
279 (value
== DRM_MODE_SCALE_NO_SCALE
);
281 if (psb_crtc
->saved_mode
.hdisplay
!= 0 &&
282 psb_crtc
->saved_mode
.vdisplay
!= 0) {
284 if (!drm_crtc_helper_set_mode(encoder
->crtc
,
285 &psb_crtc
->saved_mode
,
291 struct drm_encoder_helper_funcs
*funcs
=
292 encoder
->helper_private
;
293 funcs
->mode_set(encoder
,
294 &psb_crtc
->saved_mode
,
295 &psb_crtc
->saved_adjusted_mode
);
298 } else if (!strcmp(property
->name
, "backlight") && encoder
) {
299 if (drm_connector_property_set_value(connector
, property
,
303 #ifdef CONFIG_BACKLIGHT_CLASS_DEVICE
304 struct backlight_device
*psb_bd
;
306 psb_bd
= mdfld_get_backlight_device();
308 psb_bd
->props
.brightness
= value
;
309 mdfld_set_brightness(psb_bd
);
320 static void mdfld_dsi_connector_destroy(struct drm_connector
*connector
)
322 struct mdfld_dsi_connector
*dsi_connector
=
323 mdfld_dsi_connector(connector
);
324 struct mdfld_dsi_pkg_sender
*sender
;
328 drm_sysfs_connector_remove(connector
);
329 drm_connector_cleanup(connector
);
330 sender
= dsi_connector
->pkg_sender
;
331 mdfld_dsi_pkg_sender_destroy(sender
);
332 kfree(dsi_connector
);
335 static int mdfld_dsi_connector_get_modes(struct drm_connector
*connector
)
337 struct mdfld_dsi_connector
*dsi_connector
=
338 mdfld_dsi_connector(connector
);
339 struct mdfld_dsi_config
*dsi_config
=
340 mdfld_dsi_get_config(dsi_connector
);
341 struct drm_display_mode
*fixed_mode
= dsi_config
->fixed_mode
;
342 struct drm_display_mode
*dup_mode
= NULL
;
343 struct drm_device
*dev
= connector
->dev
;
345 connector
->display_info
.min_vfreq
= 0;
346 connector
->display_info
.max_vfreq
= 200;
347 connector
->display_info
.min_hfreq
= 0;
348 connector
->display_info
.max_hfreq
= 200;
351 dev_dbg(dev
->dev
, "fixed_mode %dx%d\n",
352 fixed_mode
->hdisplay
, fixed_mode
->vdisplay
);
353 dup_mode
= drm_mode_duplicate(dev
, fixed_mode
);
354 drm_mode_probed_add(connector
, dup_mode
);
357 DRM_ERROR("Didn't get any modes!\n");
361 static int mdfld_dsi_connector_mode_valid(struct drm_connector
*connector
,
362 struct drm_display_mode
*mode
)
364 struct mdfld_dsi_connector
*dsi_connector
=
365 mdfld_dsi_connector(connector
);
366 struct mdfld_dsi_config
*dsi_config
=
367 mdfld_dsi_get_config(dsi_connector
);
368 struct drm_display_mode
*fixed_mode
= dsi_config
->fixed_mode
;
370 if (mode
->flags
& DRM_MODE_FLAG_DBLSCAN
)
371 return MODE_NO_DBLESCAN
;
373 if (mode
->flags
& DRM_MODE_FLAG_INTERLACE
)
374 return MODE_NO_INTERLACE
;
377 * FIXME: current DC has no fitting unit, reject any mode setting
379 * Will figure out a way to do up-scaling(pannel fitting) later.
382 if (mode
->hdisplay
!= fixed_mode
->hdisplay
)
385 if (mode
->vdisplay
!= fixed_mode
->vdisplay
)
392 static void mdfld_dsi_connector_dpms(struct drm_connector
*connector
, int mode
)
394 if (mode
== connector
->dpms
)
397 /*first, execute dpms*/
399 drm_helper_connector_dpms(connector
, mode
);
402 static struct drm_encoder
*mdfld_dsi_connector_best_encoder(
403 struct drm_connector
*connector
)
405 struct mdfld_dsi_connector
*dsi_connector
=
406 mdfld_dsi_connector(connector
);
407 struct mdfld_dsi_config
*dsi_config
=
408 mdfld_dsi_get_config(dsi_connector
);
409 return &dsi_config
->encoder
->base
.base
;
412 /*DSI connector funcs*/
413 static const struct drm_connector_funcs mdfld_dsi_connector_funcs
= {
414 .dpms
= /*drm_helper_connector_dpms*/mdfld_dsi_connector_dpms
,
415 .save
= mdfld_dsi_connector_save
,
416 .restore
= mdfld_dsi_connector_restore
,
417 .detect
= mdfld_dsi_connector_detect
,
418 .fill_modes
= drm_helper_probe_single_connector_modes
,
419 .set_property
= mdfld_dsi_connector_set_property
,
420 .destroy
= mdfld_dsi_connector_destroy
,
423 /*DSI connector helper funcs*/
424 static const struct drm_connector_helper_funcs
425 mdfld_dsi_connector_helper_funcs
= {
426 .get_modes
= mdfld_dsi_connector_get_modes
,
427 .mode_valid
= mdfld_dsi_connector_mode_valid
,
428 .best_encoder
= mdfld_dsi_connector_best_encoder
,
431 static int mdfld_dsi_get_default_config(struct drm_device
*dev
,
432 struct mdfld_dsi_config
*config
, int pipe
)
434 if (!dev
|| !config
) {
435 DRM_ERROR("Invalid parameters");
440 if (mdfld_get_panel_type(dev
, pipe
) == TC35876X
)
441 config
->lane_count
= 4;
443 config
->lane_count
= 2;
444 config
->channel_num
= 0;
446 if (mdfld_get_panel_type(dev
, pipe
) == TMD_VID
)
447 config
->video_mode
= MDFLD_DSI_VIDEO_NON_BURST_MODE_SYNC_PULSE
;
448 else if (mdfld_get_panel_type(dev
, pipe
) == TC35876X
)
450 MDFLD_DSI_VIDEO_NON_BURST_MODE_SYNC_EVENTS
;
452 config
->video_mode
= MDFLD_DSI_VIDEO_BURST_MODE
;
457 int mdfld_dsi_panel_reset(int pipe
)
470 DRM_ERROR("Invalid output\n");
474 ret
= gpio_request(gpio
, "gfx");
476 DRM_ERROR("gpio_rqueset failed\n");
480 ret
= gpio_direction_output(gpio
, 1);
482 DRM_ERROR("gpio_direction_output failed\n");
489 if (gpio_is_valid(gpio
))
498 * @pipe pipe number. 0 or 2
501 * Do the initialization of a MIPI output, including create DRM mode objects
502 * initialization of DSI output on @pipe
504 void mdfld_dsi_output_init(struct drm_device
*dev
,
506 const struct panel_funcs
*p_vid_funcs
)
508 struct mdfld_dsi_config
*dsi_config
;
509 struct mdfld_dsi_connector
*dsi_connector
;
510 struct drm_connector
*connector
;
511 struct mdfld_dsi_encoder
*encoder
;
512 struct drm_psb_private
*dev_priv
= dev
->dev_private
;
513 struct panel_info dsi_panel_info
;
514 u32 width_mm
, height_mm
;
516 dev_dbg(dev
->dev
, "init DSI output on pipe %d\n", pipe
);
518 if (!dev
|| ((pipe
!= 0) && (pipe
!= 2))) {
519 DRM_ERROR("Invalid parameter\n");
523 /*create a new connetor*/
524 dsi_connector
= kzalloc(sizeof(struct mdfld_dsi_connector
), GFP_KERNEL
);
525 if (!dsi_connector
) {
526 DRM_ERROR("No memory");
530 dsi_connector
->pipe
= pipe
;
532 dsi_config
= kzalloc(sizeof(struct mdfld_dsi_config
),
535 DRM_ERROR("cannot allocate memory for DSI config\n");
538 mdfld_dsi_get_default_config(dev
, dsi_config
, pipe
);
540 dsi_connector
->private = dsi_config
;
542 dsi_config
->changed
= 1;
543 dsi_config
->dev
= dev
;
545 dsi_config
->fixed_mode
= p_vid_funcs
->get_config_mode(dev
);
546 if (p_vid_funcs
->get_panel_info(dev
, pipe
, &dsi_panel_info
))
549 width_mm
= dsi_panel_info
.width_mm
;
550 height_mm
= dsi_panel_info
.height_mm
;
552 dsi_config
->mode
= dsi_config
->fixed_mode
;
553 dsi_config
->connector
= dsi_connector
;
555 if (!dsi_config
->fixed_mode
) {
556 DRM_ERROR("No pannel fixed mode was found\n");
560 if (pipe
&& dev_priv
->dsi_configs
[0]) {
561 dsi_config
->dvr_ic_inited
= 0;
562 dev_priv
->dsi_configs
[1] = dsi_config
;
563 } else if (pipe
== 0) {
564 dsi_config
->dvr_ic_inited
= 1;
565 dev_priv
->dsi_configs
[0] = dsi_config
;
567 DRM_ERROR("Trying to init MIPI1 before MIPI0\n");
572 connector
= &dsi_connector
->base
.base
;
573 drm_connector_init(dev
, connector
, &mdfld_dsi_connector_funcs
,
574 DRM_MODE_CONNECTOR_LVDS
);
575 drm_connector_helper_add(connector
, &mdfld_dsi_connector_helper_funcs
);
577 connector
->display_info
.subpixel_order
= SubPixelHorizontalRGB
;
578 connector
->display_info
.width_mm
= width_mm
;
579 connector
->display_info
.height_mm
= height_mm
;
580 connector
->interlace_allowed
= false;
581 connector
->doublescan_allowed
= false;
583 /*attach properties*/
584 drm_connector_attach_property(connector
,
585 dev
->mode_config
.scaling_mode_property
,
586 DRM_MODE_SCALE_FULLSCREEN
);
587 drm_connector_attach_property(connector
,
588 dev_priv
->backlight_property
,
589 MDFLD_DSI_BRIGHTNESS_MAX_LEVEL
);
591 /*init DSI package sender on this output*/
592 if (mdfld_dsi_pkg_sender_init(dsi_connector
, pipe
)) {
593 DRM_ERROR("Package Sender initialization failed on pipe %d\n",
598 encoder
= mdfld_dsi_dpi_init(dev
, dsi_connector
, p_vid_funcs
);
600 DRM_ERROR("Create DPI encoder failed\n");
603 encoder
->private = dsi_config
;
604 dsi_config
->encoder
= encoder
;
605 encoder
->base
.type
= (pipe
== 0) ? INTEL_OUTPUT_MIPI
:
607 drm_sysfs_connector_add(connector
);
610 /*TODO: add code to destroy outputs on error*/
613 mdfld_dsi_pkg_sender_destroy(dsi_connector
->pkg_sender
);
615 drm_connector_cleanup(connector
);
617 kfree(dsi_config
->fixed_mode
);
620 kfree(dsi_connector
);