1 // SPDX-License-Identifier: GPL-2.0-only
2 /**************************************************************************
3 * Copyright (c) 2011, Intel Corporation.
6 **************************************************************************/
10 #include "mdfld_output.h"
11 #include "mdfld_dsi_output.h"
12 #include "tc35876x-dsi-lvds.h"
14 #include <asm/intel_scu_ipc.h>
16 #ifdef CONFIG_BACKLIGHT_CLASS_DEVICE
18 #define MRST_BLC_MAX_PWM_REG_FREQ 0xFFFF
19 #define BLC_PWM_PRECISION_FACTOR 100 /* 10000000 */
20 #define BLC_PWM_FREQ_CALC_CONSTANT 32
22 #define BRIGHTNESS_MIN_LEVEL 1
23 #define BRIGHTNESS_MAX_LEVEL 100
24 #define BRIGHTNESS_MASK 0xFF
25 #define BLC_POLARITY_NORMAL 0
26 #define BLC_POLARITY_INVERSE 1
27 #define BLC_ADJUSTMENT_MAX 100
29 #define MDFLD_BLC_PWM_PRECISION_FACTOR 10
30 #define MDFLD_BLC_MAX_PWM_REG_FREQ 0xFFFE
31 #define MDFLD_BLC_MIN_PWM_REG_FREQ 0x2
33 #define MDFLD_BACKLIGHT_PWM_POLARITY_BIT_CLEAR (0xFFFE)
34 #define MDFLD_BACKLIGHT_PWM_CTL_SHIFT (16)
36 static struct backlight_device *mdfld_backlight_device;
38 int mdfld_set_brightness(struct backlight_device *bd)
40 struct drm_device *dev =
41 (struct drm_device *)bl_get_data(mdfld_backlight_device);
42 struct drm_psb_private *dev_priv = dev->dev_private;
43 int level = bd->props.brightness;
45 DRM_DEBUG_DRIVER("backlight level set to %d\n", level);
47 /* Perform value bounds checking */
48 if (level < BRIGHTNESS_MIN_LEVEL)
49 level = BRIGHTNESS_MIN_LEVEL;
51 if (gma_power_begin(dev, false)) {
52 u32 adjusted_level = 0;
55 * Adjust the backlight level with the percent in
58 adjusted_level = level * dev_priv->blc_adj2;
59 adjusted_level = adjusted_level / BLC_ADJUSTMENT_MAX;
60 dev_priv->brightness_adjusted = adjusted_level;
62 if (mdfld_get_panel_type(dev, 0) == TC35876X) {
63 if (dev_priv->dpi_panel_on[0] ||
64 dev_priv->dpi_panel_on[2])
65 tc35876x_brightness_control(dev,
66 dev_priv->brightness_adjusted);
68 if (dev_priv->dpi_panel_on[0])
69 mdfld_dsi_brightness_control(dev, 0,
70 dev_priv->brightness_adjusted);
73 if (dev_priv->dpi_panel_on[2])
74 mdfld_dsi_brightness_control(dev, 2,
75 dev_priv->brightness_adjusted);
79 /* cache the brightness for later use */
80 dev_priv->brightness = level;
84 static int mdfld_get_brightness(struct backlight_device *bd)
86 struct drm_device *dev =
87 (struct drm_device *)bl_get_data(mdfld_backlight_device);
88 struct drm_psb_private *dev_priv = dev->dev_private;
90 DRM_DEBUG_DRIVER("brightness = 0x%x \n", dev_priv->brightness);
92 /* return locally cached var instead of HW read (due to DPST etc.) */
93 return dev_priv->brightness;
96 static const struct backlight_ops mdfld_ops = {
97 .get_brightness = mdfld_get_brightness,
98 .update_status = mdfld_set_brightness,
101 static int device_backlight_init(struct drm_device *dev)
103 struct drm_psb_private *dev_priv = (struct drm_psb_private *)
106 dev_priv->blc_adj1 = BLC_ADJUSTMENT_MAX;
107 dev_priv->blc_adj2 = BLC_ADJUSTMENT_MAX;
112 static int mdfld_backlight_init(struct drm_device *dev)
114 struct backlight_properties props;
117 memset(&props, 0, sizeof(struct backlight_properties));
118 props.max_brightness = BRIGHTNESS_MAX_LEVEL;
119 props.type = BACKLIGHT_PLATFORM;
120 mdfld_backlight_device = backlight_device_register("mdfld-bl",
121 NULL, (void *)dev, &mdfld_ops, &props);
123 if (IS_ERR(mdfld_backlight_device))
124 return PTR_ERR(mdfld_backlight_device);
126 ret = device_backlight_init(dev);
130 mdfld_backlight_device->props.brightness = BRIGHTNESS_MAX_LEVEL;
131 mdfld_backlight_device->props.max_brightness = BRIGHTNESS_MAX_LEVEL;
132 backlight_update_status(mdfld_backlight_device);
137 struct backlight_device *mdfld_get_backlight_device(void)
139 #ifdef CONFIG_BACKLIGHT_CLASS_DEVICE
140 return mdfld_backlight_device;
147 * mdfld_save_display_registers
149 * Description: We are going to suspend so save current display
152 * Notes: FIXME_JLIU7 need to add the support for DPI MIPI & HDMI audio
154 static int mdfld_save_display_registers(struct drm_device *dev, int pipenum)
156 struct drm_psb_private *dev_priv = dev->dev_private;
157 struct medfield_state *regs = &dev_priv->regs.mdfld;
158 struct psb_pipe *pipe = &dev_priv->regs.pipe[pipenum];
159 const struct psb_offset *map = &dev_priv->regmap[pipenum];
168 mipi_val = ®s->saveMIPI;
171 mipi_val = ®s->saveMIPI;
176 /* pointer to values */
177 mipi_val = ®s->saveMIPI_C;
180 DRM_ERROR("%s, invalid pipe number.\n", __func__);
184 /* Pipe & plane A info */
185 pipe->dpll = PSB_RVDC32(map->dpll);
186 pipe->fp0 = PSB_RVDC32(map->fp0);
187 pipe->conf = PSB_RVDC32(map->conf);
188 pipe->htotal = PSB_RVDC32(map->htotal);
189 pipe->hblank = PSB_RVDC32(map->hblank);
190 pipe->hsync = PSB_RVDC32(map->hsync);
191 pipe->vtotal = PSB_RVDC32(map->vtotal);
192 pipe->vblank = PSB_RVDC32(map->vblank);
193 pipe->vsync = PSB_RVDC32(map->vsync);
194 pipe->src = PSB_RVDC32(map->src);
195 pipe->stride = PSB_RVDC32(map->stride);
196 pipe->linoff = PSB_RVDC32(map->linoff);
197 pipe->tileoff = PSB_RVDC32(map->tileoff);
198 pipe->size = PSB_RVDC32(map->size);
199 pipe->pos = PSB_RVDC32(map->pos);
200 pipe->surf = PSB_RVDC32(map->surf);
201 pipe->cntr = PSB_RVDC32(map->cntr);
202 pipe->status = PSB_RVDC32(map->status);
204 /*save palette (gamma) */
205 for (i = 0; i < 256; i++)
206 pipe->palette[i] = PSB_RVDC32(map->palette + (i << 2));
209 regs->savePFIT_CONTROL = PSB_RVDC32(PFIT_CONTROL);
210 regs->savePFIT_PGM_RATIOS = PSB_RVDC32(PFIT_PGM_RATIOS);
212 regs->saveHDMIPHYMISCCTL = PSB_RVDC32(HDMIPHYMISCCTL);
213 regs->saveHDMIB_CONTROL = PSB_RVDC32(HDMIB_CONTROL);
217 *mipi_val = PSB_RVDC32(mipi_reg);
222 * mdfld_restore_display_registers
224 * Description: We are going to resume so restore display register state.
226 * Notes: FIXME_JLIU7 need to add the support for DPI MIPI & HDMI audio
228 static int mdfld_restore_display_registers(struct drm_device *dev, int pipenum)
230 /* To get panel out of ULPS mode. */
232 u32 device_ready_reg = DEVICE_READY_REG;
233 struct drm_psb_private *dev_priv = dev->dev_private;
234 struct mdfld_dsi_config *dsi_config = NULL;
235 struct medfield_state *regs = &dev_priv->regs.mdfld;
236 struct psb_pipe *pipe = &dev_priv->regs.pipe[pipenum];
237 const struct psb_offset *map = &dev_priv->regmap[pipenum];
246 u32 dpll_val = pipe->dpll;
247 u32 mipi_val = regs->saveMIPI;
251 dpll_val &= ~DPLL_VCO_ENABLE;
252 dsi_config = dev_priv->dsi_configs[0];
255 dpll_val &= ~DPLL_VCO_ENABLE;
259 mipi_val = regs->saveMIPI_C;
260 dsi_config = dev_priv->dsi_configs[1];
263 DRM_ERROR("%s, invalid pipe number.\n", __func__);
267 /*make sure VGA plane is off. it initializes to on after reset!*/
268 PSB_WVDC32(0x80000000, VGACNTRL);
271 PSB_WVDC32(dpll_val & ~DPLL_VCO_ENABLE, map->dpll);
272 PSB_RVDC32(map->dpll);
274 PSB_WVDC32(pipe->fp0, map->fp0);
277 dpll = PSB_RVDC32(map->dpll);
279 if (!(dpll & DPLL_VCO_ENABLE)) {
281 /* When ungating power of DPLL, needs to wait 0.5us
282 before enable the VCO */
283 if (dpll & MDFLD_PWR_GATE_EN) {
284 dpll &= ~MDFLD_PWR_GATE_EN;
285 PSB_WVDC32(dpll, map->dpll);
286 /* FIXME_MDFLD PO - change 500 to 1 after PO */
290 PSB_WVDC32(pipe->fp0, map->fp0);
291 PSB_WVDC32(dpll_val, map->dpll);
292 /* FIXME_MDFLD PO - change 500 to 1 after PO */
295 dpll_val |= DPLL_VCO_ENABLE;
296 PSB_WVDC32(dpll_val, map->dpll);
297 PSB_RVDC32(map->dpll);
299 /* wait for DSI PLL to lock */
300 while (timeout < 20000 &&
301 !(PSB_RVDC32(map->conf) & PIPECONF_DSIPLL_LOCK)) {
306 if (timeout == 20000) {
307 DRM_ERROR("%s, can't lock DSIPLL.\n",
314 PSB_WVDC32(pipe->htotal, map->htotal);
315 PSB_WVDC32(pipe->hblank, map->hblank);
316 PSB_WVDC32(pipe->hsync, map->hsync);
317 PSB_WVDC32(pipe->vtotal, map->vtotal);
318 PSB_WVDC32(pipe->vblank, map->vblank);
319 PSB_WVDC32(pipe->vsync, map->vsync);
320 PSB_WVDC32(pipe->src, map->src);
321 PSB_WVDC32(pipe->status, map->status);
324 PSB_WVDC32(pipe->stride, map->stride);
325 PSB_WVDC32(pipe->linoff, map->linoff);
326 PSB_WVDC32(pipe->tileoff, map->tileoff);
327 PSB_WVDC32(pipe->size, map->size);
328 PSB_WVDC32(pipe->pos, map->pos);
329 PSB_WVDC32(pipe->surf, map->surf);
332 /* restore palette (gamma) */
333 /*DRM_UDELAY(50000); */
334 for (i = 0; i < 256; i++)
335 PSB_WVDC32(pipe->palette[i], map->palette + (i << 2));
337 PSB_WVDC32(regs->savePFIT_CONTROL, PFIT_CONTROL);
338 PSB_WVDC32(regs->savePFIT_PGM_RATIOS, PFIT_PGM_RATIOS);
340 /*TODO: resume HDMI port */
342 /*TODO: resume pipe*/
345 PSB_WVDC32(pipe->cntr & ~DISPLAY_PLANE_ENABLE, map->cntr);
350 /*set up pipe related registers*/
351 PSB_WVDC32(mipi_val, mipi_reg);
353 /*setup MIPI adapter + MIPI IP registers*/
355 mdfld_dsi_controller_init(dsi_config, pipenum);
357 if (in_atomic() || in_interrupt())
363 PSB_WVDC32(pipe->cntr, map->cntr);
365 if (in_atomic() || in_interrupt())
370 /* LP Hold Release */
371 temp = REG_READ(mipi_reg);
372 temp |= LP_OUTPUT_HOLD_RELEASE;
373 REG_WRITE(mipi_reg, temp);
377 /* Set DSI host to exit from Utra Low Power State */
378 temp = REG_READ(device_ready_reg);
381 temp |= EXIT_ULPS_DEV_READY;
382 REG_WRITE(device_ready_reg, temp);
385 temp = REG_READ(device_ready_reg);
387 temp |= EXITING_ULPS;
388 REG_WRITE(device_ready_reg, temp);
392 PSB_WVDC32(pipe->conf, map->conf);
394 /* restore palette (gamma) */
395 /*DRM_UDELAY(50000); */
396 for (i = 0; i < 256; i++)
397 PSB_WVDC32(pipe->palette[i], map->palette + (i << 2));
402 static int mdfld_save_registers(struct drm_device *dev)
404 /* mdfld_save_cursor_overlay_registers(dev); */
405 mdfld_save_display_registers(dev, 0);
406 mdfld_save_display_registers(dev, 2);
407 mdfld_disable_crtc(dev, 0);
408 mdfld_disable_crtc(dev, 2);
413 static int mdfld_restore_registers(struct drm_device *dev)
415 mdfld_restore_display_registers(dev, 2);
416 mdfld_restore_display_registers(dev, 0);
417 /* mdfld_restore_cursor_overlay_registers(dev); */
422 static int mdfld_power_down(struct drm_device *dev)
428 static int mdfld_power_up(struct drm_device *dev)
435 static const struct psb_offset mdfld_regmap[3] = {
449 .stride = DSPASTRIDE,
453 .addr = MRST_DSPABASE,
455 .linoff = DSPALINOFF,
456 .tileoff = DSPATILEOFF,
457 .palette = PALETTE_A,
460 .fp0 = MDFLD_DPLL_DIV0,
464 .dpll = MDFLD_DPLL_B,
471 .stride = DSPBSTRIDE,
475 .addr = MRST_DSPBBASE,
477 .linoff = DSPBLINOFF,
478 .tileoff = DSPBTILEOFF,
479 .palette = PALETTE_B,
482 .fp0 = MRST_FPA0, /* This is what the old code did ?? */
494 .stride = DSPCSTRIDE,
498 .addr = MDFLD_DSPCBASE,
500 .linoff = DSPCLINOFF,
501 .tileoff = DSPCTILEOFF,
502 .palette = PALETTE_C,
506 static int mdfld_chip_setup(struct drm_device *dev)
508 struct drm_psb_private *dev_priv = dev->dev_private;
509 if (pci_enable_msi(dev->pdev))
510 dev_warn(dev->dev, "Enabling MSI failed!\n");
511 dev_priv->regmap = mdfld_regmap;
512 return mid_chip_setup(dev);
515 const struct psb_ops mdfld_chip_ops = {
520 .lvds_mask = (1 << 1),
521 .hdmi_mask = (1 << 1),
522 .cursor_needs_phys = 0,
523 .sgx_offset = MRST_SGX_OFFSET,
525 .chip_setup = mdfld_chip_setup,
526 .crtc_helper = &mdfld_helper_funcs,
527 .crtc_funcs = &psb_intel_crtc_funcs,
529 .output_init = mdfld_output_init,
531 #ifdef CONFIG_BACKLIGHT_CLASS_DEVICE
532 .backlight_init = mdfld_backlight_init,
535 .save_regs = mdfld_save_registers,
536 .restore_regs = mdfld_restore_registers,
537 .save_crtc = gma_crtc_save,
538 .restore_crtc = gma_crtc_restore,
539 .power_down = mdfld_power_down,
540 .power_up = mdfld_power_up,