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