root/drivers/gpu/drm/gma500/mdfld_device.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. mdfld_set_brightness
  2. mdfld_get_brightness
  3. device_backlight_init
  4. mdfld_backlight_init
  5. mdfld_get_backlight_device
  6. mdfld_save_display_registers
  7. mdfld_restore_display_registers
  8. mdfld_save_registers
  9. mdfld_restore_registers
  10. mdfld_power_down
  11. mdfld_power_up
  12. mdfld_chip_setup

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

/* [<][>][^][v][top][bottom][index][help] */