Linux Audio

Check our new training course

Loading...
Note: File does not exist in v6.13.7.
  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
 38static struct backlight_device *mdfld_backlight_device;
 39
 40int 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
 86static 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
 98static const struct backlight_ops mdfld_ops = {
 99	.get_brightness = mdfld_get_brightness,
100	.update_status  = mdfld_set_brightness,
101};
102
103static 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
114static 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
139struct 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 */
156static 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 */
230static 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
404static 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
415static 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
424static int mdfld_power_down(struct drm_device *dev)
425{
426	/* FIXME */
427	return 0;
428}
429
430static int mdfld_power_up(struct drm_device *dev)
431{
432	/* FIXME */
433	return 0;
434}
435
436/* Medfield  */
437static 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
508static 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
517const 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};