GNU Linux-libre 5.10.153-gnu1
[releases.git] / drivers / gpu / drm / gma500 / mdfld_device.c
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
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
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
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
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
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  */
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 = &regs->saveMIPI;
172                 break;
173         case 1:
174                 mipi_val = &regs->saveMIPI;
175                 break;
176         case 2:
177                 /* register */
178                 mipi_reg = MIPI_C;
179                 /* pointer to values */
180                 mipi_val = &regs->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  */
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
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
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
425 static int mdfld_power_down(struct drm_device *dev)
426 {
427         /* FIXME */
428         return 0;
429 }
430
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
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 };