506 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/**************************************************************************3 * Copyright (c) 2011, Intel Corporation.4 * All Rights Reserved.5 *6 **************************************************************************/7 8#include <linux/delay.h>9#include <linux/dmi.h>10#include <linux/module.h>11 12#include <drm/drm.h>13 14#include "intel_bios.h"15#include "mid_bios.h"16#include "psb_drv.h"17#include "psb_intel_reg.h"18#include "psb_reg.h"19 20static int oaktrail_output_init(struct drm_device *dev)21{22 struct drm_psb_private *dev_priv = to_drm_psb_private(dev);23 if (dev_priv->iLVDS_enable)24 oaktrail_lvds_init(dev, &dev_priv->mode_dev);25 else26 dev_err(dev->dev, "DSI is not supported\n");27 if (dev_priv->hdmi_priv)28 oaktrail_hdmi_init(dev, &dev_priv->mode_dev);29 30 psb_intel_sdvo_init(dev, SDVOB);31 32 return 0;33}34 35/*36 * Provide the low level interfaces for the Moorestown backlight37 */38 39#define MRST_BLC_MAX_PWM_REG_FREQ 0xFFFF40#define BLC_PWM_PRECISION_FACTOR 100 /* 10000000 */41#define BLC_PWM_FREQ_CALC_CONSTANT 3242#define MHz 100000043#define BLC_ADJUSTMENT_MAX 10044 45static void oaktrail_set_brightness(struct drm_device *dev, int level)46{47 struct drm_psb_private *dev_priv = to_drm_psb_private(dev);48 u32 blc_pwm_ctl;49 u32 max_pwm_blc;50 51 if (gma_power_begin(dev, 0)) {52 /* Calculate and set the brightness value */53 max_pwm_blc = REG_READ(BLC_PWM_CTL) >> 16;54 blc_pwm_ctl = level * max_pwm_blc / 100;55 56 /* Adjust the backlight level with the percent in57 * dev_priv->blc_adj1;58 */59 blc_pwm_ctl = blc_pwm_ctl * dev_priv->blc_adj1;60 blc_pwm_ctl = blc_pwm_ctl / 100;61 62 /* Adjust the backlight level with the percent in63 * dev_priv->blc_adj2;64 */65 blc_pwm_ctl = blc_pwm_ctl * dev_priv->blc_adj2;66 blc_pwm_ctl = blc_pwm_ctl / 100;67 68 /* force PWM bit on */69 REG_WRITE(BLC_PWM_CTL2, (0x80000000 | REG_READ(BLC_PWM_CTL2)));70 REG_WRITE(BLC_PWM_CTL, (max_pwm_blc << 16) | blc_pwm_ctl);71 gma_power_end(dev);72 }73}74 75static int oaktrail_backlight_init(struct drm_device *dev)76{77 struct drm_psb_private *dev_priv = to_drm_psb_private(dev);78 unsigned long core_clock;79 u16 bl_max_freq;80 uint32_t value;81 uint32_t blc_pwm_precision_factor;82 83 dev_priv->blc_adj1 = BLC_ADJUSTMENT_MAX;84 dev_priv->blc_adj2 = BLC_ADJUSTMENT_MAX;85 bl_max_freq = 256;86 /* this needs to be set elsewhere */87 blc_pwm_precision_factor = BLC_PWM_PRECISION_FACTOR;88 89 core_clock = dev_priv->core_freq;90 91 value = (core_clock * MHz) / BLC_PWM_FREQ_CALC_CONSTANT;92 value *= blc_pwm_precision_factor;93 value /= bl_max_freq;94 value /= blc_pwm_precision_factor;95 96 if (value > (unsigned long long)MRST_BLC_MAX_PWM_REG_FREQ)97 return -ERANGE;98 99 if (gma_power_begin(dev, false)) {100 REG_WRITE(BLC_PWM_CTL2, (0x80000000 | REG_READ(BLC_PWM_CTL2)));101 REG_WRITE(BLC_PWM_CTL, value | (value << 16));102 gma_power_end(dev);103 }104 105 oaktrail_set_brightness(dev, PSB_MAX_BRIGHTNESS);106 return 0;107}108 109/*110 * Provide the Moorestown specific chip logic and low level methods111 * for power management112 */113 114/**115 * oaktrail_save_display_registers - save registers lost on suspend116 * @dev: our DRM device117 *118 * Save the state we need in order to be able to restore the interface119 * upon resume from suspend120 */121static int oaktrail_save_display_registers(struct drm_device *dev)122{123 struct drm_psb_private *dev_priv = to_drm_psb_private(dev);124 struct psb_save_area *regs = &dev_priv->regs;125 struct psb_pipe *p = ®s->pipe[0];126 int i;127 u32 pp_stat;128 129 /* Display arbitration control + watermarks */130 regs->psb.saveDSPARB = PSB_RVDC32(DSPARB);131 regs->psb.saveDSPFW1 = PSB_RVDC32(DSPFW1);132 regs->psb.saveDSPFW2 = PSB_RVDC32(DSPFW2);133 regs->psb.saveDSPFW3 = PSB_RVDC32(DSPFW3);134 regs->psb.saveDSPFW4 = PSB_RVDC32(DSPFW4);135 regs->psb.saveDSPFW5 = PSB_RVDC32(DSPFW5);136 regs->psb.saveDSPFW6 = PSB_RVDC32(DSPFW6);137 regs->psb.saveCHICKENBIT = PSB_RVDC32(DSPCHICKENBIT);138 139 /* Pipe & plane A info */140 p->conf = PSB_RVDC32(PIPEACONF);141 p->src = PSB_RVDC32(PIPEASRC);142 p->fp0 = PSB_RVDC32(MRST_FPA0);143 p->fp1 = PSB_RVDC32(MRST_FPA1);144 p->dpll = PSB_RVDC32(MRST_DPLL_A);145 p->htotal = PSB_RVDC32(HTOTAL_A);146 p->hblank = PSB_RVDC32(HBLANK_A);147 p->hsync = PSB_RVDC32(HSYNC_A);148 p->vtotal = PSB_RVDC32(VTOTAL_A);149 p->vblank = PSB_RVDC32(VBLANK_A);150 p->vsync = PSB_RVDC32(VSYNC_A);151 regs->psb.saveBCLRPAT_A = PSB_RVDC32(BCLRPAT_A);152 p->cntr = PSB_RVDC32(DSPACNTR);153 p->stride = PSB_RVDC32(DSPASTRIDE);154 p->addr = PSB_RVDC32(DSPABASE);155 p->surf = PSB_RVDC32(DSPASURF);156 p->linoff = PSB_RVDC32(DSPALINOFF);157 p->tileoff = PSB_RVDC32(DSPATILEOFF);158 159 /* Save cursor regs */160 regs->psb.saveDSPACURSOR_CTRL = PSB_RVDC32(CURACNTR);161 regs->psb.saveDSPACURSOR_BASE = PSB_RVDC32(CURABASE);162 regs->psb.saveDSPACURSOR_POS = PSB_RVDC32(CURAPOS);163 164 /* Save palette (gamma) */165 for (i = 0; i < 256; i++)166 p->palette[i] = PSB_RVDC32(PALETTE_A + (i << 2));167 168 if (dev_priv->hdmi_priv)169 oaktrail_hdmi_save(dev);170 171 /* Save performance state */172 regs->psb.savePERF_MODE = PSB_RVDC32(MRST_PERF_MODE);173 174 /* LVDS state */175 regs->psb.savePP_CONTROL = PSB_RVDC32(PP_CONTROL);176 regs->psb.savePFIT_PGM_RATIOS = PSB_RVDC32(PFIT_PGM_RATIOS);177 regs->psb.savePFIT_AUTO_RATIOS = PSB_RVDC32(PFIT_AUTO_RATIOS);178 regs->saveBLC_PWM_CTL = PSB_RVDC32(BLC_PWM_CTL);179 regs->saveBLC_PWM_CTL2 = PSB_RVDC32(BLC_PWM_CTL2);180 regs->psb.saveLVDS = PSB_RVDC32(LVDS);181 regs->psb.savePFIT_CONTROL = PSB_RVDC32(PFIT_CONTROL);182 regs->psb.savePP_ON_DELAYS = PSB_RVDC32(LVDSPP_ON);183 regs->psb.savePP_OFF_DELAYS = PSB_RVDC32(LVDSPP_OFF);184 regs->psb.savePP_DIVISOR = PSB_RVDC32(PP_CYCLE);185 186 /* HW overlay */187 regs->psb.saveOV_OVADD = PSB_RVDC32(OV_OVADD);188 regs->psb.saveOV_OGAMC0 = PSB_RVDC32(OV_OGAMC0);189 regs->psb.saveOV_OGAMC1 = PSB_RVDC32(OV_OGAMC1);190 regs->psb.saveOV_OGAMC2 = PSB_RVDC32(OV_OGAMC2);191 regs->psb.saveOV_OGAMC3 = PSB_RVDC32(OV_OGAMC3);192 regs->psb.saveOV_OGAMC4 = PSB_RVDC32(OV_OGAMC4);193 regs->psb.saveOV_OGAMC5 = PSB_RVDC32(OV_OGAMC5);194 195 /* DPST registers */196 regs->psb.saveHISTOGRAM_INT_CONTROL_REG =197 PSB_RVDC32(HISTOGRAM_INT_CONTROL);198 regs->psb.saveHISTOGRAM_LOGIC_CONTROL_REG =199 PSB_RVDC32(HISTOGRAM_LOGIC_CONTROL);200 regs->psb.savePWM_CONTROL_LOGIC = PSB_RVDC32(PWM_CONTROL_LOGIC);201 202 if (dev_priv->iLVDS_enable) {203 /* Shut down the panel */204 PSB_WVDC32(0, PP_CONTROL);205 206 do {207 pp_stat = PSB_RVDC32(PP_STATUS);208 } while (pp_stat & 0x80000000);209 210 /* Turn off the plane */211 PSB_WVDC32(0x58000000, DSPACNTR);212 /* Trigger the plane disable */213 PSB_WVDC32(0, DSPASURF);214 215 /* Wait ~4 ticks */216 msleep(4);217 218 /* Turn off pipe */219 PSB_WVDC32(0x0, PIPEACONF);220 /* Wait ~8 ticks */221 msleep(8);222 223 /* Turn off PLLs */224 PSB_WVDC32(0, MRST_DPLL_A);225 }226 return 0;227}228 229/**230 * oaktrail_restore_display_registers - restore lost register state231 * @dev: our DRM device232 *233 * Restore register state that was lost during suspend and resume.234 */235static int oaktrail_restore_display_registers(struct drm_device *dev)236{237 struct drm_psb_private *dev_priv = to_drm_psb_private(dev);238 struct psb_save_area *regs = &dev_priv->regs;239 struct psb_pipe *p = ®s->pipe[0];240 u32 pp_stat;241 int i;242 243 /* Display arbitration + watermarks */244 PSB_WVDC32(regs->psb.saveDSPARB, DSPARB);245 PSB_WVDC32(regs->psb.saveDSPFW1, DSPFW1);246 PSB_WVDC32(regs->psb.saveDSPFW2, DSPFW2);247 PSB_WVDC32(regs->psb.saveDSPFW3, DSPFW3);248 PSB_WVDC32(regs->psb.saveDSPFW4, DSPFW4);249 PSB_WVDC32(regs->psb.saveDSPFW5, DSPFW5);250 PSB_WVDC32(regs->psb.saveDSPFW6, DSPFW6);251 PSB_WVDC32(regs->psb.saveCHICKENBIT, DSPCHICKENBIT);252 253 /* Make sure VGA plane is off. it initializes to on after reset!*/254 PSB_WVDC32(0x80000000, VGACNTRL);255 256 /* set the plls */257 PSB_WVDC32(p->fp0, MRST_FPA0);258 PSB_WVDC32(p->fp1, MRST_FPA1);259 260 /* Actually enable it */261 PSB_WVDC32(p->dpll, MRST_DPLL_A);262 udelay(150);263 264 /* Restore mode */265 PSB_WVDC32(p->htotal, HTOTAL_A);266 PSB_WVDC32(p->hblank, HBLANK_A);267 PSB_WVDC32(p->hsync, HSYNC_A);268 PSB_WVDC32(p->vtotal, VTOTAL_A);269 PSB_WVDC32(p->vblank, VBLANK_A);270 PSB_WVDC32(p->vsync, VSYNC_A);271 PSB_WVDC32(p->src, PIPEASRC);272 PSB_WVDC32(regs->psb.saveBCLRPAT_A, BCLRPAT_A);273 274 /* Restore performance mode*/275 PSB_WVDC32(regs->psb.savePERF_MODE, MRST_PERF_MODE);276 277 /* Enable the pipe*/278 if (dev_priv->iLVDS_enable)279 PSB_WVDC32(p->conf, PIPEACONF);280 281 /* Set up the plane*/282 PSB_WVDC32(p->linoff, DSPALINOFF);283 PSB_WVDC32(p->stride, DSPASTRIDE);284 PSB_WVDC32(p->tileoff, DSPATILEOFF);285 286 /* Enable the plane */287 PSB_WVDC32(p->cntr, DSPACNTR);288 PSB_WVDC32(p->surf, DSPASURF);289 290 /* Enable Cursor A */291 PSB_WVDC32(regs->psb.saveDSPACURSOR_CTRL, CURACNTR);292 PSB_WVDC32(regs->psb.saveDSPACURSOR_POS, CURAPOS);293 PSB_WVDC32(regs->psb.saveDSPACURSOR_BASE, CURABASE);294 295 /* Restore palette (gamma) */296 for (i = 0; i < 256; i++)297 PSB_WVDC32(p->palette[i], PALETTE_A + (i << 2));298 299 if (dev_priv->hdmi_priv)300 oaktrail_hdmi_restore(dev);301 302 if (dev_priv->iLVDS_enable) {303 PSB_WVDC32(regs->saveBLC_PWM_CTL2, BLC_PWM_CTL2);304 PSB_WVDC32(regs->psb.saveLVDS, LVDS); /*port 61180h*/305 PSB_WVDC32(regs->psb.savePFIT_CONTROL, PFIT_CONTROL);306 PSB_WVDC32(regs->psb.savePFIT_PGM_RATIOS, PFIT_PGM_RATIOS);307 PSB_WVDC32(regs->psb.savePFIT_AUTO_RATIOS, PFIT_AUTO_RATIOS);308 PSB_WVDC32(regs->saveBLC_PWM_CTL, BLC_PWM_CTL);309 PSB_WVDC32(regs->psb.savePP_ON_DELAYS, LVDSPP_ON);310 PSB_WVDC32(regs->psb.savePP_OFF_DELAYS, LVDSPP_OFF);311 PSB_WVDC32(regs->psb.savePP_DIVISOR, PP_CYCLE);312 PSB_WVDC32(regs->psb.savePP_CONTROL, PP_CONTROL);313 }314 315 /* Wait for cycle delay */316 do {317 pp_stat = PSB_RVDC32(PP_STATUS);318 } while (pp_stat & 0x08000000);319 320 /* Wait for panel power up */321 do {322 pp_stat = PSB_RVDC32(PP_STATUS);323 } while (pp_stat & 0x10000000);324 325 /* Restore HW overlay */326 PSB_WVDC32(regs->psb.saveOV_OVADD, OV_OVADD);327 PSB_WVDC32(regs->psb.saveOV_OGAMC0, OV_OGAMC0);328 PSB_WVDC32(regs->psb.saveOV_OGAMC1, OV_OGAMC1);329 PSB_WVDC32(regs->psb.saveOV_OGAMC2, OV_OGAMC2);330 PSB_WVDC32(regs->psb.saveOV_OGAMC3, OV_OGAMC3);331 PSB_WVDC32(regs->psb.saveOV_OGAMC4, OV_OGAMC4);332 PSB_WVDC32(regs->psb.saveOV_OGAMC5, OV_OGAMC5);333 334 /* DPST registers */335 PSB_WVDC32(regs->psb.saveHISTOGRAM_INT_CONTROL_REG,336 HISTOGRAM_INT_CONTROL);337 PSB_WVDC32(regs->psb.saveHISTOGRAM_LOGIC_CONTROL_REG,338 HISTOGRAM_LOGIC_CONTROL);339 PSB_WVDC32(regs->psb.savePWM_CONTROL_LOGIC, PWM_CONTROL_LOGIC);340 341 return 0;342}343 344/**345 * oaktrail_power_down - power down the display island346 * @dev: our DRM device347 *348 * Power down the display interface of our device349 */350static int oaktrail_power_down(struct drm_device *dev)351{352 struct drm_psb_private *dev_priv = to_drm_psb_private(dev);353 u32 pwr_mask ;354 u32 pwr_sts;355 356 pwr_mask = PSB_PWRGT_DISPLAY_MASK;357 outl(pwr_mask, dev_priv->ospm_base + PSB_PM_SSC);358 359 while (true) {360 pwr_sts = inl(dev_priv->ospm_base + PSB_PM_SSS);361 if ((pwr_sts & pwr_mask) == pwr_mask)362 break;363 else364 udelay(10);365 }366 return 0;367}368 369/*370 * oaktrail_power_up371 *372 * Restore power to the specified island(s) (powergating)373 */374static int oaktrail_power_up(struct drm_device *dev)375{376 struct drm_psb_private *dev_priv = to_drm_psb_private(dev);377 u32 pwr_mask = PSB_PWRGT_DISPLAY_MASK;378 u32 pwr_sts, pwr_cnt;379 380 pwr_cnt = inl(dev_priv->ospm_base + PSB_PM_SSC);381 pwr_cnt &= ~pwr_mask;382 outl(pwr_cnt, (dev_priv->ospm_base + PSB_PM_SSC));383 384 while (true) {385 pwr_sts = inl(dev_priv->ospm_base + PSB_PM_SSS);386 if ((pwr_sts & pwr_mask) == 0)387 break;388 else389 udelay(10);390 }391 return 0;392}393 394/* Oaktrail */395static const struct psb_offset oaktrail_regmap[2] = {396 {397 .fp0 = MRST_FPA0,398 .fp1 = MRST_FPA1,399 .cntr = DSPACNTR,400 .conf = PIPEACONF,401 .src = PIPEASRC,402 .dpll = MRST_DPLL_A,403 .htotal = HTOTAL_A,404 .hblank = HBLANK_A,405 .hsync = HSYNC_A,406 .vtotal = VTOTAL_A,407 .vblank = VBLANK_A,408 .vsync = VSYNC_A,409 .stride = DSPASTRIDE,410 .size = DSPASIZE,411 .pos = DSPAPOS,412 .surf = DSPASURF,413 .addr = MRST_DSPABASE,414 .base = MRST_DSPABASE,415 .status = PIPEASTAT,416 .linoff = DSPALINOFF,417 .tileoff = DSPATILEOFF,418 .palette = PALETTE_A,419 },420 {421 .fp0 = FPB0,422 .fp1 = FPB1,423 .cntr = DSPBCNTR,424 .conf = PIPEBCONF,425 .src = PIPEBSRC,426 .dpll = DPLL_B,427 .htotal = HTOTAL_B,428 .hblank = HBLANK_B,429 .hsync = HSYNC_B,430 .vtotal = VTOTAL_B,431 .vblank = VBLANK_B,432 .vsync = VSYNC_B,433 .stride = DSPBSTRIDE,434 .size = DSPBSIZE,435 .pos = DSPBPOS,436 .surf = DSPBSURF,437 .addr = DSPBBASE,438 .base = DSPBBASE,439 .status = PIPEBSTAT,440 .linoff = DSPBLINOFF,441 .tileoff = DSPBTILEOFF,442 .palette = PALETTE_B,443 },444};445 446static int oaktrail_chip_setup(struct drm_device *dev)447{448 struct drm_psb_private *dev_priv = to_drm_psb_private(dev);449 int ret;450 451 dev_priv->use_msi = true;452 dev_priv->regmap = oaktrail_regmap;453 454 ret = mid_chip_setup(dev);455 if (ret < 0)456 return ret;457 if (!dev_priv->has_gct) {458 /* Now pull the BIOS data */459 psb_intel_opregion_init(dev);460 psb_intel_init_bios(dev);461 }462 gma_intel_setup_gmbus(dev);463 oaktrail_hdmi_setup(dev);464 return 0;465}466 467static void oaktrail_teardown(struct drm_device *dev)468{469 struct drm_psb_private *dev_priv = to_drm_psb_private(dev);470 471 gma_intel_teardown_gmbus(dev);472 oaktrail_hdmi_teardown(dev);473 if (!dev_priv->has_gct)474 psb_intel_destroy_bios(dev);475}476 477const struct psb_ops oaktrail_chip_ops = {478 .name = "Oaktrail",479 .pipes = 2,480 .crtcs = 2,481 .hdmi_mask = (1 << 1),482 .lvds_mask = (1 << 0),483 .sdvo_mask = (1 << 1),484 .cursor_needs_phys = 0,485 .sgx_offset = MRST_SGX_OFFSET,486 487 .chip_setup = oaktrail_chip_setup,488 .chip_teardown = oaktrail_teardown,489 .crtc_helper = &oaktrail_helper_funcs,490 491 .output_init = oaktrail_output_init,492 493 .backlight_init = oaktrail_backlight_init,494 .backlight_set = oaktrail_set_brightness,495 .backlight_name = "oaktrail-bl",496 497 .save_regs = oaktrail_save_display_registers,498 .restore_regs = oaktrail_restore_display_registers,499 .save_crtc = gma_crtc_save,500 .restore_crtc = gma_crtc_restore,501 .power_down = oaktrail_power_down,502 .power_up = oaktrail_power_up,503 504 .i2c_bus = 1,505};506