1 // SPDX-License-Identifier: GPL-2.0-only
2 /**************************************************************************
3 * Copyright (c) 2011, Intel Corporation.
6 **************************************************************************/
8 #include <linux/delay.h>
9 #include <linux/gpio/machine.h>
11 #include <asm/intel_scu_ipc.h>
13 #include "mdfld_dsi_output.h"
14 #include "mdfld_output.h"
17 #include "tc35876x-dsi-lvds.h"
19 #ifdef CONFIG_BACKLIGHT_CLASS_DEVICE
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
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
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
36 #define MDFLD_BACKLIGHT_PWM_POLARITY_BIT_CLEAR (0xFFFE)
37 #define MDFLD_BACKLIGHT_PWM_CTL_SHIFT (16)
39 static struct backlight_device
*mdfld_backlight_device
;
41 int mdfld_set_brightness(struct backlight_device
*bd
)
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
;
48 DRM_DEBUG_DRIVER("backlight level set to %d\n", level
);
50 /* Perform value bounds checking */
51 if (level
< BRIGHTNESS_MIN_LEVEL
)
52 level
= BRIGHTNESS_MIN_LEVEL
;
54 if (gma_power_begin(dev
, false)) {
55 u32 adjusted_level
= 0;
58 * Adjust the backlight level with the percent in
61 adjusted_level
= level
* dev_priv
->blc_adj2
;
62 adjusted_level
= adjusted_level
/ BLC_ADJUSTMENT_MAX
;
63 dev_priv
->brightness_adjusted
= adjusted_level
;
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
);
71 if (dev_priv
->dpi_panel_on
[0])
72 mdfld_dsi_brightness_control(dev
, 0,
73 dev_priv
->brightness_adjusted
);
76 if (dev_priv
->dpi_panel_on
[2])
77 mdfld_dsi_brightness_control(dev
, 2,
78 dev_priv
->brightness_adjusted
);
82 /* cache the brightness for later use */
83 dev_priv
->brightness
= level
;
87 static int mdfld_get_brightness(struct backlight_device
*bd
)
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
;
93 DRM_DEBUG_DRIVER("brightness = 0x%x \n", dev_priv
->brightness
);
95 /* return locally cached var instead of HW read (due to DPST etc.) */
96 return dev_priv
->brightness
;
99 static const struct backlight_ops mdfld_ops
= {
100 .get_brightness
= mdfld_get_brightness
,
101 .update_status
= mdfld_set_brightness
,
104 static int device_backlight_init(struct drm_device
*dev
)
106 struct drm_psb_private
*dev_priv
= (struct drm_psb_private
*)
109 dev_priv
->blc_adj1
= BLC_ADJUSTMENT_MAX
;
110 dev_priv
->blc_adj2
= BLC_ADJUSTMENT_MAX
;
115 static int mdfld_backlight_init(struct drm_device
*dev
)
117 struct backlight_properties props
;
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
);
126 if (IS_ERR(mdfld_backlight_device
))
127 return PTR_ERR(mdfld_backlight_device
);
129 ret
= device_backlight_init(dev
);
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
);
140 struct backlight_device
*mdfld_get_backlight_device(void)
142 #ifdef CONFIG_BACKLIGHT_CLASS_DEVICE
143 return mdfld_backlight_device
;
150 * mdfld_save_display_registers
152 * Description: We are going to suspend so save current display
155 * Notes: FIXME_JLIU7 need to add the support for DPI MIPI & HDMI audio
157 static int mdfld_save_display_registers(struct drm_device
*dev
, int pipenum
)
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
];
171 mipi_val
= ®s
->saveMIPI
;
174 mipi_val
= ®s
->saveMIPI
;
179 /* pointer to values */
180 mipi_val
= ®s
->saveMIPI_C
;
183 DRM_ERROR("%s, invalid pipe number.\n", __func__
);
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
);
207 /*save palette (gamma) */
208 for (i
= 0; i
< 256; i
++)
209 pipe
->palette
[i
] = PSB_RVDC32(map
->palette
+ (i
<< 2));
212 regs
->savePFIT_CONTROL
= PSB_RVDC32(PFIT_CONTROL
);
213 regs
->savePFIT_PGM_RATIOS
= PSB_RVDC32(PFIT_PGM_RATIOS
);
215 regs
->saveHDMIPHYMISCCTL
= PSB_RVDC32(HDMIPHYMISCCTL
);
216 regs
->saveHDMIB_CONTROL
= PSB_RVDC32(HDMIB_CONTROL
);
220 *mipi_val
= PSB_RVDC32(mipi_reg
);
225 * mdfld_restore_display_registers
227 * Description: We are going to resume so restore display register state.
229 * Notes: FIXME_JLIU7 need to add the support for DPI MIPI & HDMI audio
231 static int mdfld_restore_display_registers(struct drm_device
*dev
, int pipenum
)
233 /* To get panel out of ULPS mode. */
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
];
249 u32 dpll_val
= pipe
->dpll
;
250 u32 mipi_val
= regs
->saveMIPI
;
254 dpll_val
&= ~DPLL_VCO_ENABLE
;
255 dsi_config
= dev_priv
->dsi_configs
[0];
258 dpll_val
&= ~DPLL_VCO_ENABLE
;
262 mipi_val
= regs
->saveMIPI_C
;
263 dsi_config
= dev_priv
->dsi_configs
[1];
266 DRM_ERROR("%s, invalid pipe number.\n", __func__
);
270 /*make sure VGA plane is off. it initializes to on after reset!*/
271 PSB_WVDC32(0x80000000, VGACNTRL
);
274 PSB_WVDC32(dpll_val
& ~DPLL_VCO_ENABLE
, map
->dpll
);
275 PSB_RVDC32(map
->dpll
);
277 PSB_WVDC32(pipe
->fp0
, map
->fp0
);
280 dpll
= PSB_RVDC32(map
->dpll
);
282 if (!(dpll
& DPLL_VCO_ENABLE
)) {
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 */
293 PSB_WVDC32(pipe
->fp0
, map
->fp0
);
294 PSB_WVDC32(dpll_val
, map
->dpll
);
295 /* FIXME_MDFLD PO - change 500 to 1 after PO */
298 dpll_val
|= DPLL_VCO_ENABLE
;
299 PSB_WVDC32(dpll_val
, map
->dpll
);
300 PSB_RVDC32(map
->dpll
);
302 /* wait for DSI PLL to lock */
303 while (timeout
< 20000 &&
304 !(PSB_RVDC32(map
->conf
) & PIPECONF_DSIPLL_LOCK
)) {
309 if (timeout
== 20000) {
310 DRM_ERROR("%s, can't lock DSIPLL.\n",
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
);
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
);
335 /* restore palette (gamma) */
337 for (i
= 0; i
< 256; i
++)
338 PSB_WVDC32(pipe
->palette
[i
], map
->palette
+ (i
<< 2));
340 PSB_WVDC32(regs
->savePFIT_CONTROL
, PFIT_CONTROL
);
341 PSB_WVDC32(regs
->savePFIT_PGM_RATIOS
, PFIT_PGM_RATIOS
);
343 /*TODO: resume HDMI port */
345 /*TODO: resume pipe*/
348 PSB_WVDC32(pipe
->cntr
& ~DISPLAY_PLANE_ENABLE
, map
->cntr
);
353 /*set up pipe related registers*/
354 PSB_WVDC32(mipi_val
, mipi_reg
);
356 /*setup MIPI adapter + MIPI IP registers*/
358 mdfld_dsi_controller_init(dsi_config
, pipenum
);
360 if (in_atomic() || in_interrupt())
366 PSB_WVDC32(pipe
->cntr
, map
->cntr
);
368 if (in_atomic() || in_interrupt())
373 /* LP Hold Release */
374 temp
= REG_READ(mipi_reg
);
375 temp
|= LP_OUTPUT_HOLD_RELEASE
;
376 REG_WRITE(mipi_reg
, temp
);
380 /* Set DSI host to exit from Utra Low Power State */
381 temp
= REG_READ(device_ready_reg
);
384 temp
|= EXIT_ULPS_DEV_READY
;
385 REG_WRITE(device_ready_reg
, temp
);
388 temp
= REG_READ(device_ready_reg
);
390 temp
|= EXITING_ULPS
;
391 REG_WRITE(device_ready_reg
, temp
);
395 PSB_WVDC32(pipe
->conf
, map
->conf
);
397 /* restore palette (gamma) */
399 for (i
= 0; i
< 256; i
++)
400 PSB_WVDC32(pipe
->palette
[i
], map
->palette
+ (i
<< 2));
405 static int mdfld_save_registers(struct drm_device
*dev
)
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);
416 static int mdfld_restore_registers(struct drm_device
*dev
)
418 mdfld_restore_display_registers(dev
, 2);
419 mdfld_restore_display_registers(dev
, 0);
420 /* mdfld_restore_cursor_overlay_registers(dev); */
425 static int mdfld_power_down(struct drm_device
*dev
)
431 static int mdfld_power_up(struct drm_device
*dev
)
438 static const struct psb_offset mdfld_regmap
[3] = {
452 .stride
= DSPASTRIDE
,
456 .addr
= MRST_DSPABASE
,
458 .linoff
= DSPALINOFF
,
459 .tileoff
= DSPATILEOFF
,
460 .palette
= PALETTE_A
,
463 .fp0
= MDFLD_DPLL_DIV0
,
467 .dpll
= MDFLD_DPLL_B
,
474 .stride
= DSPBSTRIDE
,
478 .addr
= MRST_DSPBBASE
,
480 .linoff
= DSPBLINOFF
,
481 .tileoff
= DSPBTILEOFF
,
482 .palette
= PALETTE_B
,
485 .fp0
= MRST_FPA0
, /* This is what the old code did ?? */
497 .stride
= DSPCSTRIDE
,
501 .addr
= MDFLD_DSPCBASE
,
503 .linoff
= DSPCLINOFF
,
504 .tileoff
= DSPCTILEOFF
,
505 .palette
= PALETTE_C
,
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.
513 static struct gpiod_lookup_table mdfld_dsi_pipe_gpio_table
= {
515 GPIO_LOOKUP("0000:00:0c.0", 128, "dsi-pipe0-reset",
517 GPIO_LOOKUP("0000:00:0c.0", 34, "dsi-pipe2-reset",
523 static int mdfld_chip_setup(struct drm_device
*dev
)
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
;
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
);
534 return mid_chip_setup(dev
);
537 const struct psb_ops mdfld_chip_ops
= {
541 .lvds_mask
= (1 << 1),
542 .hdmi_mask
= (1 << 1),
543 .cursor_needs_phys
= 0,
544 .sgx_offset
= MRST_SGX_OFFSET
,
546 .chip_setup
= mdfld_chip_setup
,
547 .crtc_helper
= &mdfld_helper_funcs
,
548 .crtc_funcs
= &psb_intel_crtc_funcs
,
550 .output_init
= mdfld_output_init
,
552 #ifdef CONFIG_BACKLIGHT_CLASS_DEVICE
553 .backlight_init
= mdfld_backlight_init
,
556 .save_regs
= mdfld_save_registers
,
557 .restore_regs
= mdfld_restore_registers
,
558 .save_crtc
= gma_crtc_save
,
559 .restore_crtc
= gma_crtc_restore
,
560 .power_down
= mdfld_power_down
,
561 .power_up
= mdfld_power_up
,