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 psb_intel_crtc
*psb_crtc
=
253 to_psb_intel_crtc(encoder
->crtc
);
261 case DRM_MODE_SCALE_FULLSCREEN
:
263 case DRM_MODE_SCALE_NO_SCALE
:
265 case DRM_MODE_SCALE_ASPECT
:
271 if (drm_object_property_get_value(&connector
->base
, property
, &val
))
277 if (drm_object_property_set_value(&connector
->base
,
281 centerechange
= (val
== DRM_MODE_SCALE_NO_SCALE
) ||
282 (value
== DRM_MODE_SCALE_NO_SCALE
);
284 if (psb_crtc
->saved_mode
.hdisplay
!= 0 &&
285 psb_crtc
->saved_mode
.vdisplay
!= 0) {
287 if (!drm_crtc_helper_set_mode(encoder
->crtc
,
288 &psb_crtc
->saved_mode
,
294 struct drm_encoder_helper_funcs
*funcs
=
295 encoder
->helper_private
;
296 funcs
->mode_set(encoder
,
297 &psb_crtc
->saved_mode
,
298 &psb_crtc
->saved_adjusted_mode
);
301 } else if (!strcmp(property
->name
, "backlight") && encoder
) {
302 if (drm_object_property_set_value(&connector
->base
, property
,
306 gma_backlight_set(encoder
->dev
, value
);
314 static void mdfld_dsi_connector_destroy(struct drm_connector
*connector
)
316 struct mdfld_dsi_connector
*dsi_connector
=
317 mdfld_dsi_connector(connector
);
318 struct mdfld_dsi_pkg_sender
*sender
;
322 drm_sysfs_connector_remove(connector
);
323 drm_connector_cleanup(connector
);
324 sender
= dsi_connector
->pkg_sender
;
325 mdfld_dsi_pkg_sender_destroy(sender
);
326 kfree(dsi_connector
);
329 static int mdfld_dsi_connector_get_modes(struct drm_connector
*connector
)
331 struct mdfld_dsi_connector
*dsi_connector
=
332 mdfld_dsi_connector(connector
);
333 struct mdfld_dsi_config
*dsi_config
=
334 mdfld_dsi_get_config(dsi_connector
);
335 struct drm_display_mode
*fixed_mode
= dsi_config
->fixed_mode
;
336 struct drm_display_mode
*dup_mode
= NULL
;
337 struct drm_device
*dev
= connector
->dev
;
339 connector
->display_info
.min_vfreq
= 0;
340 connector
->display_info
.max_vfreq
= 200;
341 connector
->display_info
.min_hfreq
= 0;
342 connector
->display_info
.max_hfreq
= 200;
345 dev_dbg(dev
->dev
, "fixed_mode %dx%d\n",
346 fixed_mode
->hdisplay
, fixed_mode
->vdisplay
);
347 dup_mode
= drm_mode_duplicate(dev
, fixed_mode
);
348 drm_mode_probed_add(connector
, dup_mode
);
351 DRM_ERROR("Didn't get any modes!\n");
355 static int mdfld_dsi_connector_mode_valid(struct drm_connector
*connector
,
356 struct drm_display_mode
*mode
)
358 struct mdfld_dsi_connector
*dsi_connector
=
359 mdfld_dsi_connector(connector
);
360 struct mdfld_dsi_config
*dsi_config
=
361 mdfld_dsi_get_config(dsi_connector
);
362 struct drm_display_mode
*fixed_mode
= dsi_config
->fixed_mode
;
364 if (mode
->flags
& DRM_MODE_FLAG_DBLSCAN
)
365 return MODE_NO_DBLESCAN
;
367 if (mode
->flags
& DRM_MODE_FLAG_INTERLACE
)
368 return MODE_NO_INTERLACE
;
371 * FIXME: current DC has no fitting unit, reject any mode setting
373 * Will figure out a way to do up-scaling(pannel fitting) later.
376 if (mode
->hdisplay
!= fixed_mode
->hdisplay
)
379 if (mode
->vdisplay
!= fixed_mode
->vdisplay
)
386 static void mdfld_dsi_connector_dpms(struct drm_connector
*connector
, int mode
)
388 if (mode
== connector
->dpms
)
391 /*first, execute dpms*/
393 drm_helper_connector_dpms(connector
, mode
);
396 static struct drm_encoder
*mdfld_dsi_connector_best_encoder(
397 struct drm_connector
*connector
)
399 struct mdfld_dsi_connector
*dsi_connector
=
400 mdfld_dsi_connector(connector
);
401 struct mdfld_dsi_config
*dsi_config
=
402 mdfld_dsi_get_config(dsi_connector
);
403 return &dsi_config
->encoder
->base
.base
;
406 /*DSI connector funcs*/
407 static const struct drm_connector_funcs mdfld_dsi_connector_funcs
= {
408 .dpms
= /*drm_helper_connector_dpms*/mdfld_dsi_connector_dpms
,
409 .save
= mdfld_dsi_connector_save
,
410 .restore
= mdfld_dsi_connector_restore
,
411 .detect
= mdfld_dsi_connector_detect
,
412 .fill_modes
= drm_helper_probe_single_connector_modes
,
413 .set_property
= mdfld_dsi_connector_set_property
,
414 .destroy
= mdfld_dsi_connector_destroy
,
417 /*DSI connector helper funcs*/
418 static const struct drm_connector_helper_funcs
419 mdfld_dsi_connector_helper_funcs
= {
420 .get_modes
= mdfld_dsi_connector_get_modes
,
421 .mode_valid
= mdfld_dsi_connector_mode_valid
,
422 .best_encoder
= mdfld_dsi_connector_best_encoder
,
425 static int mdfld_dsi_get_default_config(struct drm_device
*dev
,
426 struct mdfld_dsi_config
*config
, int pipe
)
428 if (!dev
|| !config
) {
429 DRM_ERROR("Invalid parameters");
434 if (mdfld_get_panel_type(dev
, pipe
) == TC35876X
)
435 config
->lane_count
= 4;
437 config
->lane_count
= 2;
438 config
->channel_num
= 0;
440 if (mdfld_get_panel_type(dev
, pipe
) == TMD_VID
)
441 config
->video_mode
= MDFLD_DSI_VIDEO_NON_BURST_MODE_SYNC_PULSE
;
442 else if (mdfld_get_panel_type(dev
, pipe
) == TC35876X
)
444 MDFLD_DSI_VIDEO_NON_BURST_MODE_SYNC_EVENTS
;
446 config
->video_mode
= MDFLD_DSI_VIDEO_BURST_MODE
;
451 int mdfld_dsi_panel_reset(int pipe
)
464 DRM_ERROR("Invalid output\n");
468 ret
= gpio_request(gpio
, "gfx");
470 DRM_ERROR("gpio_rqueset failed\n");
474 ret
= gpio_direction_output(gpio
, 1);
476 DRM_ERROR("gpio_direction_output failed\n");
483 if (gpio_is_valid(gpio
))
492 * @pipe pipe number. 0 or 2
495 * Do the initialization of a MIPI output, including create DRM mode objects
496 * initialization of DSI output on @pipe
498 void mdfld_dsi_output_init(struct drm_device
*dev
,
500 const struct panel_funcs
*p_vid_funcs
)
502 struct mdfld_dsi_config
*dsi_config
;
503 struct mdfld_dsi_connector
*dsi_connector
;
504 struct drm_connector
*connector
;
505 struct mdfld_dsi_encoder
*encoder
;
506 struct drm_psb_private
*dev_priv
= dev
->dev_private
;
507 struct panel_info dsi_panel_info
;
508 u32 width_mm
, height_mm
;
510 dev_dbg(dev
->dev
, "init DSI output on pipe %d\n", pipe
);
512 if (pipe
!= 0 && pipe
!= 2) {
513 DRM_ERROR("Invalid parameter\n");
517 /*create a new connetor*/
518 dsi_connector
= kzalloc(sizeof(struct mdfld_dsi_connector
), GFP_KERNEL
);
519 if (!dsi_connector
) {
520 DRM_ERROR("No memory");
524 dsi_connector
->pipe
= pipe
;
526 dsi_config
= kzalloc(sizeof(struct mdfld_dsi_config
),
529 DRM_ERROR("cannot allocate memory for DSI config\n");
532 mdfld_dsi_get_default_config(dev
, dsi_config
, pipe
);
534 dsi_connector
->private = dsi_config
;
536 dsi_config
->changed
= 1;
537 dsi_config
->dev
= dev
;
539 dsi_config
->fixed_mode
= p_vid_funcs
->get_config_mode(dev
);
540 if (p_vid_funcs
->get_panel_info(dev
, pipe
, &dsi_panel_info
))
543 width_mm
= dsi_panel_info
.width_mm
;
544 height_mm
= dsi_panel_info
.height_mm
;
546 dsi_config
->mode
= dsi_config
->fixed_mode
;
547 dsi_config
->connector
= dsi_connector
;
549 if (!dsi_config
->fixed_mode
) {
550 DRM_ERROR("No pannel fixed mode was found\n");
554 if (pipe
&& dev_priv
->dsi_configs
[0]) {
555 dsi_config
->dvr_ic_inited
= 0;
556 dev_priv
->dsi_configs
[1] = dsi_config
;
557 } else if (pipe
== 0) {
558 dsi_config
->dvr_ic_inited
= 1;
559 dev_priv
->dsi_configs
[0] = dsi_config
;
561 DRM_ERROR("Trying to init MIPI1 before MIPI0\n");
566 connector
= &dsi_connector
->base
.base
;
567 drm_connector_init(dev
, connector
, &mdfld_dsi_connector_funcs
,
568 DRM_MODE_CONNECTOR_LVDS
);
569 drm_connector_helper_add(connector
, &mdfld_dsi_connector_helper_funcs
);
571 connector
->display_info
.subpixel_order
= SubPixelHorizontalRGB
;
572 connector
->display_info
.width_mm
= width_mm
;
573 connector
->display_info
.height_mm
= height_mm
;
574 connector
->interlace_allowed
= false;
575 connector
->doublescan_allowed
= false;
577 /*attach properties*/
578 drm_object_attach_property(&connector
->base
,
579 dev
->mode_config
.scaling_mode_property
,
580 DRM_MODE_SCALE_FULLSCREEN
);
581 drm_object_attach_property(&connector
->base
,
582 dev_priv
->backlight_property
,
583 MDFLD_DSI_BRIGHTNESS_MAX_LEVEL
);
585 /*init DSI package sender on this output*/
586 if (mdfld_dsi_pkg_sender_init(dsi_connector
, pipe
)) {
587 DRM_ERROR("Package Sender initialization failed on pipe %d\n",
592 encoder
= mdfld_dsi_dpi_init(dev
, dsi_connector
, p_vid_funcs
);
594 DRM_ERROR("Create DPI encoder failed\n");
597 encoder
->private = dsi_config
;
598 dsi_config
->encoder
= encoder
;
599 encoder
->base
.type
= (pipe
== 0) ? INTEL_OUTPUT_MIPI
:
601 drm_sysfs_connector_add(connector
);
604 /*TODO: add code to destroy outputs on error*/
607 mdfld_dsi_pkg_sender_destroy(dsi_connector
->pkg_sender
);
609 drm_connector_cleanup(connector
);
611 kfree(dsi_config
->fixed_mode
);
614 kfree(dsi_connector
);