Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v3.10 615 lines 16 kB view raw
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 psb_intel_crtc *psb_crtc = 253 to_psb_intel_crtc(encoder->crtc); 254 bool centerechange; 255 uint64_t val; 256 257 if (!psb_crtc) 258 goto set_prop_error; 259 260 switch (value) { 261 case DRM_MODE_SCALE_FULLSCREEN: 262 break; 263 case DRM_MODE_SCALE_NO_SCALE: 264 break; 265 case DRM_MODE_SCALE_ASPECT: 266 break; 267 default: 268 goto set_prop_error; 269 } 270 271 if (drm_object_property_get_value(&connector->base, property, &val)) 272 goto set_prop_error; 273 274 if (val == value) 275 goto set_prop_done; 276 277 if (drm_object_property_set_value(&connector->base, 278 property, value)) 279 goto set_prop_error; 280 281 centerechange = (val == DRM_MODE_SCALE_NO_SCALE) || 282 (value == DRM_MODE_SCALE_NO_SCALE); 283 284 if (psb_crtc->saved_mode.hdisplay != 0 && 285 psb_crtc->saved_mode.vdisplay != 0) { 286 if (centerechange) { 287 if (!drm_crtc_helper_set_mode(encoder->crtc, 288 &psb_crtc->saved_mode, 289 encoder->crtc->x, 290 encoder->crtc->y, 291 encoder->crtc->fb)) 292 goto set_prop_error; 293 } else { 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); 299 } 300 } 301 } else if (!strcmp(property->name, "backlight") && encoder) { 302 if (drm_object_property_set_value(&connector->base, property, 303 value)) 304 goto set_prop_error; 305 else 306 gma_backlight_set(encoder->dev, value); 307 } 308set_prop_done: 309 return 0; 310set_prop_error: 311 return -1; 312} 313 314static void mdfld_dsi_connector_destroy(struct drm_connector *connector) 315{ 316 struct mdfld_dsi_connector *dsi_connector = 317 mdfld_dsi_connector(connector); 318 struct mdfld_dsi_pkg_sender *sender; 319 320 if (!dsi_connector) 321 return; 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); 327} 328 329static int mdfld_dsi_connector_get_modes(struct drm_connector *connector) 330{ 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; 338 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; 343 344 if (fixed_mode) { 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); 349 return 1; 350 } 351 DRM_ERROR("Didn't get any modes!\n"); 352 return 0; 353} 354 355static int mdfld_dsi_connector_mode_valid(struct drm_connector *connector, 356 struct drm_display_mode *mode) 357{ 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; 363 364 if (mode->flags & DRM_MODE_FLAG_DBLSCAN) 365 return MODE_NO_DBLESCAN; 366 367 if (mode->flags & DRM_MODE_FLAG_INTERLACE) 368 return MODE_NO_INTERLACE; 369 370 /** 371 * FIXME: current DC has no fitting unit, reject any mode setting 372 * request 373 * Will figure out a way to do up-scaling(pannel fitting) later. 374 **/ 375 if (fixed_mode) { 376 if (mode->hdisplay != fixed_mode->hdisplay) 377 return MODE_PANEL; 378 379 if (mode->vdisplay != fixed_mode->vdisplay) 380 return MODE_PANEL; 381 } 382 383 return MODE_OK; 384} 385 386static void mdfld_dsi_connector_dpms(struct drm_connector *connector, int mode) 387{ 388 if (mode == connector->dpms) 389 return; 390 391 /*first, execute dpms*/ 392 393 drm_helper_connector_dpms(connector, mode); 394} 395 396static struct drm_encoder *mdfld_dsi_connector_best_encoder( 397 struct drm_connector *connector) 398{ 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; 404} 405 406/*DSI connector funcs*/ 407static 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, 415}; 416 417/*DSI connector helper funcs*/ 418static 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, 423}; 424 425static int mdfld_dsi_get_default_config(struct drm_device *dev, 426 struct mdfld_dsi_config *config, int pipe) 427{ 428 if (!dev || !config) { 429 DRM_ERROR("Invalid parameters"); 430 return -EINVAL; 431 } 432 433 config->bpp = 24; 434 if (mdfld_get_panel_type(dev, pipe) == TC35876X) 435 config->lane_count = 4; 436 else 437 config->lane_count = 2; 438 config->channel_num = 0; 439 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) 443 config->video_mode = 444 MDFLD_DSI_VIDEO_NON_BURST_MODE_SYNC_EVENTS; 445 else 446 config->video_mode = MDFLD_DSI_VIDEO_BURST_MODE; 447 448 return 0; 449} 450 451int mdfld_dsi_panel_reset(int pipe) 452{ 453 unsigned gpio; 454 int ret = 0; 455 456 switch (pipe) { 457 case 0: 458 gpio = 128; 459 break; 460 case 2: 461 gpio = 34; 462 break; 463 default: 464 DRM_ERROR("Invalid output\n"); 465 return -EINVAL; 466 } 467 468 ret = gpio_request(gpio, "gfx"); 469 if (ret) { 470 DRM_ERROR("gpio_rqueset failed\n"); 471 return ret; 472 } 473 474 ret = gpio_direction_output(gpio, 1); 475 if (ret) { 476 DRM_ERROR("gpio_direction_output failed\n"); 477 goto gpio_error; 478 } 479 480 gpio_get_value(128); 481 482gpio_error: 483 if (gpio_is_valid(gpio)) 484 gpio_free(gpio); 485 486 return ret; 487} 488 489/* 490 * MIPI output init 491 * @dev drm device 492 * @pipe pipe number. 0 or 2 493 * @config 494 * 495 * Do the initialization of a MIPI output, including create DRM mode objects 496 * initialization of DSI output on @pipe 497 */ 498void mdfld_dsi_output_init(struct drm_device *dev, 499 int pipe, 500 const struct panel_funcs *p_vid_funcs) 501{ 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; 509 510 dev_dbg(dev->dev, "init DSI output on pipe %d\n", pipe); 511 512 if (pipe != 0 && pipe != 2) { 513 DRM_ERROR("Invalid parameter\n"); 514 return; 515 } 516 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"); 521 return; 522 } 523 524 dsi_connector->pipe = pipe; 525 526 dsi_config = kzalloc(sizeof(struct mdfld_dsi_config), 527 GFP_KERNEL); 528 if (!dsi_config) { 529 DRM_ERROR("cannot allocate memory for DSI config\n"); 530 goto dsi_init_err0; 531 } 532 mdfld_dsi_get_default_config(dev, dsi_config, pipe); 533 534 dsi_connector->private = dsi_config; 535 536 dsi_config->changed = 1; 537 dsi_config->dev = dev; 538 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)) 541 goto dsi_init_err0; 542 543 width_mm = dsi_panel_info.width_mm; 544 height_mm = dsi_panel_info.height_mm; 545 546 dsi_config->mode = dsi_config->fixed_mode; 547 dsi_config->connector = dsi_connector; 548 549 if (!dsi_config->fixed_mode) { 550 DRM_ERROR("No pannel fixed mode was found\n"); 551 goto dsi_init_err0; 552 } 553 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; 560 } else { 561 DRM_ERROR("Trying to init MIPI1 before MIPI0\n"); 562 goto dsi_init_err0; 563 } 564 565 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); 570 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; 576 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); 584 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", 588 pipe); 589 goto dsi_init_err0; 590 } 591 592 encoder = mdfld_dsi_dpi_init(dev, dsi_connector, p_vid_funcs); 593 if (!encoder) { 594 DRM_ERROR("Create DPI encoder failed\n"); 595 goto dsi_init_err1; 596 } 597 encoder->private = dsi_config; 598 dsi_config->encoder = encoder; 599 encoder->base.type = (pipe == 0) ? INTEL_OUTPUT_MIPI : 600 INTEL_OUTPUT_MIPI2; 601 drm_sysfs_connector_add(connector); 602 return; 603 604 /*TODO: add code to destroy outputs on error*/ 605dsi_init_err1: 606 /*destroy sender*/ 607 mdfld_dsi_pkg_sender_destroy(dsi_connector->pkg_sender); 608 609 drm_connector_cleanup(connector); 610 611 kfree(dsi_config->fixed_mode); 612 kfree(dsi_config); 613dsi_init_err0: 614 kfree(dsi_connector); 615}