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