Linux Audio

Check our new training course

Loading...
Note: File does not exist in v3.1.
  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
 48static struct backlight_device *mdfld_backlight_device;
 49
 50int 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
 96static 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
108static const struct backlight_ops mdfld_ops = {
109	.get_brightness = mdfld_get_brightness,
110	.update_status  = mdfld_set_brightness,
111};
112
113static 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
124static 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
149struct 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 */
166static 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 */
240static 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
414static 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
425static 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
434static int mdfld_power_down(struct drm_device *dev)
435{
436	/* FIXME */
437	return 0;
438}
439
440static int mdfld_power_up(struct drm_device *dev)
441{
442	/* FIXME */
443	return 0;
444}
445
446/* Medfield  */
447static 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
518static 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
527const 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};