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/delay.h>
29 #include <linux/moduleparam.h>
30 #include <linux/pm_runtime.h>
32 #include <asm/intel_scu_ipc.h>
34 #include "mdfld_dsi_dpi.h"
35 #include "mdfld_dsi_output.h"
36 #include "mdfld_dsi_pkg_sender.h"
37 #include "mdfld_output.h"
38 #include "tc35876x-dsi-lvds.h"
40 /* get the LABC from command line. */
41 static int LABC_control
= 1;
44 module_param(LABC_control
, int, 0644);
47 static int __init
parse_LABC_control(char *arg
)
49 /* LABC control can be passed in as a cmdline parameter */
50 /* to enable this feature add LABC=1 to cmdline */
51 /* to disable this feature add LABC=0 to cmdline */
55 if (!strcasecmp(arg
, "0"))
57 else if (!strcasecmp(arg
, "1"))
62 early_param("LABC", parse_LABC_control
);
66 * Check and see if the generic control or data buffer is empty and ready.
68 void mdfld_dsi_gen_fifo_ready(struct drm_device
*dev
, u32 gen_fifo_stat_reg
,
71 u32 GEN_BF_time_out_count
;
73 /* Check MIPI Adatper command registers */
74 for (GEN_BF_time_out_count
= 0;
75 GEN_BF_time_out_count
< GEN_FB_TIME_OUT
;
76 GEN_BF_time_out_count
++) {
77 if ((REG_READ(gen_fifo_stat_reg
) & fifo_stat
) == fifo_stat
)
82 if (GEN_BF_time_out_count
== GEN_FB_TIME_OUT
)
83 DRM_ERROR("mdfld_dsi_gen_fifo_ready, Timeout. gen_fifo_stat_reg = 0x%x.\n",
88 * Manage the DSI MIPI keyboard and display brightness.
89 * FIXME: this is exported to OSPM code. should work out an specific
90 * display interface to OSPM.
93 void mdfld_dsi_brightness_init(struct mdfld_dsi_config
*dsi_config
, int pipe
)
95 struct mdfld_dsi_pkg_sender
*sender
=
96 mdfld_dsi_get_pkg_sender(dsi_config
);
97 struct drm_device
*dev
;
98 struct drm_psb_private
*dev_priv
;
102 DRM_ERROR("No sender found\n");
107 dev_priv
= dev
->dev_private
;
109 /* Set default display backlight value to 85% (0xd8)*/
110 mdfld_dsi_send_mcs_short(sender
, write_display_brightness
, 0xd8, 1,
113 /* Set minimum brightness setting of CABC function to 20% (0x33)*/
114 mdfld_dsi_send_mcs_short(sender
, write_cabc_min_bright
, 0x33, 1, true);
116 /* Enable backlight or/and LABC */
117 gen_ctrl_val
= BRIGHT_CNTL_BLOCK_ON
| DISPLAY_DIMMING_ON
|
119 if (LABC_control
== 1)
120 gen_ctrl_val
|= DISPLAY_DIMMING_ON
| DISPLAY_BRIGHTNESS_AUTO
123 if (LABC_control
== 1)
124 gen_ctrl_val
|= AMBIENT_LIGHT_SENSE_ON
;
126 dev_priv
->mipi_ctrl_display
= gen_ctrl_val
;
128 mdfld_dsi_send_mcs_short(sender
, write_ctrl_display
, (u8
)gen_ctrl_val
,
131 mdfld_dsi_send_mcs_short(sender
, write_ctrl_cabc
, UI_IMAGE
, 1, true);
134 void mdfld_dsi_brightness_control(struct drm_device
*dev
, int pipe
, int level
)
136 struct mdfld_dsi_pkg_sender
*sender
;
137 struct drm_psb_private
*dev_priv
;
138 struct mdfld_dsi_config
*dsi_config
;
139 u32 gen_ctrl_val
= 0;
140 int p_type
= TMD_VID
;
142 if (!dev
|| (pipe
!= 0 && pipe
!= 2)) {
143 DRM_ERROR("Invalid parameter\n");
147 p_type
= mdfld_get_panel_type(dev
, 0);
149 dev_priv
= dev
->dev_private
;
152 dsi_config
= dev_priv
->dsi_configs
[1];
154 dsi_config
= dev_priv
->dsi_configs
[0];
156 sender
= mdfld_dsi_get_pkg_sender(dsi_config
);
159 DRM_ERROR("No sender found\n");
163 gen_ctrl_val
= (level
* 0xff / MDFLD_DSI_BRIGHTNESS_MAX_LEVEL
) & 0xff;
165 dev_dbg(sender
->dev
->dev
, "pipe = %d, gen_ctrl_val = %d.\n",
168 if (p_type
== TMD_VID
) {
169 /* Set display backlight value */
170 mdfld_dsi_send_mcs_short(sender
, tmd_write_display_brightness
,
171 (u8
)gen_ctrl_val
, 1, true);
173 /* Set display backlight value */
174 mdfld_dsi_send_mcs_short(sender
, write_display_brightness
,
175 (u8
)gen_ctrl_val
, 1, true);
177 /* Enable backlight control */
181 gen_ctrl_val
= dev_priv
->mipi_ctrl_display
;
183 mdfld_dsi_send_mcs_short(sender
, write_ctrl_display
,
184 (u8
)gen_ctrl_val
, 1, true);
188 static int mdfld_dsi_get_panel_status(struct mdfld_dsi_config
*dsi_config
,
189 u8 dcs
, u32
*data
, bool hs
)
191 struct mdfld_dsi_pkg_sender
*sender
192 = mdfld_dsi_get_pkg_sender(dsi_config
);
194 if (!sender
|| !data
) {
195 DRM_ERROR("Invalid parameter\n");
199 return mdfld_dsi_read_mcs(sender
, dcs
, data
, 1, hs
);
202 int mdfld_dsi_get_power_mode(struct mdfld_dsi_config
*dsi_config
, u32
*mode
,
205 if (!dsi_config
|| !mode
) {
206 DRM_ERROR("Invalid parameter\n");
210 return mdfld_dsi_get_panel_status(dsi_config
, 0x0a, mode
, hs
);
214 * NOTE: this function was used by OSPM.
215 * TODO: will be removed later, should work out display interfaces for OSPM
217 void mdfld_dsi_controller_init(struct mdfld_dsi_config
*dsi_config
, int pipe
)
219 if (!dsi_config
|| ((pipe
!= 0) && (pipe
!= 2))) {
220 DRM_ERROR("Invalid parameters\n");
224 mdfld_dsi_dpi_controller_init(dsi_config
, pipe
);
227 static void mdfld_dsi_connector_save(struct drm_connector
*connector
)
231 static void mdfld_dsi_connector_restore(struct drm_connector
*connector
)
235 /* FIXME: start using the force parameter */
236 static enum drm_connector_status
237 mdfld_dsi_connector_detect(struct drm_connector
*connector
, bool force
)
239 struct mdfld_dsi_connector
*dsi_connector
240 = mdfld_dsi_connector(connector
);
242 dsi_connector
->status
= connector_status_connected
;
244 return dsi_connector
->status
;
247 static int mdfld_dsi_connector_set_property(struct drm_connector
*connector
,
248 struct drm_property
*property
,
251 struct drm_encoder
*encoder
= connector
->encoder
;
253 if (!strcmp(property
->name
, "scaling mode") && encoder
) {
254 struct gma_crtc
*gma_crtc
= to_gma_crtc(encoder
->crtc
);
262 case DRM_MODE_SCALE_FULLSCREEN
:
264 case DRM_MODE_SCALE_NO_SCALE
:
266 case DRM_MODE_SCALE_ASPECT
:
272 if (drm_object_property_get_value(&connector
->base
, property
, &val
))
278 if (drm_object_property_set_value(&connector
->base
,
282 centerechange
= (val
== DRM_MODE_SCALE_NO_SCALE
) ||
283 (value
== DRM_MODE_SCALE_NO_SCALE
);
285 if (gma_crtc
->saved_mode
.hdisplay
!= 0 &&
286 gma_crtc
->saved_mode
.vdisplay
!= 0) {
288 if (!drm_crtc_helper_set_mode(encoder
->crtc
,
289 &gma_crtc
->saved_mode
,
292 encoder
->crtc
->primary
->fb
))
295 const struct drm_encoder_helper_funcs
*funcs
=
296 encoder
->helper_private
;
297 funcs
->mode_set(encoder
,
298 &gma_crtc
->saved_mode
,
299 &gma_crtc
->saved_adjusted_mode
);
302 } else if (!strcmp(property
->name
, "backlight") && encoder
) {
303 if (drm_object_property_set_value(&connector
->base
, property
,
307 gma_backlight_set(encoder
->dev
, value
);
315 static void mdfld_dsi_connector_destroy(struct drm_connector
*connector
)
317 struct mdfld_dsi_connector
*dsi_connector
=
318 mdfld_dsi_connector(connector
);
319 struct mdfld_dsi_pkg_sender
*sender
;
323 drm_connector_unregister(connector
);
324 drm_connector_cleanup(connector
);
325 sender
= dsi_connector
->pkg_sender
;
326 mdfld_dsi_pkg_sender_destroy(sender
);
327 kfree(dsi_connector
);
330 static int mdfld_dsi_connector_get_modes(struct drm_connector
*connector
)
332 struct mdfld_dsi_connector
*dsi_connector
=
333 mdfld_dsi_connector(connector
);
334 struct mdfld_dsi_config
*dsi_config
=
335 mdfld_dsi_get_config(dsi_connector
);
336 struct drm_display_mode
*fixed_mode
= dsi_config
->fixed_mode
;
337 struct drm_display_mode
*dup_mode
= NULL
;
338 struct drm_device
*dev
= connector
->dev
;
341 dev_dbg(dev
->dev
, "fixed_mode %dx%d\n",
342 fixed_mode
->hdisplay
, fixed_mode
->vdisplay
);
343 dup_mode
= drm_mode_duplicate(dev
, fixed_mode
);
344 drm_mode_probed_add(connector
, dup_mode
);
347 DRM_ERROR("Didn't get any modes!\n");
351 static enum drm_mode_status
mdfld_dsi_connector_mode_valid(struct drm_connector
*connector
,
352 struct drm_display_mode
*mode
)
354 struct mdfld_dsi_connector
*dsi_connector
=
355 mdfld_dsi_connector(connector
);
356 struct mdfld_dsi_config
*dsi_config
=
357 mdfld_dsi_get_config(dsi_connector
);
358 struct drm_display_mode
*fixed_mode
= dsi_config
->fixed_mode
;
360 if (mode
->flags
& DRM_MODE_FLAG_DBLSCAN
)
361 return MODE_NO_DBLESCAN
;
363 if (mode
->flags
& DRM_MODE_FLAG_INTERLACE
)
364 return MODE_NO_INTERLACE
;
367 * FIXME: current DC has no fitting unit, reject any mode setting
369 * Will figure out a way to do up-scaling(pannel fitting) later.
372 if (mode
->hdisplay
!= fixed_mode
->hdisplay
)
375 if (mode
->vdisplay
!= fixed_mode
->vdisplay
)
382 static struct drm_encoder
*mdfld_dsi_connector_best_encoder(
383 struct drm_connector
*connector
)
385 struct mdfld_dsi_connector
*dsi_connector
=
386 mdfld_dsi_connector(connector
);
387 struct mdfld_dsi_config
*dsi_config
=
388 mdfld_dsi_get_config(dsi_connector
);
389 return &dsi_config
->encoder
->base
.base
;
392 /*DSI connector funcs*/
393 static const struct drm_connector_funcs mdfld_dsi_connector_funcs
= {
394 .dpms
= drm_helper_connector_dpms
,
395 .detect
= mdfld_dsi_connector_detect
,
396 .fill_modes
= drm_helper_probe_single_connector_modes
,
397 .set_property
= mdfld_dsi_connector_set_property
,
398 .destroy
= mdfld_dsi_connector_destroy
,
401 /*DSI connector helper funcs*/
402 static const struct drm_connector_helper_funcs
403 mdfld_dsi_connector_helper_funcs
= {
404 .get_modes
= mdfld_dsi_connector_get_modes
,
405 .mode_valid
= mdfld_dsi_connector_mode_valid
,
406 .best_encoder
= mdfld_dsi_connector_best_encoder
,
409 static int mdfld_dsi_get_default_config(struct drm_device
*dev
,
410 struct mdfld_dsi_config
*config
, int pipe
)
412 if (!dev
|| !config
) {
413 DRM_ERROR("Invalid parameters");
418 if (mdfld_get_panel_type(dev
, pipe
) == TC35876X
)
419 config
->lane_count
= 4;
421 config
->lane_count
= 2;
422 config
->channel_num
= 0;
424 if (mdfld_get_panel_type(dev
, pipe
) == TMD_VID
)
425 config
->video_mode
= MDFLD_DSI_VIDEO_NON_BURST_MODE_SYNC_PULSE
;
426 else if (mdfld_get_panel_type(dev
, pipe
) == TC35876X
)
428 MDFLD_DSI_VIDEO_NON_BURST_MODE_SYNC_EVENTS
;
430 config
->video_mode
= MDFLD_DSI_VIDEO_BURST_MODE
;
435 int mdfld_dsi_panel_reset(int pipe
)
448 DRM_ERROR("Invalid output\n");
452 ret
= gpio_request(gpio
, "gfx");
454 DRM_ERROR("gpio_rqueset failed\n");
458 ret
= gpio_direction_output(gpio
, 1);
460 DRM_ERROR("gpio_direction_output failed\n");
467 if (gpio_is_valid(gpio
))
476 * @pipe pipe number. 0 or 2
479 * Do the initialization of a MIPI output, including create DRM mode objects
480 * initialization of DSI output on @pipe
482 void mdfld_dsi_output_init(struct drm_device
*dev
,
484 const struct panel_funcs
*p_vid_funcs
)
486 struct mdfld_dsi_config
*dsi_config
;
487 struct mdfld_dsi_connector
*dsi_connector
;
488 struct drm_connector
*connector
;
489 struct mdfld_dsi_encoder
*encoder
;
490 struct drm_psb_private
*dev_priv
= dev
->dev_private
;
491 struct panel_info dsi_panel_info
;
492 u32 width_mm
, height_mm
;
494 dev_dbg(dev
->dev
, "init DSI output on pipe %d\n", pipe
);
496 if (pipe
!= 0 && pipe
!= 2) {
497 DRM_ERROR("Invalid parameter\n");
501 /*create a new connector*/
502 dsi_connector
= kzalloc(sizeof(struct mdfld_dsi_connector
), GFP_KERNEL
);
503 if (!dsi_connector
) {
504 DRM_ERROR("No memory");
508 dsi_connector
->pipe
= pipe
;
510 dsi_config
= kzalloc(sizeof(struct mdfld_dsi_config
),
513 DRM_ERROR("cannot allocate memory for DSI config\n");
516 mdfld_dsi_get_default_config(dev
, dsi_config
, pipe
);
518 dsi_connector
->private = dsi_config
;
520 dsi_config
->changed
= 1;
521 dsi_config
->dev
= dev
;
523 dsi_config
->fixed_mode
= p_vid_funcs
->get_config_mode(dev
);
524 if (p_vid_funcs
->get_panel_info(dev
, pipe
, &dsi_panel_info
))
527 width_mm
= dsi_panel_info
.width_mm
;
528 height_mm
= dsi_panel_info
.height_mm
;
530 dsi_config
->mode
= dsi_config
->fixed_mode
;
531 dsi_config
->connector
= dsi_connector
;
533 if (!dsi_config
->fixed_mode
) {
534 DRM_ERROR("No pannel fixed mode was found\n");
538 if (pipe
&& dev_priv
->dsi_configs
[0]) {
539 dsi_config
->dvr_ic_inited
= 0;
540 dev_priv
->dsi_configs
[1] = dsi_config
;
541 } else if (pipe
== 0) {
542 dsi_config
->dvr_ic_inited
= 1;
543 dev_priv
->dsi_configs
[0] = dsi_config
;
545 DRM_ERROR("Trying to init MIPI1 before MIPI0\n");
550 connector
= &dsi_connector
->base
.base
;
551 dsi_connector
->base
.save
= mdfld_dsi_connector_save
;
552 dsi_connector
->base
.restore
= mdfld_dsi_connector_restore
;
554 drm_connector_init(dev
, connector
, &mdfld_dsi_connector_funcs
,
555 DRM_MODE_CONNECTOR_LVDS
);
556 drm_connector_helper_add(connector
, &mdfld_dsi_connector_helper_funcs
);
558 connector
->display_info
.subpixel_order
= SubPixelHorizontalRGB
;
559 connector
->display_info
.width_mm
= width_mm
;
560 connector
->display_info
.height_mm
= height_mm
;
561 connector
->interlace_allowed
= false;
562 connector
->doublescan_allowed
= false;
564 /*attach properties*/
565 drm_object_attach_property(&connector
->base
,
566 dev
->mode_config
.scaling_mode_property
,
567 DRM_MODE_SCALE_FULLSCREEN
);
568 drm_object_attach_property(&connector
->base
,
569 dev_priv
->backlight_property
,
570 MDFLD_DSI_BRIGHTNESS_MAX_LEVEL
);
572 /*init DSI package sender on this output*/
573 if (mdfld_dsi_pkg_sender_init(dsi_connector
, pipe
)) {
574 DRM_ERROR("Package Sender initialization failed on pipe %d\n",
579 encoder
= mdfld_dsi_dpi_init(dev
, dsi_connector
, p_vid_funcs
);
581 DRM_ERROR("Create DPI encoder failed\n");
584 encoder
->private = dsi_config
;
585 dsi_config
->encoder
= encoder
;
586 encoder
->base
.type
= (pipe
== 0) ? INTEL_OUTPUT_MIPI
:
588 drm_connector_register(connector
);
591 /*TODO: add code to destroy outputs on error*/
594 mdfld_dsi_pkg_sender_destroy(dsi_connector
->pkg_sender
);
596 drm_connector_cleanup(connector
);
598 kfree(dsi_config
->fixed_mode
);
601 kfree(dsi_connector
);