linux/drivers/gpu/drm/gma500/mdfld_dsi_output.c
<<
>>
Prefs
   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 struct drm_encoder *mdfld_dsi_connector_best_encoder(
 386                                struct drm_connector *connector)
 387{
 388        struct mdfld_dsi_connector *dsi_connector =
 389                                mdfld_dsi_connector(connector);
 390        struct mdfld_dsi_config *dsi_config =
 391                                mdfld_dsi_get_config(dsi_connector);
 392        return &dsi_config->encoder->base.base;
 393}
 394
 395/*DSI connector funcs*/
 396static const struct drm_connector_funcs mdfld_dsi_connector_funcs = {
 397        .dpms = drm_helper_connector_dpms,
 398        .detect = mdfld_dsi_connector_detect,
 399        .fill_modes = drm_helper_probe_single_connector_modes,
 400        .set_property = mdfld_dsi_connector_set_property,
 401        .destroy = mdfld_dsi_connector_destroy,
 402};
 403
 404/*DSI connector helper funcs*/
 405static const struct drm_connector_helper_funcs
 406        mdfld_dsi_connector_helper_funcs = {
 407        .get_modes = mdfld_dsi_connector_get_modes,
 408        .mode_valid = mdfld_dsi_connector_mode_valid,
 409        .best_encoder = mdfld_dsi_connector_best_encoder,
 410};
 411
 412static int mdfld_dsi_get_default_config(struct drm_device *dev,
 413                                struct mdfld_dsi_config *config, int pipe)
 414{
 415        if (!dev || !config) {
 416                DRM_ERROR("Invalid parameters");
 417                return -EINVAL;
 418        }
 419
 420        config->bpp = 24;
 421        if (mdfld_get_panel_type(dev, pipe) == TC35876X)
 422                config->lane_count = 4;
 423        else
 424                config->lane_count = 2;
 425        config->channel_num = 0;
 426
 427        if (mdfld_get_panel_type(dev, pipe) == TMD_VID)
 428                config->video_mode = MDFLD_DSI_VIDEO_NON_BURST_MODE_SYNC_PULSE;
 429        else if (mdfld_get_panel_type(dev, pipe) == TC35876X)
 430                config->video_mode =
 431                                MDFLD_DSI_VIDEO_NON_BURST_MODE_SYNC_EVENTS;
 432        else
 433                config->video_mode = MDFLD_DSI_VIDEO_BURST_MODE;
 434
 435        return 0;
 436}
 437
 438int mdfld_dsi_panel_reset(int pipe)
 439{
 440        unsigned gpio;
 441        int ret = 0;
 442
 443        switch (pipe) {
 444        case 0:
 445                gpio = 128;
 446                break;
 447        case 2:
 448                gpio = 34;
 449                break;
 450        default:
 451                DRM_ERROR("Invalid output\n");
 452                return -EINVAL;
 453        }
 454
 455        ret = gpio_request(gpio, "gfx");
 456        if (ret) {
 457                DRM_ERROR("gpio_rqueset failed\n");
 458                return ret;
 459        }
 460
 461        ret = gpio_direction_output(gpio, 1);
 462        if (ret) {
 463                DRM_ERROR("gpio_direction_output failed\n");
 464                goto gpio_error;
 465        }
 466
 467        gpio_get_value(128);
 468
 469gpio_error:
 470        if (gpio_is_valid(gpio))
 471                gpio_free(gpio);
 472
 473        return ret;
 474}
 475
 476/*
 477 * MIPI output init
 478 * @dev drm device
 479 * @pipe pipe number. 0 or 2
 480 * @config
 481 *
 482 * Do the initialization of a MIPI output, including create DRM mode objects
 483 * initialization of DSI output on @pipe
 484 */
 485void mdfld_dsi_output_init(struct drm_device *dev,
 486                           int pipe,
 487                           const struct panel_funcs *p_vid_funcs)
 488{
 489        struct mdfld_dsi_config *dsi_config;
 490        struct mdfld_dsi_connector *dsi_connector;
 491        struct drm_connector *connector;
 492        struct mdfld_dsi_encoder *encoder;
 493        struct drm_psb_private *dev_priv = dev->dev_private;
 494        struct panel_info dsi_panel_info;
 495        u32 width_mm, height_mm;
 496
 497        dev_dbg(dev->dev, "init DSI output on pipe %d\n", pipe);
 498
 499        if (pipe != 0 && pipe != 2) {
 500                DRM_ERROR("Invalid parameter\n");
 501                return;
 502        }
 503
 504        /*create a new connetor*/
 505        dsi_connector = kzalloc(sizeof(struct mdfld_dsi_connector), GFP_KERNEL);
 506        if (!dsi_connector) {
 507                DRM_ERROR("No memory");
 508                return;
 509        }
 510
 511        dsi_connector->pipe =  pipe;
 512
 513        dsi_config = kzalloc(sizeof(struct mdfld_dsi_config),
 514                        GFP_KERNEL);
 515        if (!dsi_config) {
 516                DRM_ERROR("cannot allocate memory for DSI config\n");
 517                goto dsi_init_err0;
 518        }
 519        mdfld_dsi_get_default_config(dev, dsi_config, pipe);
 520
 521        dsi_connector->private = dsi_config;
 522
 523        dsi_config->changed = 1;
 524        dsi_config->dev = dev;
 525
 526        dsi_config->fixed_mode = p_vid_funcs->get_config_mode(dev);
 527        if (p_vid_funcs->get_panel_info(dev, pipe, &dsi_panel_info))
 528                        goto dsi_init_err0;
 529
 530        width_mm = dsi_panel_info.width_mm;
 531        height_mm = dsi_panel_info.height_mm;
 532
 533        dsi_config->mode = dsi_config->fixed_mode;
 534        dsi_config->connector = dsi_connector;
 535
 536        if (!dsi_config->fixed_mode) {
 537                DRM_ERROR("No pannel fixed mode was found\n");
 538                goto dsi_init_err0;
 539        }
 540
 541        if (pipe && dev_priv->dsi_configs[0]) {
 542                dsi_config->dvr_ic_inited = 0;
 543                dev_priv->dsi_configs[1] = dsi_config;
 544        } else if (pipe == 0) {
 545                dsi_config->dvr_ic_inited = 1;
 546                dev_priv->dsi_configs[0] = dsi_config;
 547        } else {
 548                DRM_ERROR("Trying to init MIPI1 before MIPI0\n");
 549                goto dsi_init_err0;
 550        }
 551
 552
 553        connector = &dsi_connector->base.base;
 554        dsi_connector->base.save = mdfld_dsi_connector_save;
 555        dsi_connector->base.restore = mdfld_dsi_connector_restore;
 556
 557        drm_connector_init(dev, connector, &mdfld_dsi_connector_funcs,
 558                                                DRM_MODE_CONNECTOR_LVDS);
 559        drm_connector_helper_add(connector, &mdfld_dsi_connector_helper_funcs);
 560
 561        connector->display_info.subpixel_order = SubPixelHorizontalRGB;
 562        connector->display_info.width_mm = width_mm;
 563        connector->display_info.height_mm = height_mm;
 564        connector->interlace_allowed = false;
 565        connector->doublescan_allowed = false;
 566
 567        /*attach properties*/
 568        drm_object_attach_property(&connector->base,
 569                                dev->mode_config.scaling_mode_property,
 570                                DRM_MODE_SCALE_FULLSCREEN);
 571        drm_object_attach_property(&connector->base,
 572                                dev_priv->backlight_property,
 573                                MDFLD_DSI_BRIGHTNESS_MAX_LEVEL);
 574
 575        /*init DSI package sender on this output*/
 576        if (mdfld_dsi_pkg_sender_init(dsi_connector, pipe)) {
 577                DRM_ERROR("Package Sender initialization failed on pipe %d\n",
 578                                                                        pipe);
 579                goto dsi_init_err0;
 580        }
 581
 582        encoder = mdfld_dsi_dpi_init(dev, dsi_connector, p_vid_funcs);
 583        if (!encoder) {
 584                DRM_ERROR("Create DPI encoder failed\n");
 585                goto dsi_init_err1;
 586        }
 587        encoder->private = dsi_config;
 588        dsi_config->encoder = encoder;
 589        encoder->base.type = (pipe == 0) ? INTEL_OUTPUT_MIPI :
 590                INTEL_OUTPUT_MIPI2;
 591        drm_connector_register(connector);
 592        return;
 593
 594        /*TODO: add code to destroy outputs on error*/
 595dsi_init_err1:
 596        /*destroy sender*/
 597        mdfld_dsi_pkg_sender_destroy(dsi_connector->pkg_sender);
 598
 599        drm_connector_cleanup(connector);
 600
 601        kfree(dsi_config->fixed_mode);
 602        kfree(dsi_config);
 603dsi_init_err0:
 604        kfree(dsi_connector);
 605}
 606