• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
mdfld_set_brightness(struct backlight_device * bd)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 
mdfld_get_brightness(struct backlight_device * bd)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 
device_backlight_init(struct drm_device * dev)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 
mdfld_backlight_init(struct drm_device * dev)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 
mdfld_get_backlight_device(void)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  */
mdfld_save_display_registers(struct drm_device * dev,int pipenum)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  */
mdfld_restore_display_registers(struct drm_device * dev,int pipenum)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 
mdfld_save_registers(struct drm_device * dev)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 
mdfld_restore_registers(struct drm_device * dev)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 
mdfld_power_down(struct drm_device * dev)434 static int mdfld_power_down(struct drm_device *dev)
435 {
436 	/* FIXME */
437 	return 0;
438 }
439 
mdfld_power_up(struct drm_device * dev)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 
mdfld_chip_setup(struct drm_device * dev)518 static int mdfld_chip_setup(struct drm_device *dev)
519 {
520 	struct drm_psb_private *dev_priv = dev->dev_private;
521 	if (pci_enable_msi(dev->pdev))
522 		dev_warn(dev->dev, "Enabling MSI failed!\n");
523 	dev_priv->regmap = mdfld_regmap;
524 	return mid_chip_setup(dev);
525 }
526 
527 const struct psb_ops mdfld_chip_ops = {
528 	.name = "mdfld",
529 	.accel_2d = 0,
530 	.pipes = 3,
531 	.crtcs = 3,
532 	.lvds_mask = (1 << 1),
533 	.hdmi_mask = (1 << 1),
534 	.cursor_needs_phys = 0,
535 	.sgx_offset = MRST_SGX_OFFSET,
536 
537 	.chip_setup = mdfld_chip_setup,
538 	.crtc_helper = &mdfld_helper_funcs,
539 	.crtc_funcs = &psb_intel_crtc_funcs,
540 
541 	.output_init = mdfld_output_init,
542 
543 #ifdef CONFIG_BACKLIGHT_CLASS_DEVICE
544 	.backlight_init = mdfld_backlight_init,
545 #endif
546 
547 	.save_regs = mdfld_save_registers,
548 	.restore_regs = mdfld_restore_registers,
549 	.power_down = mdfld_power_down,
550 	.power_up = mdfld_power_up,
551 };
552