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