1 /**************************************************************************
2 * Copyright (c) 2011, Intel Corporation.
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.
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
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.
18 **************************************************************************/
22 #include "mdfld_output.h"
23 #include "mdfld_dsi_output.h"
24 #include "tc35876x-dsi-lvds.h"
26 #include <asm/intel_scu_ipc.h>
28 #ifdef CONFIG_BACKLIGHT_CLASS_DEVICE
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
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
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
45 #define MDFLD_BACKLIGHT_PWM_POLARITY_BIT_CLEAR (0xFFFE)
46 #define MDFLD_BACKLIGHT_PWM_CTL_SHIFT (16)
48 static struct backlight_device
*mdfld_backlight_device
;
50 int mdfld_set_brightness(struct backlight_device
*bd
)
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
;
57 DRM_DEBUG_DRIVER("backlight level set to %d\n", level
);
59 /* Perform value bounds checking */
60 if (level
< BRIGHTNESS_MIN_LEVEL
)
61 level
= BRIGHTNESS_MIN_LEVEL
;
63 if (gma_power_begin(dev
, false)) {
64 u32 adjusted_level
= 0;
67 * Adjust the backlight level with the percent in
70 adjusted_level
= level
* dev_priv
->blc_adj2
;
71 adjusted_level
= adjusted_level
/ BLC_ADJUSTMENT_MAX
;
72 dev_priv
->brightness_adjusted
= adjusted_level
;
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
);
80 if (dev_priv
->dpi_panel_on
[0])
81 mdfld_dsi_brightness_control(dev
, 0,
82 dev_priv
->brightness_adjusted
);
85 if (dev_priv
->dpi_panel_on
[2])
86 mdfld_dsi_brightness_control(dev
, 2,
87 dev_priv
->brightness_adjusted
);
91 /* cache the brightness for later use */
92 dev_priv
->brightness
= level
;
96 static int mdfld_get_brightness(struct backlight_device
*bd
)
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
;
102 DRM_DEBUG_DRIVER("brightness = 0x%x \n", dev_priv
->brightness
);
104 /* return locally cached var instead of HW read (due to DPST etc.) */
105 return dev_priv
->brightness
;
108 static const struct backlight_ops mdfld_ops
= {
109 .get_brightness
= mdfld_get_brightness
,
110 .update_status
= mdfld_set_brightness
,
113 static int device_backlight_init(struct drm_device
*dev
)
115 struct drm_psb_private
*dev_priv
= (struct drm_psb_private
*)
118 dev_priv
->blc_adj1
= BLC_ADJUSTMENT_MAX
;
119 dev_priv
->blc_adj2
= BLC_ADJUSTMENT_MAX
;
124 static int mdfld_backlight_init(struct drm_device
*dev
)
126 struct backlight_properties props
;
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
);
135 if (IS_ERR(mdfld_backlight_device
))
136 return PTR_ERR(mdfld_backlight_device
);
138 ret
= device_backlight_init(dev
);
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
);
149 struct backlight_device
*mdfld_get_backlight_device(void)
151 #ifdef CONFIG_BACKLIGHT_CLASS_DEVICE
152 return mdfld_backlight_device
;
159 * mdfld_save_display_registers
161 * Description: We are going to suspend so save current display
164 * Notes: FIXME_JLIU7 need to add the support for DPI MIPI & HDMI audio
166 static int mdfld_save_display_registers(struct drm_device
*dev
, int pipenum
)
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
];
180 mipi_val
= ®s
->saveMIPI
;
183 mipi_val
= ®s
->saveMIPI
;
188 /* pointer to values */
189 mipi_val
= ®s
->saveMIPI_C
;
192 DRM_ERROR("%s, invalid pipe number.\n", __func__
);
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
);
216 /*save palette (gamma) */
217 for (i
= 0; i
< 256; i
++)
218 pipe
->palette
[i
] = PSB_RVDC32(map
->palette
+ (i
<< 2));
221 regs
->savePFIT_CONTROL
= PSB_RVDC32(PFIT_CONTROL
);
222 regs
->savePFIT_PGM_RATIOS
= PSB_RVDC32(PFIT_PGM_RATIOS
);
224 regs
->saveHDMIPHYMISCCTL
= PSB_RVDC32(HDMIPHYMISCCTL
);
225 regs
->saveHDMIB_CONTROL
= PSB_RVDC32(HDMIB_CONTROL
);
229 *mipi_val
= PSB_RVDC32(mipi_reg
);
234 * mdfld_restore_display_registers
236 * Description: We are going to resume so restore display register state.
238 * Notes: FIXME_JLIU7 need to add the support for DPI MIPI & HDMI audio
240 static int mdfld_restore_display_registers(struct drm_device
*dev
, int pipenum
)
242 /* To get panel out of ULPS mode. */
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
];
258 u32 dpll_val
= pipe
->dpll
;
259 u32 mipi_val
= regs
->saveMIPI
;
263 dpll_val
&= ~DPLL_VCO_ENABLE
;
264 dsi_config
= dev_priv
->dsi_configs
[0];
267 dpll_val
&= ~DPLL_VCO_ENABLE
;
271 mipi_val
= regs
->saveMIPI_C
;
272 dsi_config
= dev_priv
->dsi_configs
[1];
275 DRM_ERROR("%s, invalid pipe number.\n", __func__
);
279 /*make sure VGA plane is off. it initializes to on after reset!*/
280 PSB_WVDC32(0x80000000, VGACNTRL
);
283 PSB_WVDC32(dpll_val
& ~DPLL_VCO_ENABLE
, map
->dpll
);
284 PSB_RVDC32(map
->dpll
);
286 PSB_WVDC32(pipe
->fp0
, map
->fp0
);
289 dpll
= PSB_RVDC32(map
->dpll
);
291 if (!(dpll
& DPLL_VCO_ENABLE
)) {
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 */
302 PSB_WVDC32(pipe
->fp0
, map
->fp0
);
303 PSB_WVDC32(dpll_val
, map
->dpll
);
304 /* FIXME_MDFLD PO - change 500 to 1 after PO */
307 dpll_val
|= DPLL_VCO_ENABLE
;
308 PSB_WVDC32(dpll_val
, map
->dpll
);
309 PSB_RVDC32(map
->dpll
);
311 /* wait for DSI PLL to lock */
312 while (timeout
< 20000 &&
313 !(PSB_RVDC32(map
->conf
) & PIPECONF_DSIPLL_LOCK
)) {
318 if (timeout
== 20000) {
319 DRM_ERROR("%s, can't lock DSIPLL.\n",
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
);
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
);
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));
349 PSB_WVDC32(regs
->savePFIT_CONTROL
, PFIT_CONTROL
);
350 PSB_WVDC32(regs
->savePFIT_PGM_RATIOS
, PFIT_PGM_RATIOS
);
352 /*TODO: resume HDMI port */
354 /*TODO: resume pipe*/
357 PSB_WVDC32(pipe
->cntr
& ~DISPLAY_PLANE_ENABLE
, map
->cntr
);
362 /*set up pipe related registers*/
363 PSB_WVDC32(mipi_val
, mipi_reg
);
365 /*setup MIPI adapter + MIPI IP registers*/
367 mdfld_dsi_controller_init(dsi_config
, pipenum
);
369 if (in_atomic() || in_interrupt())
375 PSB_WVDC32(pipe
->cntr
, map
->cntr
);
377 if (in_atomic() || in_interrupt())
382 /* LP Hold Release */
383 temp
= REG_READ(mipi_reg
);
384 temp
|= LP_OUTPUT_HOLD_RELEASE
;
385 REG_WRITE(mipi_reg
, temp
);
389 /* Set DSI host to exit from Utra Low Power State */
390 temp
= REG_READ(device_ready_reg
);
393 temp
|= EXIT_ULPS_DEV_READY
;
394 REG_WRITE(device_ready_reg
, temp
);
397 temp
= REG_READ(device_ready_reg
);
399 temp
|= EXITING_ULPS
;
400 REG_WRITE(device_ready_reg
, temp
);
404 PSB_WVDC32(pipe
->conf
, map
->conf
);
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));
414 static int mdfld_save_registers(struct drm_device
*dev
)
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);
425 static int mdfld_restore_registers(struct drm_device
*dev
)
427 mdfld_restore_display_registers(dev
, 2);
428 mdfld_restore_display_registers(dev
, 0);
429 /* mdfld_restore_cursor_overlay_registers(dev); */
434 static int mdfld_power_down(struct drm_device
*dev
)
440 static int mdfld_power_up(struct drm_device
*dev
)
447 static const struct psb_offset mdfld_regmap
[3] = {
461 .stride
= DSPASTRIDE
,
465 .addr
= MRST_DSPABASE
,
467 .linoff
= DSPALINOFF
,
468 .tileoff
= DSPATILEOFF
,
469 .palette
= PALETTE_A
,
472 .fp0
= MDFLD_DPLL_DIV0
,
476 .dpll
= MDFLD_DPLL_B
,
483 .stride
= DSPBSTRIDE
,
487 .addr
= MRST_DSPBBASE
,
489 .linoff
= DSPBLINOFF
,
490 .tileoff
= DSPBTILEOFF
,
491 .palette
= PALETTE_B
,
494 .fp0
= MRST_FPA0
, /* This is what the old code did ?? */
506 .stride
= DSPCSTRIDE
,
510 .addr
= MDFLD_DSPCBASE
,
512 .linoff
= DSPCLINOFF
,
513 .tileoff
= DSPCTILEOFF
,
514 .palette
= PALETTE_C
,
518 static int mdfld_chip_setup(struct drm_device
*dev
)
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
);
527 const struct psb_ops mdfld_chip_ops
= {
532 .lvds_mask
= (1 << 1),
533 .hdmi_mask
= (1 << 1),
534 .cursor_needs_phys
= 0,
535 .sgx_offset
= MRST_SGX_OFFSET
,
537 .chip_setup
= mdfld_chip_setup
,
538 .crtc_helper
= &mdfld_helper_funcs
,
539 .crtc_funcs
= &psb_intel_crtc_funcs
,
541 .output_init
= mdfld_output_init
,
543 #ifdef CONFIG_BACKLIGHT_CLASS_DEVICE
544 .backlight_init
= mdfld_backlight_init
,
547 .save_regs
= mdfld_save_registers
,
548 .restore_regs
= mdfld_restore_registers
,
549 .power_down
= mdfld_power_down
,
550 .power_up
= mdfld_power_up
,