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