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