1/* 2 * Copyright �� 2010 Intel Corporation 3 * 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: 10 * 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 13 * Software. 14 * 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. 22 * 23 * Authors: 24 * jim liu <jim.liu@intel.com> 25 * Jackie Li<yaodong.li@intel.com> 26 */ 27 28#include <linux/module.h> 29 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> 37 38/* get the LABC from command line. */ 39static int LABC_control = 1; 40 41#ifdef MODULE 42module_param(LABC_control, int, 0644); 43#else 44 45static int __init parse_LABC_control(char *arg) 46{ 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 */ 50 if (!arg) 51 return -EINVAL; 52 53 if (!strcasecmp(arg, "0")) 54 LABC_control = 0; 55 else if (!strcasecmp(arg, "1")) 56 LABC_control = 1; 57 58 return 0; 59} 60early_param("LABC", parse_LABC_control); 61#endif 62 63/** 64 * Check and see if the generic control or data buffer is empty and ready. 65 */ 66void mdfld_dsi_gen_fifo_ready(struct drm_device *dev, u32 gen_fifo_stat_reg, 67 u32 fifo_stat) 68{ 69 u32 GEN_BF_time_out_count; 70 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) 76 break; 77 udelay(100); 78 } 79 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", 82 gen_fifo_stat_reg); 83} 84 85/** 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. 89 */ 90 91void mdfld_dsi_brightness_init(struct mdfld_dsi_config *dsi_config, int pipe) 92{ 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; 97 u32 gen_ctrl_val; 98 99 if (!sender) { 100 DRM_ERROR("No sender found\n"); 101 return; 102 } 103 104 dev = sender->dev; 105 dev_priv = dev->dev_private; 106 107 /* Set default display backlight value to 85% (0xd8)*/ 108 mdfld_dsi_send_mcs_short(sender, write_display_brightness, 0xd8, 1, 109 true); 110 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); 113 114 /* Enable backlight or/and LABC */ 115 gen_ctrl_val = BRIGHT_CNTL_BLOCK_ON | DISPLAY_DIMMING_ON | 116 BACKLIGHT_ON; 117 if (LABC_control == 1) 118 gen_ctrl_val |= DISPLAY_DIMMING_ON | DISPLAY_BRIGHTNESS_AUTO 119 | GAMMA_AUTO; 120 121 if (LABC_control == 1) 122 gen_ctrl_val |= AMBIENT_LIGHT_SENSE_ON; 123 124 dev_priv->mipi_ctrl_display = gen_ctrl_val; 125 126 mdfld_dsi_send_mcs_short(sender, write_ctrl_display, (u8)gen_ctrl_val, 127 1, true); 128 129 mdfld_dsi_send_mcs_short(sender, write_ctrl_cabc, UI_IMAGE, 1, true); 130} 131 132void mdfld_dsi_brightness_control(struct drm_device *dev, int pipe, int level) 133{ 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; 139 140 if (!dev || (pipe != 0 && pipe != 2)) { 141 DRM_ERROR("Invalid parameter\n"); 142 return; 143 } 144 145 p_type = mdfld_get_panel_type(dev, 0); 146 147 dev_priv = dev->dev_private; 148 149 if (pipe) 150 dsi_config = dev_priv->dsi_configs[1]; 151 else 152 dsi_config = dev_priv->dsi_configs[0]; 153 154 sender = mdfld_dsi_get_pkg_sender(dsi_config); 155 156 if (!sender) { 157 DRM_ERROR("No sender found\n"); 158 return; 159 } 160 161 gen_ctrl_val = (level * 0xff / MDFLD_DSI_BRIGHTNESS_MAX_LEVEL) & 0xff; 162 163 dev_dbg(sender->dev->dev, "pipe = %d, gen_ctrl_val = %d.\n", 164 pipe, gen_ctrl_val); 165 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); 170 } else { 171 /* Set display backlight value */ 172 mdfld_dsi_send_mcs_short(sender, write_display_brightness, 173 (u8)gen_ctrl_val, 1, true); 174 175 /* Enable backlight control */ 176 if (level == 0) 177 gen_ctrl_val = 0; 178 else 179 gen_ctrl_val = dev_priv->mipi_ctrl_display; 180 181 mdfld_dsi_send_mcs_short(sender, write_ctrl_display, 182 (u8)gen_ctrl_val, 1, true); 183 } 184} 185 186static int mdfld_dsi_get_panel_status(struct mdfld_dsi_config *dsi_config, 187 u8 dcs, u32 *data, bool hs) 188{ 189 struct mdfld_dsi_pkg_sender *sender 190 = mdfld_dsi_get_pkg_sender(dsi_config); 191 192 if (!sender || !data) { 193 DRM_ERROR("Invalid parameter\n"); 194 return -EINVAL; 195 } 196 197 return mdfld_dsi_read_mcs(sender, dcs, data, 1, hs); 198} 199 200int mdfld_dsi_get_power_mode(struct mdfld_dsi_config *dsi_config, u32 *mode, 201 bool hs) 202{ 203 if (!dsi_config || !mode) { 204 DRM_ERROR("Invalid parameter\n"); 205 return -EINVAL; 206 } 207 208 return mdfld_dsi_get_panel_status(dsi_config, 0x0a, mode, hs); 209} 210 211/* 212 * NOTE: this function was used by OSPM. 213 * TODO: will be removed later, should work out display interfaces for OSPM 214 */ 215void mdfld_dsi_controller_init(struct mdfld_dsi_config *dsi_config, int pipe) 216{ 217 if (!dsi_config || ((pipe != 0) && (pipe != 2))) { 218 DRM_ERROR("Invalid parameters\n"); 219 return; 220 } 221 222 mdfld_dsi_dpi_controller_init(dsi_config, pipe); 223} 224 225static void mdfld_dsi_connector_save(struct drm_connector *connector) 226{ 227} 228 229static void mdfld_dsi_connector_restore(struct drm_connector *connector) 230{ 231} 232 233/* FIXME: start using the force parameter */ 234static enum drm_connector_status 235mdfld_dsi_connector_detect(struct drm_connector *connector, bool force) 236{ 237 struct mdfld_dsi_connector *dsi_connector 238 = mdfld_dsi_connector(connector); 239 240 dsi_connector->status = connector_status_connected; 241 242 return dsi_connector->status; 243} 244 245static int mdfld_dsi_connector_set_property(struct drm_connector *connector, 246 struct drm_property *property, 247 uint64_t value) 248{ 249 struct drm_encoder *encoder = connector->encoder; 250 251 if (!strcmp(property->name, "scaling mode") && encoder) { 252 struct gma_crtc *gma_crtc = to_gma_crtc(encoder->crtc); 253 bool centerechange; 254 uint64_t val; 255 256 if (!gma_crtc) 257 goto set_prop_error; 258 259 switch (value) { 260 case DRM_MODE_SCALE_FULLSCREEN: 261 break; 262 case DRM_MODE_SCALE_NO_SCALE: 263 break; 264 case DRM_MODE_SCALE_ASPECT: 265 break; 266 default: 267 goto set_prop_error; 268 } 269 270 if (drm_object_property_get_value(&connector->base, property, &val)) 271 goto set_prop_error; 272 273 if (val == value) 274 goto set_prop_done; 275 276 if (drm_object_property_set_value(&connector->base, 277 property, value)) 278 goto set_prop_error; 279 280 centerechange = (val == DRM_MODE_SCALE_NO_SCALE) || 281 (value == DRM_MODE_SCALE_NO_SCALE); 282 283 if (gma_crtc->saved_mode.hdisplay != 0 && 284 gma_crtc->saved_mode.vdisplay != 0) { 285 if (centerechange) { 286 if (!drm_crtc_helper_set_mode(encoder->crtc, 287 &gma_crtc->saved_mode, 288 encoder->crtc->x, 289 encoder->crtc->y, 290 encoder->crtc->primary->fb)) 291 goto set_prop_error; 292 } else { 293 const 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); 298 } 299 } 300 } else if (!strcmp(property->name, "backlight") && encoder) { 301 if (drm_object_property_set_value(&connector->base, property, 302 value)) 303 goto set_prop_error; 304 else 305 gma_backlight_set(encoder->dev, value); 306 } 307set_prop_done: 308 return 0; 309set_prop_error: 310 return -1; 311} 312 313static void mdfld_dsi_connector_destroy(struct drm_connector *connector) 314{ 315 struct mdfld_dsi_connector *dsi_connector = 316 mdfld_dsi_connector(connector); 317 struct mdfld_dsi_pkg_sender *sender; 318 319 if (!dsi_connector) 320 return; 321 drm_connector_unregister(connector); 322 drm_connector_cleanup(connector); 323 sender = dsi_connector->pkg_sender; 324 mdfld_dsi_pkg_sender_destroy(sender); 325 kfree(dsi_connector); 326} 327 328static int mdfld_dsi_connector_get_modes(struct drm_connector *connector) 329{ 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; 337 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; 342 343 if (fixed_mode) { 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); 348 return 1; 349 } 350 DRM_ERROR("Didn't get any modes!\n"); 351 return 0; 352} 353 354static int mdfld_dsi_connector_mode_valid(struct drm_connector *connector, 355 struct drm_display_mode *mode) 356{ 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; 362 363 if (mode->flags & DRM_MODE_FLAG_DBLSCAN) 364 return MODE_NO_DBLESCAN; 365 366 if (mode->flags & DRM_MODE_FLAG_INTERLACE) 367 return MODE_NO_INTERLACE; 368 369 /** 370 * FIXME: current DC has no fitting unit, reject any mode setting 371 * request 372 * Will figure out a way to do up-scaling(pannel fitting) later. 373 **/ 374 if (fixed_mode) { 375 if (mode->hdisplay != fixed_mode->hdisplay) 376 return MODE_PANEL; 377 378 if (mode->vdisplay != fixed_mode->vdisplay) 379 return MODE_PANEL; 380 } 381 382 return MODE_OK; 383} 384 385static void mdfld_dsi_connector_dpms(struct drm_connector *connector, int mode) 386{ 387 if (mode == connector->dpms) 388 return; 389 390 /*first, execute dpms*/ 391 392 drm_helper_connector_dpms(connector, mode); 393} 394 395static struct drm_encoder *mdfld_dsi_connector_best_encoder( 396 struct drm_connector *connector) 397{ 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; 403} 404 405/*DSI connector funcs*/ 406static 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, 414}; 415 416/*DSI connector helper funcs*/ 417static 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, 422}; 423 424static int mdfld_dsi_get_default_config(struct drm_device *dev, 425 struct mdfld_dsi_config *config, int pipe) 426{ 427 if (!dev || !config) { 428 DRM_ERROR("Invalid parameters"); 429 return -EINVAL; 430 } 431 432 config->bpp = 24; 433 if (mdfld_get_panel_type(dev, pipe) == TC35876X) 434 config->lane_count = 4; 435 else 436 config->lane_count = 2; 437 config->channel_num = 0; 438 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) 442 config->video_mode = 443 MDFLD_DSI_VIDEO_NON_BURST_MODE_SYNC_EVENTS; 444 else 445 config->video_mode = MDFLD_DSI_VIDEO_BURST_MODE; 446 447 return 0; 448} 449 450int mdfld_dsi_panel_reset(int pipe) 451{ 452 unsigned gpio; 453 int ret = 0; 454 455 switch (pipe) { 456 case 0: 457 gpio = 128; 458 break; 459 case 2: 460 gpio = 34; 461 break; 462 default: 463 DRM_ERROR("Invalid output\n"); 464 return -EINVAL; 465 } 466 467 ret = gpio_request(gpio, "gfx"); 468 if (ret) { 469 DRM_ERROR("gpio_rqueset failed\n"); 470 return ret; 471 } 472 473 ret = gpio_direction_output(gpio, 1); 474 if (ret) { 475 DRM_ERROR("gpio_direction_output failed\n"); 476 goto gpio_error; 477 } 478 479 gpio_get_value(128); 480 481gpio_error: 482 if (gpio_is_valid(gpio)) 483 gpio_free(gpio); 484 485 return ret; 486} 487 488/* 489 * MIPI output init 490 * @dev drm device 491 * @pipe pipe number. 0 or 2 492 * @config 493 * 494 * Do the initialization of a MIPI output, including create DRM mode objects 495 * initialization of DSI output on @pipe 496 */ 497void mdfld_dsi_output_init(struct drm_device *dev, 498 int pipe, 499 const struct panel_funcs *p_vid_funcs) 500{ 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; 508 509 dev_dbg(dev->dev, "init DSI output on pipe %d\n", pipe); 510 511 if (pipe != 0 && pipe != 2) { 512 DRM_ERROR("Invalid parameter\n"); 513 return; 514 } 515 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"); 520 return; 521 } 522 523 dsi_connector->pipe = pipe; 524 525 dsi_config = kzalloc(sizeof(struct mdfld_dsi_config), 526 GFP_KERNEL); 527 if (!dsi_config) { 528 DRM_ERROR("cannot allocate memory for DSI config\n"); 529 goto dsi_init_err0; 530 } 531 mdfld_dsi_get_default_config(dev, dsi_config, pipe); 532 533 dsi_connector->private = dsi_config; 534 535 dsi_config->changed = 1; 536 dsi_config->dev = dev; 537 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)) 540 goto dsi_init_err0; 541 542 width_mm = dsi_panel_info.width_mm; 543 height_mm = dsi_panel_info.height_mm; 544 545 dsi_config->mode = dsi_config->fixed_mode; 546 dsi_config->connector = dsi_connector; 547 548 if (!dsi_config->fixed_mode) { 549 DRM_ERROR("No pannel fixed mode was found\n"); 550 goto dsi_init_err0; 551 } 552 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; 559 } else { 560 DRM_ERROR("Trying to init MIPI1 before MIPI0\n"); 561 goto dsi_init_err0; 562 } 563 564 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); 569 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; 575 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); 583 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", 587 pipe); 588 goto dsi_init_err0; 589 } 590 591 encoder = mdfld_dsi_dpi_init(dev, dsi_connector, p_vid_funcs); 592 if (!encoder) { 593 DRM_ERROR("Create DPI encoder failed\n"); 594 goto dsi_init_err1; 595 } 596 encoder->private = dsi_config; 597 dsi_config->encoder = encoder; 598 encoder->base.type = (pipe == 0) ? INTEL_OUTPUT_MIPI : 599 INTEL_OUTPUT_MIPI2; 600 drm_connector_register(connector); 601 return; 602 603 /*TODO: add code to destroy outputs on error*/ 604dsi_init_err1: 605 /*destroy sender*/ 606 mdfld_dsi_pkg_sender_destroy(dsi_connector->pkg_sender); 607 608 drm_connector_cleanup(connector); 609 610 kfree(dsi_config->fixed_mode); 611 kfree(dsi_config); 612dsi_init_err0: 613 kfree(dsi_connector); 614} 615