linux/drivers/gpu/drm/gma500/mdfld_device.c
<<
>>
Prefs
   1/**************************************************************************
   2 * Copyright (c) 2011, Intel Corporation.
   3 * All Rights Reserved.
   4 *
   5 * This program is free software; you can redistribute it and/or modify it
   6 * under the terms and conditions of the GNU General Public License,
   7 * version 2, as published by the Free Software Foundation.
   8 *
   9 * This program is distributed in the hope it will be useful, but WITHOUT
  10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
  12 * more details.
  13 *
  14 * You should have received a copy of the GNU General Public License along with
  15 * this program; if not, write to the Free Software Foundation, Inc.,
  16 * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
  17 *
  18 **************************************************************************/
  19
  20#include "psb_drv.h"
  21#include "mid_bios.h"
  22#include "mdfld_output.h"
  23#include "mdfld_dsi_output.h"
  24#include "tc35876x-dsi-lvds.h"
  25
  26#include <asm/intel_scu_ipc.h>
  27
  28#ifdef CONFIG_BACKLIGHT_CLASS_DEVICE
  29
  30#define MRST_BLC_MAX_PWM_REG_FREQ           0xFFFF
  31#define BLC_PWM_PRECISION_FACTOR 100    /* 10000000 */
  32#define BLC_PWM_FREQ_CALC_CONSTANT 32
  33#define MHz 1000000
  34#define BRIGHTNESS_MIN_LEVEL 1
  35#define BRIGHTNESS_MAX_LEVEL 100
  36#define BRIGHTNESS_MASK 0xFF
  37#define BLC_POLARITY_NORMAL 0
  38#define BLC_POLARITY_INVERSE 1
  39#define BLC_ADJUSTMENT_MAX 100
  40
  41#define MDFLD_BLC_PWM_PRECISION_FACTOR    10
  42#define MDFLD_BLC_MAX_PWM_REG_FREQ        0xFFFE
  43#define MDFLD_BLC_MIN_PWM_REG_FREQ        0x2
  44
  45#define MDFLD_BACKLIGHT_PWM_POLARITY_BIT_CLEAR (0xFFFE)
  46#define MDFLD_BACKLIGHT_PWM_CTL_SHIFT   (16)
  47
  48static struct backlight_device *mdfld_backlight_device;
  49
  50int mdfld_set_brightness(struct backlight_device *bd)
  51{
  52        struct drm_device *dev =
  53                (struct drm_device *)bl_get_data(mdfld_backlight_device);
  54        struct drm_psb_private *dev_priv = dev->dev_private;
  55        int level = bd->props.brightness;
  56
  57        DRM_DEBUG_DRIVER("backlight level set to %d\n", level);
  58
  59        /* Perform value bounds checking */
  60        if (level < BRIGHTNESS_MIN_LEVEL)
  61                level = BRIGHTNESS_MIN_LEVEL;
  62
  63        if (gma_power_begin(dev, false)) {
  64                u32 adjusted_level = 0;
  65
  66                /*
  67                 * Adjust the backlight level with the percent in
  68                 * dev_priv->blc_adj2
  69                 */
  70                adjusted_level = level * dev_priv->blc_adj2;
  71                adjusted_level = adjusted_level / BLC_ADJUSTMENT_MAX;
  72                dev_priv->brightness_adjusted = adjusted_level;
  73
  74                if (mdfld_get_panel_type(dev, 0) == TC35876X) {
  75                        if (dev_priv->dpi_panel_on[0] ||
  76                                        dev_priv->dpi_panel_on[2])
  77                                tc35876x_brightness_control(dev,
  78                                                dev_priv->brightness_adjusted);
  79                } else {
  80                        if (dev_priv->dpi_panel_on[0])
  81                                mdfld_dsi_brightness_control(dev, 0,
  82                                                dev_priv->brightness_adjusted);
  83                }
  84
  85                if (dev_priv->dpi_panel_on[2])
  86                        mdfld_dsi_brightness_control(dev, 2,
  87                                        dev_priv->brightness_adjusted);
  88                gma_power_end(dev);
  89        }
  90
  91        /* cache the brightness for later use */
  92        dev_priv->brightness = level;
  93        return 0;
  94}
  95
  96static int mdfld_get_brightness(struct backlight_device *bd)
  97{
  98        struct drm_device *dev =
  99                (struct drm_device *)bl_get_data(mdfld_backlight_device);
 100        struct drm_psb_private *dev_priv = dev->dev_private;
 101
 102        DRM_DEBUG_DRIVER("brightness = 0x%x \n", dev_priv->brightness);
 103
 104        /* return locally cached var instead of HW read (due to DPST etc.) */
 105        return dev_priv->brightness;
 106}
 107
 108static const struct backlight_ops mdfld_ops = {
 109        .get_brightness = mdfld_get_brightness,
 110        .update_status  = mdfld_set_brightness,
 111};
 112
 113static int device_backlight_init(struct drm_device *dev)
 114{
 115        struct drm_psb_private *dev_priv = (struct drm_psb_private *)
 116                dev->dev_private;
 117
 118        dev_priv->blc_adj1 = BLC_ADJUSTMENT_MAX;
 119        dev_priv->blc_adj2 = BLC_ADJUSTMENT_MAX;
 120
 121        return 0;
 122}
 123
 124static int mdfld_backlight_init(struct drm_device *dev)
 125{
 126        struct backlight_properties props;
 127        int ret = 0;
 128
 129        memset(&props, 0, sizeof(struct backlight_properties));
 130        props.max_brightness = BRIGHTNESS_MAX_LEVEL;
 131        props.type = BACKLIGHT_PLATFORM;
 132        mdfld_backlight_device = backlight_device_register("mdfld-bl",
 133                                NULL, (void *)dev, &mdfld_ops, &props);
 134
 135        if (IS_ERR(mdfld_backlight_device))
 136                return PTR_ERR(mdfld_backlight_device);
 137
 138        ret = device_backlight_init(dev);
 139        if (ret)
 140                return ret;
 141
 142        mdfld_backlight_device->props.brightness = BRIGHTNESS_MAX_LEVEL;
 143        mdfld_backlight_device->props.max_brightness = BRIGHTNESS_MAX_LEVEL;
 144        backlight_update_status(mdfld_backlight_device);
 145        return 0;
 146}
 147#endif
 148
 149struct backlight_device *mdfld_get_backlight_device(void)
 150{
 151#ifdef CONFIG_BACKLIGHT_CLASS_DEVICE
 152        return mdfld_backlight_device;
 153#else
 154        return NULL;
 155#endif
 156}
 157
 158/*
 159 * mdfld_save_display_registers
 160 *
 161 * Description: We are going to suspend so save current display
 162 * register state.
 163 *
 164 * Notes: FIXME_JLIU7 need to add the support for DPI MIPI & HDMI audio
 165 */
 166static int mdfld_save_display_registers(struct drm_device *dev, int pipenum)
 167{
 168        struct drm_psb_private *dev_priv = dev->dev_private;
 169        struct medfield_state *regs = &dev_priv->regs.mdfld;
 170        struct psb_pipe *pipe = &dev_priv->regs.pipe[pipenum];
 171        const struct psb_offset *map = &dev_priv->regmap[pipenum];
 172        int i;
 173        u32 *mipi_val;
 174
 175        /* register */
 176        u32 mipi_reg = MIPI;
 177
 178        switch (pipenum) {
 179        case 0:
 180                mipi_val = &regs->saveMIPI;
 181                break;
 182        case 1:
 183                mipi_val = &regs->saveMIPI;
 184                break;
 185        case 2:
 186                /* register */
 187                mipi_reg = MIPI_C;
 188                /* pointer to values */
 189                mipi_val = &regs->saveMIPI_C;
 190                break;
 191        default:
 192                DRM_ERROR("%s, invalid pipe number.\n", __func__);
 193                return -EINVAL;
 194        }
 195
 196        /* Pipe & plane A info */
 197        pipe->dpll = PSB_RVDC32(map->dpll);
 198        pipe->fp0 = PSB_RVDC32(map->fp0);
 199        pipe->conf = PSB_RVDC32(map->conf);
 200        pipe->htotal = PSB_RVDC32(map->htotal);
 201        pipe->hblank = PSB_RVDC32(map->hblank);
 202        pipe->hsync = PSB_RVDC32(map->hsync);
 203        pipe->vtotal = PSB_RVDC32(map->vtotal);
 204        pipe->vblank = PSB_RVDC32(map->vblank);
 205        pipe->vsync = PSB_RVDC32(map->vsync);
 206        pipe->src = PSB_RVDC32(map->src);
 207        pipe->stride = PSB_RVDC32(map->stride);
 208        pipe->linoff = PSB_RVDC32(map->linoff);
 209        pipe->tileoff = PSB_RVDC32(map->tileoff);
 210        pipe->size = PSB_RVDC32(map->size);
 211        pipe->pos = PSB_RVDC32(map->pos);
 212        pipe->surf = PSB_RVDC32(map->surf);
 213        pipe->cntr = PSB_RVDC32(map->cntr);
 214        pipe->status = PSB_RVDC32(map->status);
 215
 216        /*save palette (gamma) */
 217        for (i = 0; i < 256; i++)
 218                pipe->palette[i] = PSB_RVDC32(map->palette + (i << 2));
 219
 220        if (pipenum == 1) {
 221                regs->savePFIT_CONTROL = PSB_RVDC32(PFIT_CONTROL);
 222                regs->savePFIT_PGM_RATIOS = PSB_RVDC32(PFIT_PGM_RATIOS);
 223
 224                regs->saveHDMIPHYMISCCTL = PSB_RVDC32(HDMIPHYMISCCTL);
 225                regs->saveHDMIB_CONTROL = PSB_RVDC32(HDMIB_CONTROL);
 226                return 0;
 227        }
 228
 229        *mipi_val = PSB_RVDC32(mipi_reg);
 230        return 0;
 231}
 232
 233/*
 234 * mdfld_restore_display_registers
 235 *
 236 * Description: We are going to resume so restore display register state.
 237 *
 238 * Notes: FIXME_JLIU7 need to add the support for DPI MIPI & HDMI audio
 239 */
 240static int mdfld_restore_display_registers(struct drm_device *dev, int pipenum)
 241{
 242        /* To get  panel out of ULPS mode. */
 243        u32 temp = 0;
 244        u32 device_ready_reg = DEVICE_READY_REG;
 245        struct drm_psb_private *dev_priv = dev->dev_private;
 246        struct mdfld_dsi_config *dsi_config = NULL;
 247        struct medfield_state *regs = &dev_priv->regs.mdfld;
 248        struct psb_pipe *pipe = &dev_priv->regs.pipe[pipenum];
 249        const struct psb_offset *map = &dev_priv->regmap[pipenum];
 250        u32 i;
 251        u32 dpll;
 252        u32 timeout = 0;
 253
 254        /* register */
 255        u32 mipi_reg = MIPI;
 256
 257        /* values */
 258        u32 dpll_val = pipe->dpll;
 259        u32 mipi_val = regs->saveMIPI;
 260
 261        switch (pipenum) {
 262        case 0:
 263                dpll_val &= ~DPLL_VCO_ENABLE;
 264                dsi_config = dev_priv->dsi_configs[0];
 265                break;
 266        case 1:
 267                dpll_val &= ~DPLL_VCO_ENABLE;
 268                break;
 269        case 2:
 270                mipi_reg = MIPI_C;
 271                mipi_val = regs->saveMIPI_C;
 272                dsi_config = dev_priv->dsi_configs[1];
 273                break;
 274        default:
 275                DRM_ERROR("%s, invalid pipe number.\n", __func__);
 276                return -EINVAL;
 277        }
 278
 279        /*make sure VGA plane is off. it initializes to on after reset!*/
 280        PSB_WVDC32(0x80000000, VGACNTRL);
 281
 282        if (pipenum == 1) {
 283                PSB_WVDC32(dpll_val & ~DPLL_VCO_ENABLE, map->dpll);
 284                PSB_RVDC32(map->dpll);
 285
 286                PSB_WVDC32(pipe->fp0, map->fp0);
 287        } else {
 288
 289                dpll = PSB_RVDC32(map->dpll);
 290
 291                if (!(dpll & DPLL_VCO_ENABLE)) {
 292
 293                        /* When ungating power of DPLL, needs to wait 0.5us
 294                           before enable the VCO */
 295                        if (dpll & MDFLD_PWR_GATE_EN) {
 296                                dpll &= ~MDFLD_PWR_GATE_EN;
 297                                PSB_WVDC32(dpll, map->dpll);
 298                                /* FIXME_MDFLD PO - change 500 to 1 after PO */
 299                                udelay(500);
 300                        }
 301
 302                        PSB_WVDC32(pipe->fp0, map->fp0);
 303                        PSB_WVDC32(dpll_val, map->dpll);
 304                        /* FIXME_MDFLD PO - change 500 to 1 after PO */
 305                        udelay(500);
 306
 307                        dpll_val |= DPLL_VCO_ENABLE;
 308                        PSB_WVDC32(dpll_val, map->dpll);
 309                        PSB_RVDC32(map->dpll);
 310
 311                        /* wait for DSI PLL to lock */
 312                        while (timeout < 20000 &&
 313                          !(PSB_RVDC32(map->conf) & PIPECONF_DSIPLL_LOCK)) {
 314                                udelay(150);
 315                                timeout++;
 316                        }
 317
 318                        if (timeout == 20000) {
 319                                DRM_ERROR("%s, can't lock DSIPLL.\n",
 320                                                                __func__);
 321                                return -EINVAL;
 322                        }
 323                }
 324        }
 325        /* Restore mode */
 326        PSB_WVDC32(pipe->htotal, map->htotal);
 327        PSB_WVDC32(pipe->hblank, map->hblank);
 328        PSB_WVDC32(pipe->hsync, map->hsync);
 329        PSB_WVDC32(pipe->vtotal, map->vtotal);
 330        PSB_WVDC32(pipe->vblank, map->vblank);
 331        PSB_WVDC32(pipe->vsync, map->vsync);
 332        PSB_WVDC32(pipe->src, map->src);
 333        PSB_WVDC32(pipe->status, map->status);
 334
 335        /*set up the plane*/
 336        PSB_WVDC32(pipe->stride, map->stride);
 337        PSB_WVDC32(pipe->linoff, map->linoff);
 338        PSB_WVDC32(pipe->tileoff, map->tileoff);
 339        PSB_WVDC32(pipe->size, map->size);
 340        PSB_WVDC32(pipe->pos, map->pos);
 341        PSB_WVDC32(pipe->surf, map->surf);
 342
 343        if (pipenum == 1) {
 344                /* restore palette (gamma) */
 345                /*DRM_UDELAY(50000); */
 346                for (i = 0; i < 256; i++)
 347                        PSB_WVDC32(pipe->palette[i], map->palette + (i << 2));
 348
 349                PSB_WVDC32(regs->savePFIT_CONTROL, PFIT_CONTROL);
 350                PSB_WVDC32(regs->savePFIT_PGM_RATIOS, PFIT_PGM_RATIOS);
 351
 352                /*TODO: resume HDMI port */
 353
 354                /*TODO: resume pipe*/
 355
 356                /*enable the plane*/
 357                PSB_WVDC32(pipe->cntr & ~DISPLAY_PLANE_ENABLE, map->cntr);
 358
 359                return 0;
 360        }
 361
 362        /*set up pipe related registers*/
 363        PSB_WVDC32(mipi_val, mipi_reg);
 364
 365        /*setup MIPI adapter + MIPI IP registers*/
 366        if (dsi_config)
 367                mdfld_dsi_controller_init(dsi_config, pipenum);
 368
 369        if (in_atomic() || in_interrupt())
 370                mdelay(20);
 371        else
 372                msleep(20);
 373
 374        /*enable the plane*/
 375        PSB_WVDC32(pipe->cntr, map->cntr);
 376
 377        if (in_atomic() || in_interrupt())
 378                mdelay(20);
 379        else
 380                msleep(20);
 381
 382        /* LP Hold Release */
 383        temp = REG_READ(mipi_reg);
 384        temp |= LP_OUTPUT_HOLD_RELEASE;
 385        REG_WRITE(mipi_reg, temp);
 386        mdelay(1);
 387
 388
 389        /* Set DSI host to exit from Utra Low Power State */
 390        temp = REG_READ(device_ready_reg);
 391        temp &= ~ULPS_MASK;
 392        temp |= 0x3;
 393        temp |= EXIT_ULPS_DEV_READY;
 394        REG_WRITE(device_ready_reg, temp);
 395        mdelay(1);
 396
 397        temp = REG_READ(device_ready_reg);
 398        temp &= ~ULPS_MASK;
 399        temp |= EXITING_ULPS;
 400        REG_WRITE(device_ready_reg, temp);
 401        mdelay(1);
 402
 403        /*enable the pipe*/
 404        PSB_WVDC32(pipe->conf, map->conf);
 405
 406        /* restore palette (gamma) */
 407        /*DRM_UDELAY(50000); */
 408        for (i = 0; i < 256; i++)
 409                PSB_WVDC32(pipe->palette[i], map->palette + (i << 2));
 410
 411        return 0;
 412}
 413
 414static int mdfld_save_registers(struct drm_device *dev)
 415{
 416        /* mdfld_save_cursor_overlay_registers(dev); */
 417        mdfld_save_display_registers(dev, 0);
 418        mdfld_save_display_registers(dev, 2);
 419        mdfld_disable_crtc(dev, 0);
 420        mdfld_disable_crtc(dev, 2);
 421
 422        return 0;
 423}
 424
 425static int mdfld_restore_registers(struct drm_device *dev)
 426{
 427        mdfld_restore_display_registers(dev, 2);
 428        mdfld_restore_display_registers(dev, 0);
 429        /* mdfld_restore_cursor_overlay_registers(dev); */
 430
 431        return 0;
 432}
 433
 434static int mdfld_power_down(struct drm_device *dev)
 435{
 436        /* FIXME */
 437        return 0;
 438}
 439
 440static int mdfld_power_up(struct drm_device *dev)
 441{
 442        /* FIXME */
 443        return 0;
 444}
 445
 446/* Medfield  */
 447static const struct psb_offset mdfld_regmap[3] = {
 448        {
 449                .fp0 = MRST_FPA0,
 450                .fp1 = MRST_FPA1,
 451                .cntr = DSPACNTR,
 452                .conf = PIPEACONF,
 453                .src = PIPEASRC,
 454                .dpll = MRST_DPLL_A,
 455                .htotal = HTOTAL_A,
 456                .hblank = HBLANK_A,
 457                .hsync = HSYNC_A,
 458                .vtotal = VTOTAL_A,
 459                .vblank = VBLANK_A,
 460                .vsync = VSYNC_A,
 461                .stride = DSPASTRIDE,
 462                .size = DSPASIZE,
 463                .pos = DSPAPOS,
 464                .surf = DSPASURF,
 465                .addr = MRST_DSPABASE,
 466                .status = PIPEASTAT,
 467                .linoff = DSPALINOFF,
 468                .tileoff = DSPATILEOFF,
 469                .palette = PALETTE_A,
 470        },
 471        {
 472                .fp0 = MDFLD_DPLL_DIV0,
 473                .cntr = DSPBCNTR,
 474                .conf = PIPEBCONF,
 475                .src = PIPEBSRC,
 476                .dpll = MDFLD_DPLL_B,
 477                .htotal = HTOTAL_B,
 478                .hblank = HBLANK_B,
 479                .hsync = HSYNC_B,
 480                .vtotal = VTOTAL_B,
 481                .vblank = VBLANK_B,
 482                .vsync = VSYNC_B,
 483                .stride = DSPBSTRIDE,
 484                .size = DSPBSIZE,
 485                .pos = DSPBPOS,
 486                .surf = DSPBSURF,
 487                .addr = MRST_DSPBBASE,
 488                .status = PIPEBSTAT,
 489                .linoff = DSPBLINOFF,
 490                .tileoff = DSPBTILEOFF,
 491                .palette = PALETTE_B,
 492        },
 493        {
 494                .fp0 = MRST_FPA0,       /* This is what the old code did ?? */
 495                .cntr = DSPCCNTR,
 496                .conf = PIPECCONF,
 497                .src = PIPECSRC,
 498                /* No DPLL_C */
 499                .dpll = MRST_DPLL_A,
 500                .htotal = HTOTAL_C,
 501                .hblank = HBLANK_C,
 502                .hsync = HSYNC_C,
 503                .vtotal = VTOTAL_C,
 504                .vblank = VBLANK_C,
 505                .vsync = VSYNC_C,
 506                .stride = DSPCSTRIDE,
 507                .size = DSPBSIZE,
 508                .pos = DSPCPOS,
 509                .surf = DSPCSURF,
 510                .addr = MDFLD_DSPCBASE,
 511                .status = PIPECSTAT,
 512                .linoff = DSPCLINOFF,
 513                .tileoff = DSPCTILEOFF,
 514                .palette = PALETTE_C,
 515        },
 516};
 517
 518static int mdfld_chip_setup(struct drm_device *dev)
 519{
 520        struct drm_psb_private *dev_priv = dev->dev_private;
 521        if (pci_enable_msi(dev->pdev))
 522                dev_warn(dev->dev, "Enabling MSI failed!\n");
 523        dev_priv->regmap = mdfld_regmap;
 524        return mid_chip_setup(dev);
 525}
 526
 527const struct psb_ops mdfld_chip_ops = {
 528        .name = "mdfld",
 529        .accel_2d = 0,
 530        .pipes = 3,
 531        .crtcs = 3,
 532        .lvds_mask = (1 << 1),
 533        .hdmi_mask = (1 << 1),
 534        .cursor_needs_phys = 0,
 535        .sgx_offset = MRST_SGX_OFFSET,
 536
 537        .chip_setup = mdfld_chip_setup,
 538        .crtc_helper = &mdfld_helper_funcs,
 539        .crtc_funcs = &psb_intel_crtc_funcs,
 540
 541        .output_init = mdfld_output_init,
 542
 543#ifdef CONFIG_BACKLIGHT_CLASS_DEVICE
 544        .backlight_init = mdfld_backlight_init,
 545#endif
 546
 547        .save_regs = mdfld_save_registers,
 548        .restore_regs = mdfld_restore_registers,
 549        .save_crtc = gma_crtc_save,
 550        .restore_crtc = gma_crtc_restore,
 551        .power_down = mdfld_power_down,
 552        .power_up = mdfld_power_up,
 553};
 554