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