]> Git Repo - linux.git/blob - drivers/gpu/drm/gma500/mdfld_device.c
Merge ath-next from git://git.kernel.org/pub/scm/linux/kernel/git/kvalo/ath.git
[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 <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
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
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
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
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
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  */
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 = &regs->saveMIPI;
171                 break;
172         case 1:
173                 mipi_val = &regs->saveMIPI;
174                 break;
175         case 2:
176                 /* register */
177                 mipi_reg = MIPI_C;
178                 /* pointer to values */
179                 mipi_val = &regs->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  */
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
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
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
424 static int mdfld_power_down(struct drm_device *dev)
425 {
426         /* FIXME */
427         return 0;
428 }
429
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
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 };
This page took 0.070199 seconds and 4 git commands to generate.