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